Compare commits
11 Commits
f118cc1e9b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| aa763a0ee6 | |||
| 7a8f25cf65 | |||
| ab86729e33 | |||
| f9eaa441a3 | |||
| 891bffba3b | |||
| 07f8ef90bb | |||
| e076e42b86 | |||
| fbfe6c30f9 | |||
| 839e0617ee | |||
| ac0a17a943 | |||
| 9ed58de1ce |
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"permissions": {
|
|
||||||
"allow": [
|
|
||||||
"Bash(tree:*)",
|
|
||||||
"Bash(mvn clean package:*)",
|
|
||||||
"Bash(echo:*)"
|
|
||||||
],
|
|
||||||
"deny": [],
|
|
||||||
"ask": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,7 +3,10 @@
|
|||||||
"allow": [
|
"allow": [
|
||||||
"Bash(tree:*)",
|
"Bash(tree:*)",
|
||||||
"Bash(mvn clean package:*)",
|
"Bash(mvn clean package:*)",
|
||||||
"Bash(echo:*)"
|
"Bash(echo:*)",
|
||||||
|
"Bash(git add:*)",
|
||||||
|
"Bash(git commit:*)",
|
||||||
|
"Bash(grep:*)"
|
||||||
],
|
],
|
||||||
"deny": [],
|
"deny": [],
|
||||||
"ask": []
|
"ask": []
|
||||||
|
|||||||
384
CLAUDE.md
384
CLAUDE.md
@@ -142,95 +142,12 @@ plus-ui/
|
|||||||
4. **HTTP 客户端**: Axios 1.8.4
|
4. **HTTP 客户端**: Axios 1.8.4
|
||||||
5. **表格组件**: vxe-table 4.13.7
|
5. **表格组件**: vxe-table 4.13.7
|
||||||
6. **接口加密**: RSA + AES 动态加密
|
6. **接口加密**: RSA + AES 动态加密
|
||||||
7. **原子化CSS**: UnoCSS
|
7. **原子化CSS**: UnoCSS 66.5.2
|
||||||
|
|
||||||
## 项目特定技术规范
|
## 常用命令
|
||||||
|
|
||||||
### 后端开发规范
|
### 后端开发
|
||||||
|
|
||||||
1. **模块结构**:
|
|
||||||
- `ruoyi-admin/` - 主应用入口,负责启动和全局配置
|
|
||||||
- `ruoyi-common/` - 通用功能模块(不要随意修改)
|
|
||||||
- `ruoyi-modules/` - 业务模块目录
|
|
||||||
- `ruoyi-system/` - 系统管理模块
|
|
||||||
- `ruoyi-inspection/` - AR巡检核心业务模块
|
|
||||||
- 其他业务模块按功能划分
|
|
||||||
|
|
||||||
2. **代码分层**:
|
|
||||||
```
|
|
||||||
controller/ # 控制器层,处理HTTP请求
|
|
||||||
service/ # 业务逻辑层接口
|
|
||||||
service/impl/ # 业务逻辑实现
|
|
||||||
mapper/ # 数据访问层
|
|
||||||
domain/ # 实体类
|
|
||||||
vo/ # 视图对象
|
|
||||||
bo/ # 业务对象
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **必须遵循的规范**:
|
|
||||||
- 实体类必须继承 `BaseEntity` 并使用 Lombok 注解
|
|
||||||
- Mapper 接口继承 `BaseMapperPlus<实体类Mapper, 实体类, VO类>`
|
|
||||||
- Service 实现类使用 `@RequiredArgsConstructor` 注入依赖
|
|
||||||
- Controller 统一返回 `R<T>` 类型
|
|
||||||
- 使用 `@SaCheckPermission` 进行权限控制
|
|
||||||
- 所有 API 添加 Swagger 注解: `@Tag`, `@Operation`, `@Parameters`
|
|
||||||
|
|
||||||
4. **命名约定**:
|
|
||||||
- 实体类: `XxxEntity` 或直接 `Xxx`
|
|
||||||
- Mapper: `XxxMapper`
|
|
||||||
- Service: `IXxxService` (接口) / `XxxServiceImpl` (实现)
|
|
||||||
- Controller: `XxxController`
|
|
||||||
- VO: `XxxVo`
|
|
||||||
- BO: `XxxBo`
|
|
||||||
|
|
||||||
5. **数据库操作**:
|
|
||||||
- 优先使用 MyBatis-Plus 的内置方法
|
|
||||||
- 复杂查询在 Mapper XML 中编写
|
|
||||||
- 使用 `LambdaQueryWrapper` 构建动态查询
|
|
||||||
- 分页使用 `TableDataInfo<T>` 和 `PageQuery`
|
|
||||||
|
|
||||||
### 前端开发规范
|
|
||||||
|
|
||||||
1. **目录结构**:
|
|
||||||
```
|
|
||||||
plus-ui/
|
|
||||||
├── src/
|
|
||||||
│ ├── api/ # API接口定义
|
|
||||||
│ ├── views/ # 页面视图
|
|
||||||
│ ├── components/ # 可复用组件
|
|
||||||
│ ├── store/ # Pinia状态管理
|
|
||||||
│ ├── router/ # 路由配置
|
|
||||||
│ ├── utils/ # 工具函数
|
|
||||||
│ └── types/ # TypeScript类型定义
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **组件开发**:
|
|
||||||
- 使用 Vue 3 Composition API (`<script setup lang="ts">`)
|
|
||||||
- 优先使用 Element Plus 组件
|
|
||||||
- 表单使用 `el-form` + 表单验证规则
|
|
||||||
- 表格使用 `vxe-table` 或 `el-table`
|
|
||||||
- 使用 `useRouter`, `useRoute` 进行路由操作
|
|
||||||
|
|
||||||
3. **API 调用规范**:
|
|
||||||
- API 定义在 `src/api/` 目录,按模块分文件
|
|
||||||
- 使用 `request` 工具发起请求
|
|
||||||
- 统一错误处理,使用 `ElMessage` 显示提示
|
|
||||||
- 类型定义使用 TypeScript interface
|
|
||||||
|
|
||||||
4. **状态管理**:
|
|
||||||
- 使用 Pinia 管理全局状态
|
|
||||||
- Store 文件放在 `src/store/modules/`
|
|
||||||
- 使用组合式 API: `defineStore`
|
|
||||||
|
|
||||||
5. **样式规范**:
|
|
||||||
- 使用 `<style scoped lang="scss">`
|
|
||||||
- 优先使用 UnoCSS 原子类
|
|
||||||
- 遵循 BEM 命名规范
|
|
||||||
- 响应式布局使用 Element Plus 的栅格系统
|
|
||||||
|
|
||||||
### 常用命令
|
|
||||||
|
|
||||||
**后端开发**:
|
|
||||||
```bash
|
```bash
|
||||||
# 构建项目(跳过测试)
|
# 构建项目(跳过测试)
|
||||||
mvn clean install -DskipTests
|
mvn clean install -DskipTests
|
||||||
@@ -245,7 +162,8 @@ mvn test
|
|||||||
mvn clean package -Pprod -DskipTests
|
mvn clean package -Pprod -DskipTests
|
||||||
```
|
```
|
||||||
|
|
||||||
**前端开发**:
|
### 前端开发
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 安装依赖
|
# 安装依赖
|
||||||
cd plus-ui && npm install --registry=https://registry.npmmirror.com
|
cd plus-ui && npm install --registry=https://registry.npmmirror.com
|
||||||
@@ -265,12 +183,12 @@ npm run prettier
|
|||||||
|
|
||||||
### 自定义斜杠命令
|
### 自定义斜杠命令
|
||||||
|
|
||||||
- `/build` - 构建整个 Maven 项目
|
- `/build` - 构建整个 Maven 项目并运行测试
|
||||||
- `/start-backend` - 启动后端 Spring Boot 服务
|
- `/start-backend` - 启动后端 Spring Boot 应用
|
||||||
- `/start-frontend` - 启动前端 Vue3 开发服务器
|
- `/start-frontend` - 启动前端 Vue3 开发服务器
|
||||||
|
- `/new-module` - 创建新的业务模块(Controller, Service, Mapper, Domain)
|
||||||
|
- `/analyze` - 分析项目结构并生成架构文档
|
||||||
- `/lint` - 运行前端代码检查和格式化
|
- `/lint` - 运行前端代码检查和格式化
|
||||||
- `/new-module` - 创建新的业务模块脚手架
|
|
||||||
- `/analyze` - 分析项目架构和依赖关系
|
|
||||||
|
|
||||||
## 配置说明
|
## 配置说明
|
||||||
|
|
||||||
@@ -344,6 +262,67 @@ VITE_APP_CONTEXT_PATH = /
|
|||||||
- 支持本部门、本部门及以下、仅本人等权限范围
|
- 支持本部门、本部门及以下、仅本人等权限范围
|
||||||
- 通过 MyBatis-Plus 插件实现
|
- 通过 MyBatis-Plus 插件实现
|
||||||
|
|
||||||
|
## 开发规范
|
||||||
|
|
||||||
|
### 后端代码分层
|
||||||
|
|
||||||
|
```
|
||||||
|
controller/ # 控制器层,处理HTTP请求
|
||||||
|
service/ # 业务逻辑层接口
|
||||||
|
service/impl/ # 业务逻辑实现
|
||||||
|
mapper/ # 数据访问层
|
||||||
|
domain/ # 实体类
|
||||||
|
vo/ # 视图对象
|
||||||
|
bo/ # 业务对象
|
||||||
|
```
|
||||||
|
|
||||||
|
### 必须遵循的规范
|
||||||
|
|
||||||
|
1. **实体类**: 继承 `BaseEntity` 并使用 Lombok 注解
|
||||||
|
2. **Mapper 接口**: 继承 `BaseMapperPlus<实体类Mapper, 实体类, VO类>`
|
||||||
|
3. **Service 实现**: 使用 `@RequiredArgsConstructor` 注入依赖
|
||||||
|
4. **Controller 返回**: 统一返回 `R<T>` 类型
|
||||||
|
5. **权限控制**: 使用 `@SaCheckPermission` 注解
|
||||||
|
6. **API 文档**: 添加 `@Tag`, `@Operation`, `@Parameters` 注解
|
||||||
|
|
||||||
|
### 命名约定
|
||||||
|
|
||||||
|
- 实体类: `XxxEntity` 或直接 `Xxx`
|
||||||
|
- Mapper: `XxxMapper`
|
||||||
|
- Service: `IXxxService` (接口) / `XxxServiceImpl` (实现)
|
||||||
|
- Controller: `XxxController`
|
||||||
|
- VO: `XxxVo`
|
||||||
|
- BO: `XxxBo`
|
||||||
|
|
||||||
|
### 数据库操作
|
||||||
|
|
||||||
|
- 优先使用 MyBatis-Plus 的内置方法
|
||||||
|
- 复杂查询在 Mapper XML 中编写
|
||||||
|
- 使用 `LambdaQueryWrapper` 构建动态查询
|
||||||
|
- 分页使用 `TableDataInfo<T>` 和 `PageQuery`
|
||||||
|
|
||||||
|
### 前端开发规范
|
||||||
|
|
||||||
|
1. **组件开发**:
|
||||||
|
- 使用 Vue 3 Composition API (`<script setup lang="ts">`)
|
||||||
|
- 优先使用 Element Plus 组件
|
||||||
|
- 表单使用 `el-form` + 表单验证规则
|
||||||
|
- 表格使用 `vxe-table` 或 `el-table`
|
||||||
|
|
||||||
|
2. **API 调用**:
|
||||||
|
- API 定义在 `src/api/` 目录,按模块分文件
|
||||||
|
- 使用 `request` 工具发起请求
|
||||||
|
- 统一错误处理,使用 `ElMessage` 显示提示
|
||||||
|
|
||||||
|
3. **状态管理**:
|
||||||
|
- 使用 Pinia 管理全局状态
|
||||||
|
- Store 文件放在 `src/store/modules/`
|
||||||
|
|
||||||
|
4. **样式规范**:
|
||||||
|
- 使用 `<style scoped lang="scss">`
|
||||||
|
- 优先使用 UnoCSS 原子类
|
||||||
|
- 响应式布局使用 Element Plus 栅格系统
|
||||||
|
|
||||||
## 监控与运维
|
## 监控与运维
|
||||||
|
|
||||||
### 服务端口
|
### 服务端口
|
||||||
@@ -385,95 +364,33 @@ VITE_APP_CONTEXT_PATH = /
|
|||||||
- 符合项目规范的代码风格
|
- 符合项目规范的代码风格
|
||||||
- 生成后需根据业务需求调整
|
- 生成后需根据业务需求调整
|
||||||
|
|
||||||
### 项目特定注意事项
|
## 项目特定注意事项
|
||||||
|
|
||||||
1. **AR 巡检业务模块** (`ruoyi-inspection`):
|
### AR 巡检业务模块 (`ruoyi-inspection`)
|
||||||
- 核心业务逻辑,修改需谨慎
|
|
||||||
- 涉及设备点位、巡检任务、缺陷记录等核心功能
|
|
||||||
- 修改前先阅读业务设计文档: `AR-INSPECTION-DESIGN.md`
|
|
||||||
|
|
||||||
2. **权限控制**:
|
- **核心业务逻辑**: 位于 `ruoyi-modules/ruoyi-inspection`
|
||||||
- 使用 Sa-Token 进行权限认证
|
- **主要功能**: 设备点位管理、巡检任务、缺陷记录、AR 技术集成
|
||||||
- 权限字符串格式: `模块:功能:操作` (如 `system:user:add`)
|
- **修改建议**: 涉及核心业务,修改需谨慎
|
||||||
- 菜单权限在数据库 `sys_menu` 表管理
|
- **依赖模块**: 依赖所有 ruoyi-common 核心模块
|
||||||
|
|
||||||
3. **文件存储**:
|
### 权限控制
|
||||||
- 使用 OSS 进行文件存储(支持 MinIO, 阿里云OSS等)
|
|
||||||
- 配置在 `application-*.yml` 中的 `oss` 节点
|
|
||||||
|
|
||||||
4. **多租户支持**:
|
- 使用 Sa-Token 进行权限认证
|
||||||
- 框架内置多租户功能
|
- 权限字符串格式: `模块:功能:操作` (如 `system:user:add`)
|
||||||
- 通过 `@TenantIgnore` 注解排除租户过滤
|
- 菜单权限在数据库 `sys_menu` 表管理
|
||||||
|
- 使用 `@SaCheckPermission("system:user:list")` 注解控制接口权限
|
||||||
|
|
||||||
5. **代码生成器**:
|
### 文件存储
|
||||||
- 访问 http://localhost:8080/tool/gen
|
|
||||||
- 可快速生成 CRUD 代码
|
|
||||||
- 生成后需根据业务需求调整
|
|
||||||
|
|
||||||
### 问题排查
|
- 使用 OSS 进行文件存储(支持 MinIO, 阿里云OSS等)
|
||||||
|
- 配置在 `application-*.yml` 中的 `oss` 节点
|
||||||
|
- 统一的文件上传下载接口
|
||||||
|
|
||||||
1. **后端启动失败**:
|
### 多租户支持
|
||||||
- 检查数据库连接配置
|
|
||||||
- 检查 Redis 是否启动
|
|
||||||
- 查看日志: `logs/sys-console.log`
|
|
||||||
|
|
||||||
2. **前端启动失败**:
|
- 框架内置多租户功能
|
||||||
- 删除 `node_modules` 重新安装
|
- 通过 `@TenantIgnore` 注解排除租户过滤
|
||||||
- 检查 Node.js 版本 >= 18.18.0
|
- 租户隔离在数据库层面自动实现
|
||||||
- 检查端口 80 是否被占用
|
|
||||||
|
|
||||||
3. **接口调用失败**:
|
|
||||||
- 检查后端服务是否启动
|
|
||||||
- 检查跨域配置
|
|
||||||
- 查看浏览器控制台和网络请求
|
|
||||||
|
|
||||||
## 框架技术注意事项
|
|
||||||
|
|
||||||
### 架构特点
|
|
||||||
|
|
||||||
1. **插件化架构**
|
|
||||||
- 各 `ruoyi-common-*` 模块相互独立
|
|
||||||
- 可按需引入功能模块
|
|
||||||
- 易于扩展和维护
|
|
||||||
|
|
||||||
2. **编码规范**
|
|
||||||
- 严格遵守 Alibaba Java 编码规范
|
|
||||||
- 使用 Lombok 简化代码
|
|
||||||
- IDE 需要安装 Lombok 插件
|
|
||||||
|
|
||||||
3. **对象转换**
|
|
||||||
- 使用 MapStruct-Plus 进行对象转换
|
|
||||||
- 避免使用 BeanUtils.copyProperties
|
|
||||||
- 性能优于反射方式
|
|
||||||
|
|
||||||
### 技术选型说明
|
|
||||||
|
|
||||||
1. **数据库连接池**: HikariCP (非 Druid)
|
|
||||||
- 性能更优
|
|
||||||
- Spring Boot 默认连接池
|
|
||||||
|
|
||||||
2. **Web 容器**: Undertow (非 Tomcat)
|
|
||||||
- 非阻塞 IO
|
|
||||||
- 内存占用更小
|
|
||||||
- 高并发性能更好
|
|
||||||
|
|
||||||
3. **JSON 序列化**: Jackson (非 Fastjson)
|
|
||||||
- 安全性更高
|
|
||||||
- Spring Boot 默认选择
|
|
||||||
|
|
||||||
4. **接口加密**
|
|
||||||
- 前后端需同时开启/关闭
|
|
||||||
- RSA + AES 混合加密
|
|
||||||
- 开发环境建议关闭
|
|
||||||
|
|
||||||
### 测试
|
|
||||||
|
|
||||||
- **单元测试**: JUnit 5 + Spring Boot Test
|
|
||||||
- **运行测试**: `mvn test`
|
|
||||||
- **测试分组**: 通过 `@Tag` 注解标记,根据环境执行
|
|
||||||
- `@Tag("dev")` - 开发环境测试
|
|
||||||
- `@Tag("prod")` - 生产环境测试
|
|
||||||
- `@Tag("exclude")` - 排除的测试
|
|
||||||
|
|
||||||
### Docker 部署
|
### Docker 部署
|
||||||
|
|
||||||
@@ -488,108 +405,41 @@ docker-compose up -d
|
|||||||
docker-compose down
|
docker-compose down
|
||||||
```
|
```
|
||||||
|
|
||||||
## Universal Development Guidelines
|
## 测试
|
||||||
|
|
||||||
### Code Quality Standards
|
- **单元测试**: JUnit 5 + Spring Boot Test
|
||||||
- Write clean, readable, and maintainable code
|
- **运行测试**: `mvn test`
|
||||||
- Follow consistent naming conventions across the project
|
- **测试分组**: 通过 `@Tag` 注解标记,根据环境执行
|
||||||
- Use meaningful variable and function names
|
- `@Tag("dev")` - 开发环境测试
|
||||||
- Keep functions focused and single-purpose
|
- `@Tag("prod")` - 生产环境测试
|
||||||
- Add comments for complex logic and business rules
|
- `@Tag("exclude")` - 排除的测试
|
||||||
|
|
||||||
### Git Workflow
|
## 问题排查
|
||||||
- Use descriptive commit messages following conventional commits format
|
|
||||||
- Create feature branches for new development
|
|
||||||
- Keep commits atomic and focused on single changes
|
|
||||||
- Use pull requests for code review before merging
|
|
||||||
- Maintain a clean commit history
|
|
||||||
|
|
||||||
### Documentation
|
### 后端启动失败
|
||||||
- Keep README.md files up to date
|
|
||||||
- Document public APIs and interfaces
|
|
||||||
- Include usage examples for complex features
|
|
||||||
- Maintain inline code documentation
|
|
||||||
- Update documentation when making changes
|
|
||||||
|
|
||||||
### Testing Approach
|
- 检查数据库连接配置
|
||||||
- Write tests for new features and bug fixes
|
- 检查 Redis 是否启动
|
||||||
- Maintain good test coverage
|
- 查看日志: `logs/sys-console.log`
|
||||||
- Use descriptive test names that explain the expected behavior
|
|
||||||
- Organize tests logically by feature or module
|
|
||||||
- Run tests before committing changes
|
|
||||||
|
|
||||||
### Security Best Practices
|
### 前端启动失败
|
||||||
- Never commit sensitive information (API keys, passwords, tokens)
|
|
||||||
- Use environment variables for configuration
|
|
||||||
- Validate input data and sanitize outputs
|
|
||||||
- Follow principle of least privilege
|
|
||||||
- Keep dependencies updated
|
|
||||||
|
|
||||||
## Project Structure Guidelines
|
- 删除 `node_modules` 重新安装
|
||||||
|
- 检查 Node.js 版本 >= 18.18.0
|
||||||
|
- 检查端口 80 是否被占用
|
||||||
|
|
||||||
### File Organization
|
### 接口调用失败
|
||||||
- Group related files in logical directories
|
|
||||||
- Use consistent file and folder naming conventions
|
|
||||||
- Separate source code from configuration files
|
|
||||||
- Keep build artifacts out of version control
|
|
||||||
- Organize assets and resources appropriately
|
|
||||||
|
|
||||||
### Configuration Management
|
- 检查后端服务是否启动
|
||||||
- Use configuration files for environment-specific settings
|
- 检查跨域配置
|
||||||
- Centralize configuration in dedicated files
|
- 查看浏览器控制台和网络请求
|
||||||
- Use environment variables for sensitive or environment-specific data
|
|
||||||
- Document configuration options and their purposes
|
|
||||||
- Provide example configuration files
|
|
||||||
|
|
||||||
## Development Workflow
|
## 框架技术注意事项
|
||||||
|
|
||||||
### Before Starting Work
|
1. **插件化架构**: 各 `ruoyi-common-*` 模块相互独立,可按需引入
|
||||||
1. Pull latest changes from main branch
|
2. **编码规范**: 严格遵守 Alibaba Java 编码规范
|
||||||
2. Create a new feature branch
|
3. **对象转换**: 使用 MapStruct-Plus 进行对象转换
|
||||||
3. Review existing code and architecture
|
4. **数据库连接池**: HikariCP (非 Druid)
|
||||||
4. Plan the implementation approach
|
5. **Web 容器**: Undertow (非 Tomcat)
|
||||||
|
6. **JSON 序列化**: Jackson (非 Fastjson)
|
||||||
### During Development
|
7. **接口加密**: 前后端需同时开启/关闭
|
||||||
1. Make incremental commits with clear messages
|
|
||||||
2. Run tests frequently to catch issues early
|
|
||||||
3. Follow established coding standards
|
|
||||||
4. Update documentation as needed
|
|
||||||
|
|
||||||
### Before Submitting
|
|
||||||
1. Run full test suite
|
|
||||||
2. Check code quality and formatting
|
|
||||||
3. Update documentation if necessary
|
|
||||||
4. Create clear pull request description
|
|
||||||
|
|
||||||
## Common Patterns
|
|
||||||
|
|
||||||
### Error Handling
|
|
||||||
- Use appropriate error handling mechanisms for the language
|
|
||||||
- Provide meaningful error messages
|
|
||||||
- Log errors appropriately for debugging
|
|
||||||
- Handle edge cases gracefully
|
|
||||||
- Don't expose sensitive information in error messages
|
|
||||||
|
|
||||||
### Performance Considerations
|
|
||||||
- Profile code for performance bottlenecks
|
|
||||||
- Optimize database queries and API calls
|
|
||||||
- Use caching where appropriate
|
|
||||||
- Consider memory usage and resource management
|
|
||||||
- Monitor and measure performance metrics
|
|
||||||
|
|
||||||
### Code Reusability
|
|
||||||
- Extract common functionality into reusable modules
|
|
||||||
- Use dependency injection for better testability
|
|
||||||
- Create utility functions for repeated operations
|
|
||||||
- Design interfaces for extensibility
|
|
||||||
- Follow DRY (Don't Repeat Yourself) principle
|
|
||||||
|
|
||||||
## Review Checklist
|
|
||||||
|
|
||||||
Before marking any task as complete:
|
|
||||||
- [ ] Code follows established conventions
|
|
||||||
- [ ] Tests are written and passing
|
|
||||||
- [ ] Documentation is updated
|
|
||||||
- [ ] Security considerations are addressed
|
|
||||||
- [ ] Performance impact is considered
|
|
||||||
- [ ] Code is reviewed for maintainability
|
|
||||||
|
|||||||
@@ -1,273 +0,0 @@
|
|||||||
# CLAUDE.md
|
|
||||||
|
|
||||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
||||||
|
|
||||||
## 项目概述
|
|
||||||
|
|
||||||
这是一个基于 RuoYi-Vue-Plus 5.5.1 的分布式多租户管理系统,采用前后端分离架构:
|
|
||||||
- **后端**: Spring Boot 3.5.7 + JDK 17/21 + MyBatis-Plus
|
|
||||||
- **前端**: Vue 3 + TypeScript + Element Plus + Vite
|
|
||||||
|
|
||||||
## 开发环境要求
|
|
||||||
|
|
||||||
### 后端
|
|
||||||
- JDK 17 或 JDK 21
|
|
||||||
- Maven 3.6+
|
|
||||||
- MySQL 5.7+ / Oracle / PostgreSQL / SQL Server
|
|
||||||
|
|
||||||
### 前端
|
|
||||||
- Node.js >= 18.18.0
|
|
||||||
- npm >= 8.9.0
|
|
||||||
|
|
||||||
## 常用命令
|
|
||||||
|
|
||||||
### 后端开发
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 编译项目(跳过测试)
|
|
||||||
mvn clean install -DskipTests
|
|
||||||
|
|
||||||
# 运行项目(默认 dev 环境)
|
|
||||||
mvn spring-boot:run
|
|
||||||
|
|
||||||
# 运行项目(指定环境)
|
|
||||||
mvn spring-boot:run -Plocal
|
|
||||||
mvn spring-boot:run -Pprod
|
|
||||||
|
|
||||||
# 运行单元测试
|
|
||||||
mvn test
|
|
||||||
|
|
||||||
# 打包生产环境
|
|
||||||
mvn clean package -Pprod
|
|
||||||
|
|
||||||
# 主应用入口
|
|
||||||
# ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java
|
|
||||||
```
|
|
||||||
|
|
||||||
### 前端开发
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 进入前端目录
|
|
||||||
cd plus-ui
|
|
||||||
|
|
||||||
# 安装依赖
|
|
||||||
npm install --registry=https://registry.npmmirror.com
|
|
||||||
|
|
||||||
# 启动开发服务器 (http://localhost:80)
|
|
||||||
npm run dev
|
|
||||||
|
|
||||||
# 构建生产环境
|
|
||||||
npm run build:prod
|
|
||||||
|
|
||||||
# 构建开发环境
|
|
||||||
npm run build:dev
|
|
||||||
|
|
||||||
# 代码检查和修复
|
|
||||||
npm run lint:eslint:fix
|
|
||||||
|
|
||||||
# 代码格式化
|
|
||||||
npm prettier
|
|
||||||
```
|
|
||||||
|
|
||||||
### Docker 部署
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# 使用 docker-compose 启动所有服务(MySQL + Redis + Nginx 等)
|
|
||||||
cd script/docker
|
|
||||||
docker-compose up -d
|
|
||||||
|
|
||||||
# 停止所有服务
|
|
||||||
docker-compose down
|
|
||||||
```
|
|
||||||
|
|
||||||
## 项目架构
|
|
||||||
|
|
||||||
### 后端模块结构
|
|
||||||
|
|
||||||
```
|
|
||||||
ruoyi-vue-plus/
|
|
||||||
├── ruoyi-admin/ # 主应用模块,Web服务入口
|
|
||||||
├── ruoyi-common/ # 通用模块(插件化架构)
|
|
||||||
│ ├── ruoyi-common-core/ # 核心模块
|
|
||||||
│ ├── ruoyi-common-mybatis/ # MyBatis-Plus 集成
|
|
||||||
│ ├── ruoyi-common-security/ # Sa-Token 安全认证
|
|
||||||
│ ├── ruoyi-common-oss/ # 对象存储(S3/Minio)
|
|
||||||
│ ├── ruoyi-common-doc/ # SpringDoc API文档
|
|
||||||
│ ├── ruoyi-common-redis/ # Redis 缓存
|
|
||||||
│ ├── ruoyi-common-job/ # SnailJob 定时任务
|
|
||||||
│ ├── ruoyi-common-json/ # Jackson 序列化
|
|
||||||
│ ├── ruoyi-common-log/ # 操作日志
|
|
||||||
│ ├── ruoyi-common-web/ # Web 配置
|
|
||||||
│ ├── ruoyi-common-translation/# 数据翻译
|
|
||||||
│ ├── ruoyi-common-encrypt/ # 数据加解密
|
|
||||||
│ ├── ruoyi-common-sensitive/ # 数据脱敏
|
|
||||||
│ ├── ruoyi-common-idempotent/ # 幂等处理
|
|
||||||
│ ├── ruoyi-common-ratelimiter/# 限流
|
|
||||||
│ ├── ruoyi-common-social/ # 第三方登录
|
|
||||||
│ ├── ruoyi-common-sms/ # 短信服务
|
|
||||||
│ ├── ruoyi-common-mail/ # 邮件服务
|
|
||||||
│ └── ruoyi-common-websocket/ # WebSocket/SSE
|
|
||||||
├── ruoyi-modules/ # 业务模块
|
|
||||||
│ ├── ruoyi-system/ # 系统管理模块
|
|
||||||
│ ├── ruoyi-generator/ # 代码生成器
|
|
||||||
│ ├── ruoyi-demo/ # 演示案例
|
|
||||||
│ ├── ruoyi-workflow/ # 工作流模块(Warm-Flow)
|
|
||||||
│ └── ruoyi-job/ # 任务调度
|
|
||||||
└── ruoyi-extend/ # 扩展模块
|
|
||||||
├── ruoyi-monitor-admin/ # SpringBoot Admin 监控
|
|
||||||
└── ruoyi-snailjob-server/ # SnailJob 调度中心
|
|
||||||
```
|
|
||||||
|
|
||||||
### 前端目录结构
|
|
||||||
|
|
||||||
```
|
|
||||||
plus-ui/
|
|
||||||
├── src/
|
|
||||||
│ ├── api/ # API 接口定义
|
|
||||||
│ │ ├── demo/ # 演示模块
|
|
||||||
│ │ ├── monitor/ # 监控模块
|
|
||||||
│ │ ├── system/ # 系统管理
|
|
||||||
│ │ ├── tool/ # 工具模块
|
|
||||||
│ │ └── workflow/ # 工作流
|
|
||||||
│ ├── assets/ # 静态资源
|
|
||||||
│ ├── components/ # 公共组件
|
|
||||||
│ ├── directive/ # 自定义指令
|
|
||||||
│ ├── hooks/ # 组合式函数
|
|
||||||
│ ├── layout/ # 布局组件
|
|
||||||
│ ├── lang/ # 国际化
|
|
||||||
│ ├── plugins/ # 插件封装
|
|
||||||
│ ├── router/ # 路由配置
|
|
||||||
│ ├── store/ # Pinia 状态管理
|
|
||||||
│ ├── types/ # TypeScript 类型定义
|
|
||||||
│ ├── utils/ # 工具函数
|
|
||||||
│ └── views/ # 页面视图
|
|
||||||
├── vite/ # Vite 插件配置
|
|
||||||
└── vite.config.ts # Vite 配置文件
|
|
||||||
```
|
|
||||||
|
|
||||||
## 核心技术架构
|
|
||||||
|
|
||||||
### 后端核心组件
|
|
||||||
|
|
||||||
1. **权限认证**: Sa-Token + JWT (非 Spring Security)
|
|
||||||
- 支持登录校验、角色校验、权限校验、二级认证等
|
|
||||||
- 支持复杂权限表达式 (AND/OR)
|
|
||||||
|
|
||||||
2. **ORM 框架**: MyBatis-Plus
|
|
||||||
- 雪花ID主键 (ASSIGN_ID)
|
|
||||||
- 多租户插件 (默认启用)
|
|
||||||
- 数据权限插件
|
|
||||||
- 分页插件
|
|
||||||
|
|
||||||
3. **缓存方案**: Redisson (非 Lettuce)
|
|
||||||
- 支持分布式锁 (Lock4j)
|
|
||||||
- 支持 Spring Cache 注解
|
|
||||||
|
|
||||||
4. **多数据源**: Dynamic-Datasource
|
|
||||||
- 支持异构数据库动态切换
|
|
||||||
|
|
||||||
5. **任务调度**: SnailJob (非 Quartz)
|
|
||||||
- 分布式任务调度
|
|
||||||
- 支持分片、重试、DAG 任务流
|
|
||||||
|
|
||||||
6. **工作流引擎**: Warm-Flow
|
|
||||||
- 国产工作流引擎
|
|
||||||
- 支持复杂审批流程
|
|
||||||
|
|
||||||
7. **文件存储**: MinIO / AWS S3
|
|
||||||
- 支持七牛、阿里云、腾讯云等
|
|
||||||
|
|
||||||
8. **API 文档**: SpringDoc (非 Springfox)
|
|
||||||
- 基于 javadoc 注释自动生成
|
|
||||||
- 零注解入侵
|
|
||||||
|
|
||||||
### 前端核心特性
|
|
||||||
|
|
||||||
1. **UI 框架**: Element Plus
|
|
||||||
2. **状态管理**: Pinia (非 Vuex)
|
|
||||||
3. **路由**: Vue Router 4
|
|
||||||
4. **HTTP 客户端**: Axios
|
|
||||||
5. **表格组件**: vxe-table
|
|
||||||
6. **接口加密**: RSA + AES 动态加密
|
|
||||||
|
|
||||||
## 配置说明
|
|
||||||
|
|
||||||
### 后端配置
|
|
||||||
|
|
||||||
- **主配置文件**: `ruoyi-admin/src/main/resources/application.yml`
|
|
||||||
- **环境配置**:
|
|
||||||
- `application-dev.yml` (开发)
|
|
||||||
- `application-prod.yml` (生产)
|
|
||||||
- `application-local.yml` (本地)
|
|
||||||
|
|
||||||
- **多环境切换**: 通过 Maven Profile 切换
|
|
||||||
```xml
|
|
||||||
<profiles.active>dev|prod|local</profiles.active>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 前端配置
|
|
||||||
|
|
||||||
- **环境变量**: `.env.development` / `.env.production`
|
|
||||||
- **代理配置**: `vite.config.ts` 中配置后端代理
|
|
||||||
- 默认代理到 `http://localhost:8080`
|
|
||||||
|
|
||||||
### 重要配置项
|
|
||||||
|
|
||||||
1. **多租户**: `tenant.enable=true` (默认开启)
|
|
||||||
2. **接口加密**: `api-decrypt.enabled=true`
|
|
||||||
3. **数据加密**: `mybatis-encryptor.enable=false` (默认关闭)
|
|
||||||
4. **WebSocket**: 默认关闭,推荐使用 SSE
|
|
||||||
5. **验证码**: `captcha.enable=true`
|
|
||||||
|
|
||||||
## 数据库说明
|
|
||||||
|
|
||||||
- **主键策略**: 雪花ID (ASSIGN_ID),不使用数据库自增
|
|
||||||
- **逻辑删除**: 默认启用 (`mybatis-plus.enableLogicDelete=true`)
|
|
||||||
- **多租户表**: 自动添加 `tenant_id` 字段 (排除表在配置中指定)
|
|
||||||
|
|
||||||
## 代码生成器
|
|
||||||
|
|
||||||
位于系统管理 -> 代码生成模块:
|
|
||||||
- 支持多数据源代码生成
|
|
||||||
- 自动生成 Controller、Service、Mapper、Vue 页面
|
|
||||||
- 符合项目规范的代码风格
|
|
||||||
|
|
||||||
## 监控与运维
|
|
||||||
|
|
||||||
1. **应用监控**: Spring Boot Admin
|
|
||||||
- 访问地址: `http://localhost:9090/admin`
|
|
||||||
- 用户名/密码: 配置文件中设置
|
|
||||||
|
|
||||||
2. **任务调度中心**: SnailJob
|
|
||||||
- 访问地址: `http://localhost:8800/snail-job`
|
|
||||||
|
|
||||||
3. **API 文档**: SpringDoc
|
|
||||||
- 开发环境访问: `http://localhost:8080/doc.html`
|
|
||||||
|
|
||||||
4. **日志**: Logback
|
|
||||||
- 日志路径: `./logs/sys-console.log`
|
|
||||||
|
|
||||||
## 测试
|
|
||||||
|
|
||||||
- **单元测试**: 使用 JUnit 5 + Spring Boot Test
|
|
||||||
- **运行测试**: `mvn test`
|
|
||||||
- **测试分组**: 通过 `@Tag` 注解标记,根据环境执行
|
|
||||||
|
|
||||||
## 注意事项
|
|
||||||
|
|
||||||
1. 项目采用插件化架构,各 `ruoyi-common-*` 模块相互独立,易于扩展
|
|
||||||
2. 严格遵守 Alibaba Java 编码规范
|
|
||||||
3. 使用 Lombok 简化代码,需要IDE安装 Lombok 插件
|
|
||||||
4. 使用 MapStruct-Plus 进行对象转换
|
|
||||||
5. 前端使用 TypeScript,需要注意类型定义
|
|
||||||
6. 接口加密功能前后端需同时开启/关闭
|
|
||||||
7. 数据库连接池使用 HikariCP (非 Druid)
|
|
||||||
8. Web 容器使用 Undertow (非 Tomcat)
|
|
||||||
|
|
||||||
## 部署端口
|
|
||||||
|
|
||||||
- 后端应用: 8080
|
|
||||||
- 前端应用: 80
|
|
||||||
- SnailJob 客户端: 28080
|
|
||||||
- Spring Boot Admin: 9090
|
|
||||||
- SnailJob Server: 8800
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# 页面标题
|
# 页面标题
|
||||||
VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统
|
VITE_APP_TITLE = AR巡检管理平台
|
||||||
VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus
|
VITE_APP_LOGO_TITLE = AR巡检管理平台
|
||||||
|
|
||||||
# 开发环境配置
|
# 开发环境配置
|
||||||
VITE_APP_ENV = 'development'
|
VITE_APP_ENV = 'development'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# 页面标题
|
# 页面标题
|
||||||
VITE_APP_TITLE = RuoYi-Vue-Plus多租户管理系统
|
VITE_APP_TITLE = AR巡检管理平台
|
||||||
VITE_APP_LOGO_TITLE = RuoYi-Vue-Plus
|
VITE_APP_LOGO_TITLE = AR巡检管理平台
|
||||||
|
|
||||||
# 生产环境配置
|
# 生产环境配置
|
||||||
VITE_APP_ENV = 'production'
|
VITE_APP_ENV = 'production'
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://json.schemastore.org/package",
|
"$schema": "https://json.schemastore.org/package",
|
||||||
"name": "ruoyi-vue-plus",
|
"name": "AR巡检管理平台",
|
||||||
"version": "5.5.1-2.5.1",
|
"version": "1.0.0",
|
||||||
"description": "RuoYi-Vue-Plus多租户管理系统",
|
"description": "AR巡检管理平台",
|
||||||
"author": "LionLi",
|
"author": "LionLi",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -15,10 +15,6 @@
|
|||||||
"lint:eslint:fix": "eslint --fix",
|
"lint:eslint:fix": "eslint --fix",
|
||||||
"prettier": "prettier --write ."
|
"prettier": "prettier --write ."
|
||||||
},
|
},
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://gitee.com/JavaLionLi/plus-ui.git"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "2.3.1",
|
"@element-plus/icons-vue": "2.3.1",
|
||||||
"@highlightjs/vue-plugin": "2.1.0",
|
"@highlightjs/vue-plugin": "2.1.0",
|
||||||
|
|||||||
@@ -27,8 +27,8 @@
|
|||||||
<svg-icon class-name="search-icon" icon-class="search" />
|
<svg-icon class-name="search-icon" icon-class="search" />
|
||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<!-- 消息 -->
|
<!-- 消息 - 已隐藏 -->
|
||||||
<el-tooltip :content="proxy.$t('navbar.message')" effect="dark" placement="bottom">
|
<el-tooltip v-if="false" :content="proxy.$t('navbar.message')" effect="dark" placement="bottom">
|
||||||
<div>
|
<div>
|
||||||
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
|
<el-popover placement="bottom" trigger="click" transition="el-zoom-in-top" :width="300" :persistent="false">
|
||||||
<template #reference>
|
<template #reference>
|
||||||
@@ -42,25 +42,6 @@
|
|||||||
</el-popover>
|
</el-popover>
|
||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-tooltip content="Github" effect="dark" placement="bottom">
|
|
||||||
<ruo-yi-git id="ruoyi-git" class="right-menu-item hover-effect" />
|
|
||||||
</el-tooltip>
|
|
||||||
|
|
||||||
<el-tooltip :content="proxy.$t('navbar.document')" effect="dark" placement="bottom">
|
|
||||||
<ruo-yi-doc id="ruoyi-doc" class="right-menu-item hover-effect" />
|
|
||||||
</el-tooltip>
|
|
||||||
|
|
||||||
<el-tooltip :content="proxy.$t('navbar.full')" effect="dark" placement="bottom">
|
|
||||||
<screenfull id="screenfull" class="right-menu-item hover-effect" />
|
|
||||||
</el-tooltip>
|
|
||||||
|
|
||||||
<el-tooltip :content="proxy.$t('navbar.language')" effect="dark" placement="bottom">
|
|
||||||
<lang-select id="lang-select" class="right-menu-item hover-effect" />
|
|
||||||
</el-tooltip>
|
|
||||||
|
|
||||||
<el-tooltip :content="proxy.$t('navbar.layoutSize')" effect="dark" placement="bottom">
|
|
||||||
<size-select id="size-select" class="right-menu-item hover-effect" />
|
|
||||||
</el-tooltip>
|
|
||||||
</template>
|
</template>
|
||||||
<div class="avatar-container">
|
<div class="avatar-container">
|
||||||
<el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand">
|
<el-dropdown class="right-menu-item hover-effect" trigger="click" @command="handleCommand">
|
||||||
@@ -281,6 +262,7 @@ watch(
|
|||||||
|
|
||||||
.avatar-container {
|
.avatar-container {
|
||||||
margin-right: 40px;
|
margin-right: 40px;
|
||||||
|
margin-left: 20px;
|
||||||
|
|
||||||
.avatar-wrapper {
|
.avatar-wrapper {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
@@ -290,7 +272,7 @@ watch(
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 40px;
|
width: 40px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
border-radius: 10px;
|
border-radius: 20px;
|
||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,6 @@
|
|||||||
<el-color-picker v-model="theme" :predefine="predefineColors" @change="themeChange" />
|
<el-color-picker v-model="theme" :predefine="predefineColors" @change="themeChange" />
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="drawer-item">
|
|
||||||
<span>深色模式</span>
|
|
||||||
<span class="comp-style">
|
|
||||||
<el-switch v-model="isDark" class="drawer-switch" @change="toggleDark" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-divider />
|
<el-divider />
|
||||||
|
|
||||||
@@ -114,22 +108,6 @@ const sideTheme = ref(settingsStore.sideTheme);
|
|||||||
const storeSettings = computed(() => settingsStore);
|
const storeSettings = computed(() => settingsStore);
|
||||||
const predefineColors = ref(['#409EFF', '#ff4500', '#ff8c00', '#ffd700', '#90ee90', '#00ced1', '#1e90ff', '#c71585']);
|
const predefineColors = ref(['#409EFF', '#ff4500', '#ff8c00', '#ffd700', '#90ee90', '#00ced1', '#1e90ff', '#c71585']);
|
||||||
|
|
||||||
// 是否暗黑模式
|
|
||||||
const isDark = useDark({
|
|
||||||
storageKey: 'useDarkKey',
|
|
||||||
valueDark: 'dark',
|
|
||||||
valueLight: 'light'
|
|
||||||
});
|
|
||||||
// 匹配菜单颜色
|
|
||||||
watch(isDark, () => {
|
|
||||||
if (isDark.value) {
|
|
||||||
settingsStore.sideTheme = SideThemeEnum.DARK;
|
|
||||||
} else {
|
|
||||||
settingsStore.sideTheme = sideTheme.value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const toggleDark = () => useToggle(isDark);
|
|
||||||
|
|
||||||
const topNavChange = (val: any) => {
|
const topNavChange = (val: any) => {
|
||||||
if (!val) {
|
if (!val) {
|
||||||
appStore.toggleSideBarHide(false);
|
appStore.toggleSideBarHide(false);
|
||||||
@@ -148,11 +126,6 @@ const themeChange = (val: string) => {
|
|||||||
};
|
};
|
||||||
const handleTheme = (val: string) => {
|
const handleTheme = (val: string) => {
|
||||||
sideTheme.value = val;
|
sideTheme.value = val;
|
||||||
if (isDark.value && val === SideThemeEnum.LIGHT) {
|
|
||||||
// 暗黑模式颜色不变
|
|
||||||
settingsStore.sideTheme = SideThemeEnum.DARK;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
settingsStore.sideTheme = val;
|
settingsStore.sideTheme = val;
|
||||||
};
|
};
|
||||||
const saveSetting = () => {
|
const saveSetting = () => {
|
||||||
|
|||||||
@@ -1,165 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="app-container home">
|
<div class="app-container home">
|
||||||
<el-row :gutter="20">
|
<h2>AR巡检管理平台 Dashboard</h2>
|
||||||
<el-col :sm="24" :lg="12" style="padding-left: 20px">
|
|
||||||
<h2>RuoYi-Vue-Plus多租户管理系统</h2>
|
|
||||||
<p>
|
|
||||||
RuoYi-Vue-Plus 是基于 RuoYi-Vue 针对 分布式集群 场景升级(不兼容原框架)
|
|
||||||
<br />
|
|
||||||
* 前端开发框架 Vue3、TS、Element Plus<br />
|
|
||||||
* 后端开发框架 Spring Boot<br />
|
|
||||||
* 容器框架 Undertow 基于 Netty 的高性能容器<br />
|
|
||||||
* 权限认证框架 Sa-Token 支持多终端认证系统<br />
|
|
||||||
* 关系数据库 MySQL 适配 8.X 最低 5.7<br />
|
|
||||||
* 缓存数据库 Redis 适配 6.X 最低 4.X<br />
|
|
||||||
* 数据库框架 Mybatis-Plus 快速 CRUD 增加开发效率<br />
|
|
||||||
* 数据库框架 p6spy 更强劲的 SQL 分析<br />
|
|
||||||
* 多数据源框架 dynamic-datasource 支持主从与多种类数据库异构<br />
|
|
||||||
* 序列化框架 Jackson 统一使用 jackson 高效可靠<br />
|
|
||||||
* Redis客户端 Redisson 性能强劲、API丰富<br />
|
|
||||||
* 分布式限流 Redisson 全局、请求IP、集群ID 多种限流<br />
|
|
||||||
* 分布式锁 Lock4j 注解锁、工具锁 多种多样<br />
|
|
||||||
* 分布式幂等 Lock4j 基于分布式锁实现<br />
|
|
||||||
* 分布式链路追踪 SkyWalking 支持链路追踪、网格分析、度量聚合、可视化<br />
|
|
||||||
* 分布式任务调度 SnailJob 高性能 高可靠 易扩展<br />
|
|
||||||
* 文件存储 Minio 本地存储<br />
|
|
||||||
* 文件存储 七牛、阿里、腾讯 云存储<br />
|
|
||||||
* 监控框架 SpringBoot-Admin 全方位服务监控<br />
|
|
||||||
* 校验框架 Validation 增强接口安全性 严谨性<br />
|
|
||||||
* Excel框架 FastExcel(原Alibaba EasyExcel) 性能优异 扩展性强<br />
|
|
||||||
* 文档框架 SpringDoc、javadoc 无注解零入侵基于java注释<br />
|
|
||||||
* 工具类框架 Hutool、Lombok 减少代码冗余 增加安全性<br />
|
|
||||||
* 代码生成器 适配MP、SpringDoc规范化代码 一键生成前后端代码<br />
|
|
||||||
* 部署方式 Docker 容器编排 一键部署业务集群<br />
|
|
||||||
* 国际化 SpringMessage Spring标准国际化方案<br />
|
|
||||||
</p>
|
|
||||||
<p><b>当前版本:</b> <span>v5.5.1</span></p>
|
|
||||||
<p>
|
|
||||||
<el-tag type="danger">¥免费开源</el-tag>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Vue-Plus')">访问码云</el-button>
|
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Vue-Plus')">访问GitHub</el-button>
|
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-vue-plus/changlog')"
|
|
||||||
>更新日志</el-button
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</el-col>
|
|
||||||
|
|
||||||
<el-col :sm="24" :lg="12" style="padding-left: 20px">
|
|
||||||
<h2>RuoYi-Cloud-Plus多租户微服务管理系统</h2>
|
|
||||||
<p>
|
|
||||||
RuoYi-Cloud-Plus 微服务通用权限管理系统 重写 RuoYi-Cloud 全方位升级(不兼容原框架)
|
|
||||||
<br />
|
|
||||||
* 前端开发框架 Vue3、TS、Element UI<br />
|
|
||||||
* 后端开发框架 Spring Boot<br />
|
|
||||||
* 微服务开发框架 Spring Cloud、Spring Cloud Alibaba<br />
|
|
||||||
* 容器框架 Undertow 基于 XNIO 的高性能容器<br />
|
|
||||||
* 权限认证框架 Sa-Token、Jwt 支持多终端认证系统<br />
|
|
||||||
* 关系数据库 MySQL 适配 8.X 最低 5.7<br />
|
|
||||||
* 关系数据库 Oracle 适配 11g 12c<br />
|
|
||||||
* 关系数据库 PostgreSQL 适配 13 14<br />
|
|
||||||
* 关系数据库 SQLServer 适配 2017 2019<br />
|
|
||||||
* 缓存数据库 Redis 适配 6.X 最低 5.X<br />
|
|
||||||
* 分布式注册中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br />
|
|
||||||
* 分布式配置中心 Alibaba Nacos 采用2.X 基于GRPC通信高性能<br />
|
|
||||||
* 服务网关 Spring Cloud Gateway 响应式高性能网关<br />
|
|
||||||
* 负载均衡 Spring Cloud Loadbalancer 负载均衡处理<br />
|
|
||||||
* RPC远程调用 Apache Dubbo 原生态使用体验、高性能<br />
|
|
||||||
* 分布式限流熔断 Alibaba Sentinel 无侵入、高扩展<br />
|
|
||||||
* 分布式事务 Alibaba Seata 无侵入、高扩展 支持 四种模式<br />
|
|
||||||
* 分布式消息队列 Apache Kafka 高性能高速度<br />
|
|
||||||
* 分布式消息队列 Apache RocketMQ 高可用功能多样<br />
|
|
||||||
* 分布式消息队列 RabbitMQ 支持各种扩展插件功能多样性<br />
|
|
||||||
* 分布式搜索引擎 ElasticSearch 业界知名<br />
|
|
||||||
* 分布式链路追踪 Apache SkyWalking 链路追踪、网格分析、度量聚合、可视化<br />
|
|
||||||
* 分布式日志中心 ELK 业界成熟解决方案<br />
|
|
||||||
* 分布式监控 Prometheus、Grafana 全方位性能监控<br />
|
|
||||||
* 其余与 Vue 版本一致<br />
|
|
||||||
</p>
|
|
||||||
<p><b>当前版本:</b> <span>v2.5.1</span></p>
|
|
||||||
<p>
|
|
||||||
<el-tag type="danger">¥免费开源</el-tag>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://gitee.com/dromara/RuoYi-Cloud-Plus')">访问码云</el-button>
|
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://github.com/dromara/RuoYi-Cloud-Plus')">访问GitHub</el-button>
|
|
||||||
<el-button type="primary" icon="Cloudy" plain @click="goTarget('https://plus-doc.dromara.org/#/ruoyi-cloud-plus/changlog')"
|
|
||||||
>更新日志</el-button
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</el-col>
|
|
||||||
</el-row>
|
|
||||||
<el-divider />
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="Index" lang="ts">
|
<script setup name="Index" lang="ts"></script>
|
||||||
const goTarget = (url: string) => {
|
|
||||||
window.open(url, '__blank');
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.home {
|
.home {
|
||||||
blockquote {
|
display: flex;
|
||||||
padding: 10px 20px;
|
justify-content: center;
|
||||||
margin: 0 0 20px;
|
align-items: center;
|
||||||
font-size: 17.5px;
|
height: 100%;
|
||||||
border-left: 5px solid #eee;
|
font-size: 24px;
|
||||||
}
|
font-weight: bold;
|
||||||
hr {
|
|
||||||
margin-top: 20px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
border: 0;
|
|
||||||
border-top: 1px solid #eee;
|
|
||||||
}
|
|
||||||
.col-item {
|
|
||||||
margin-bottom: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
font-family: 'open sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
|
||||||
font-size: 13px;
|
|
||||||
color: #676a6c;
|
|
||||||
overflow-x: hidden;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin-top: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
margin-top: 10px;
|
|
||||||
font-size: 26px;
|
|
||||||
font-weight: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-top: 10px;
|
|
||||||
|
|
||||||
b {
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.update-log {
|
|
||||||
ol {
|
|
||||||
display: block;
|
|
||||||
list-style-type: decimal;
|
|
||||||
margin-block-start: 1em;
|
|
||||||
margin-block-end: 1em;
|
|
||||||
margin-inline-start: 0;
|
|
||||||
margin-inline-end: 0;
|
|
||||||
padding-inline-start: 40px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -107,7 +107,13 @@
|
|||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="区域" prop="regionId">
|
<el-form-item label="区域" prop="regionId">
|
||||||
<el-select v-model="form.regionId" placeholder="请选择区域" filterable style="width: 100%">
|
<el-select
|
||||||
|
v-model="form.regionId"
|
||||||
|
placeholder="请选择任务模板后自动填充"
|
||||||
|
filterable
|
||||||
|
style="width: 100%"
|
||||||
|
:disabled="!!form.taskId && !form.id"
|
||||||
|
>
|
||||||
<el-option v-for="region in regionOptions" :key="region.id" :label="region.regionName" :value="region.id" />
|
<el-option v-for="region in regionOptions" :key="region.id" :label="region.regionName" :value="region.id" />
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -121,7 +127,8 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<!-- 仅编辑时显示状态字段 -->
|
||||||
|
<el-col v-if="form.id" :span="12">
|
||||||
<el-form-item label="执行状态" prop="status">
|
<el-form-item label="执行状态" prop="status">
|
||||||
<el-select v-model="form.status" placeholder="请选择状态" style="width: 100%">
|
<el-select v-model="form.status" placeholder="请选择状态" style="width: 100%">
|
||||||
<el-option label="待执行" value="pending" />
|
<el-option label="待执行" value="pending" />
|
||||||
@@ -134,34 +141,90 @@
|
|||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-divider content-position="left">执行角色</el-divider>
|
<el-divider content-position="left">执行角色</el-divider>
|
||||||
|
|
||||||
|
<!-- 操作人和监护人 -->
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="操作人" prop="operatorName">
|
<el-form-item label="操作人" prop="operatorName">
|
||||||
<el-input v-model="form.operatorName" placeholder="请输入操作人姓名" />
|
<el-input
|
||||||
|
v-model="form.operatorName"
|
||||||
|
placeholder="请选择操作人"
|
||||||
|
readonly
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<el-button icon="User" @click="operatorSelectRef.open()" />
|
||||||
|
<el-button v-if="form.operatorName" icon="Close" @click="clearUser('operator')" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="监护人" prop="custodianName">
|
<el-form-item label="监护人" prop="custodianName">
|
||||||
<el-input v-model="form.custodianName" placeholder="请输入监护人姓名" />
|
<el-input
|
||||||
|
v-model="form.custodianName"
|
||||||
|
placeholder="请选择监护人"
|
||||||
|
readonly
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<el-button icon="User" @click="custodianSelectRef.open()" />
|
||||||
|
<el-button v-if="form.custodianName" icon="Close" @click="clearUser('custodian')" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 送电人和受电人 -->
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="送电人" prop="senderName">
|
<el-form-item label="送电人" prop="senderName">
|
||||||
<el-input v-model="form.senderName" placeholder="请输入送电人姓名" />
|
<el-input
|
||||||
|
v-model="form.senderName"
|
||||||
|
placeholder="请选择送电人"
|
||||||
|
readonly
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<el-button icon="User" @click="senderSelectRef.open()" />
|
||||||
|
<el-button v-if="form.senderName" icon="Close" @click="clearUser('sender')" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="受电人" prop="recipientName">
|
<el-form-item label="受电人" prop="recipientName">
|
||||||
<el-input v-model="form.recipientName" placeholder="请输入受电人姓名" />
|
<el-input
|
||||||
|
v-model="form.recipientName"
|
||||||
|
placeholder="请选择受电人"
|
||||||
|
readonly
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<el-button icon="User" @click="recipientSelectRef.open()" />
|
||||||
|
<el-button v-if="form.recipientName" icon="Close" @click="clearUser('recipient')" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
|
<!-- 指挥人 -->
|
||||||
<el-row :gutter="20">
|
<el-row :gutter="20">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="指挥人" prop="commanderName">
|
<el-form-item label="指挥人" prop="commanderName">
|
||||||
<el-input v-model="form.commanderName" placeholder="请输入指挥人姓名" />
|
<el-input
|
||||||
|
v-model="form.commanderName"
|
||||||
|
placeholder="请选择指挥人"
|
||||||
|
readonly
|
||||||
|
style="width: 100%"
|
||||||
|
>
|
||||||
|
<template #append>
|
||||||
|
<el-button icon="User" @click="commanderSelectRef.open()" />
|
||||||
|
<el-button v-if="form.commanderName" icon="Close" @click="clearUser('commander')" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
@@ -173,18 +236,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
|
<!-- 用户选择组件 -->
|
||||||
|
<UserSelect ref="operatorSelectRef" :multiple="false" @confirmCallBack="handleOperatorSelect" />
|
||||||
|
<UserSelect ref="custodianSelectRef" :multiple="false" @confirmCallBack="handleCustodianSelect" />
|
||||||
|
<UserSelect ref="senderSelectRef" :multiple="false" @confirmCallBack="handleSenderSelect" />
|
||||||
|
<UserSelect ref="recipientSelectRef" :multiple="false" @confirmCallBack="handleRecipientSelect" />
|
||||||
|
<UserSelect ref="commanderSelectRef" :multiple="false" @confirmCallBack="handleCommanderSelect" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup name="ArExecution" lang="ts">
|
<script setup name="ArExecution" lang="ts">
|
||||||
import { listArExecution, getArExecution, delArExecution, addArExecution, updateArExecution } from '@/api/inspection/execution';
|
import { listArExecution, getArExecution, delArExecution, addArExecution, updateArExecution } from '@/api/inspection/execution';
|
||||||
import { ArExecutionVO, ArExecutionQuery, ArExecutionForm } from '@/api/inspection/execution/types';
|
import { ArExecutionVO, ArExecutionQuery, ArExecutionForm } from '@/api/inspection/execution/types';
|
||||||
import { listArTask } from '@/api/inspection/task';
|
import { listArTask, getArTask } from '@/api/inspection/task';
|
||||||
import { ArTaskVO } from '@/api/inspection/task/types';
|
import { ArTaskVO } from '@/api/inspection/task/types';
|
||||||
import { listArRegion } from '@/api/inspection/region';
|
import { listArRegion } from '@/api/inspection/region';
|
||||||
import { ArRegionVO } from '@/api/inspection/region/types';
|
import { ArRegionVO } from '@/api/inspection/region/types';
|
||||||
import { listArDevice } from '@/api/inspection/device';
|
import { listArDevice } from '@/api/inspection/device';
|
||||||
import { ArDeviceVO } from '@/api/inspection/device/types';
|
import { ArDeviceVO } from '@/api/inspection/device/types';
|
||||||
|
import { UserVO } from '@/api/system/user/types';
|
||||||
|
import UserSelect from '@/components/UserSelect/index.vue';
|
||||||
|
|
||||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||||
|
|
||||||
@@ -203,6 +275,12 @@ const total = ref(0);
|
|||||||
const queryFormRef = ref<ElFormInstance>();
|
const queryFormRef = ref<ElFormInstance>();
|
||||||
const executionFormRef = ref<ElFormInstance>();
|
const executionFormRef = ref<ElFormInstance>();
|
||||||
|
|
||||||
|
const operatorSelectRef = ref();
|
||||||
|
const custodianSelectRef = ref();
|
||||||
|
const senderSelectRef = ref();
|
||||||
|
const recipientSelectRef = ref();
|
||||||
|
const commanderSelectRef = ref();
|
||||||
|
|
||||||
const dialog = reactive<DialogOption>({
|
const dialog = reactive<DialogOption>({
|
||||||
visible: false,
|
visible: false,
|
||||||
title: ''
|
title: ''
|
||||||
@@ -369,6 +447,90 @@ const handleExport = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 监听任务模板变化,自动填充区域 */
|
||||||
|
watch(() => form.value.taskId, async (newTaskId) => {
|
||||||
|
if (newTaskId && !form.value.id) { // 仅新增时自动填充
|
||||||
|
try {
|
||||||
|
const res = await getArTask(newTaskId);
|
||||||
|
if (res.data && res.data.regionId) {
|
||||||
|
form.value.regionId = res.data.regionId;
|
||||||
|
const region = regionOptions.value.find(r => r.id === res.data.regionId);
|
||||||
|
if (region) {
|
||||||
|
proxy?.$modal.msgSuccess(`已自动填充区域:${region.regionName}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取任务模板详情失败', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/** 操作人选择回调 */
|
||||||
|
const handleOperatorSelect = (users: UserVO[]) => {
|
||||||
|
if (users && users.length > 0) {
|
||||||
|
form.value.operatorId = users[0].userId;
|
||||||
|
form.value.operatorName = users[0].nickName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 监护人选择回调 */
|
||||||
|
const handleCustodianSelect = (users: UserVO[]) => {
|
||||||
|
if (users && users.length > 0) {
|
||||||
|
form.value.custodianId = users[0].userId;
|
||||||
|
form.value.custodianName = users[0].nickName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 送电人选择回调 */
|
||||||
|
const handleSenderSelect = (users: UserVO[]) => {
|
||||||
|
if (users && users.length > 0) {
|
||||||
|
form.value.senderId = users[0].userId;
|
||||||
|
form.value.senderName = users[0].nickName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 受电人选择回调 */
|
||||||
|
const handleRecipientSelect = (users: UserVO[]) => {
|
||||||
|
if (users && users.length > 0) {
|
||||||
|
form.value.recipientId = users[0].userId;
|
||||||
|
form.value.recipientName = users[0].nickName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 指挥人选择回调 */
|
||||||
|
const handleCommanderSelect = (users: UserVO[]) => {
|
||||||
|
if (users && users.length > 0) {
|
||||||
|
form.value.commanderId = users[0].userId;
|
||||||
|
form.value.commanderName = users[0].nickName;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** 清空人员选择 */
|
||||||
|
const clearUser = (role: 'operator' | 'custodian' | 'sender' | 'recipient' | 'commander') => {
|
||||||
|
switch (role) {
|
||||||
|
case 'operator':
|
||||||
|
form.value.operatorId = undefined;
|
||||||
|
form.value.operatorName = undefined;
|
||||||
|
break;
|
||||||
|
case 'custodian':
|
||||||
|
form.value.custodianId = undefined;
|
||||||
|
form.value.custodianName = undefined;
|
||||||
|
break;
|
||||||
|
case 'sender':
|
||||||
|
form.value.senderId = undefined;
|
||||||
|
form.value.senderName = undefined;
|
||||||
|
break;
|
||||||
|
case 'recipient':
|
||||||
|
form.value.recipientId = undefined;
|
||||||
|
form.value.recipientName = undefined;
|
||||||
|
break;
|
||||||
|
case 'commander':
|
||||||
|
form.value.commanderId = undefined;
|
||||||
|
form.value.commanderName = undefined;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getOptions();
|
getOptions();
|
||||||
getList();
|
getList();
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }}</el-checkbox>
|
<el-checkbox v-model="loginForm.rememberMe" style="margin: 0 0 25px 0">{{ proxy.$t('login.rememberPassword') }}</el-checkbox>
|
||||||
<el-form-item style="float: right">
|
<el-form-item v-if="false" style="float: right">
|
||||||
<el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">
|
<el-button circle :title="proxy.$t('login.social.wechat')" @click="doSocialLogin('wechat')">
|
||||||
<svg-icon icon-class="wechat" />
|
<svg-icon icon-class="wechat" />
|
||||||
</el-button>
|
</el-button>
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
</el-form>
|
</el-form>
|
||||||
<!-- 底部 -->
|
<!-- 底部 -->
|
||||||
<div class="el-login-footer">
|
<div class="el-login-footer">
|
||||||
<span>Copyright © 2018-2025 疯狂的狮子Li All Rights Reserved.</span>
|
<span>Copyright © 2021-2025 NJCQ Tech All Rights Reserved.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -96,8 +96,8 @@ const { t } = useI18n();
|
|||||||
|
|
||||||
const loginForm = ref<LoginData>({
|
const loginForm = ref<LoginData>({
|
||||||
tenantId: '000000',
|
tenantId: '000000',
|
||||||
username: 'admin',
|
username: '',
|
||||||
password: 'admin123',
|
password: '',
|
||||||
rememberMe: false,
|
rememberMe: false,
|
||||||
code: '',
|
code: '',
|
||||||
uuid: ''
|
uuid: ''
|
||||||
@@ -236,8 +236,9 @@ onMounted(() => {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
background-image: url('../assets/images/login-background.jpg');
|
// background-image: url('../assets/images/login-background.jpg');
|
||||||
background-size: cover;
|
background-color: #28273a;
|
||||||
|
// background-size: cover;
|
||||||
}
|
}
|
||||||
|
|
||||||
.title-box {
|
.title-box {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export default defineConfig(({ mode, command }) => {
|
|||||||
open: true,
|
open: true,
|
||||||
proxy: {
|
proxy: {
|
||||||
[env.VITE_APP_BASE_API]: {
|
[env.VITE_APP_BASE_API]: {
|
||||||
target: 'http://localhost:8080',
|
target: 'http://119.45.199.65:8081',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
ws: true,
|
ws: true,
|
||||||
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
rewrite: (path) => path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
|
||||||
|
|||||||
@@ -103,13 +103,14 @@ public class AuthController {
|
|||||||
// 登录
|
// 登录
|
||||||
LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
|
LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
|
||||||
|
|
||||||
Long userId = LoginHelper.getUserId();
|
// 注释掉登录欢迎消息推送 - UI定制需求
|
||||||
scheduledExecutorService.schedule(() -> {
|
// Long userId = LoginHelper.getUserId();
|
||||||
SseMessageDto dto = new SseMessageDto();
|
// scheduledExecutorService.schedule(() -> {
|
||||||
dto.setMessage("欢迎登录RuoYi-Vue-Plus后台管理系统");
|
// SseMessageDto dto = new SseMessageDto();
|
||||||
dto.setUserIds(List.of(userId));
|
// dto.setMessage("欢迎登录RuoYi-Vue-Plus后台管理系统");
|
||||||
SseMessageUtils.publishMessage(dto);
|
// dto.setUserIds(List.of(userId));
|
||||||
}, 5, TimeUnit.SECONDS);
|
// SseMessageUtils.publishMessage(dto);
|
||||||
|
// }, 5, TimeUnit.SECONDS);
|
||||||
return R.ok(loginVo);
|
return R.ok(loginVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ spring.servlet.multipart.location: /ruoyi/server/temp
|
|||||||
--- # 监控中心配置
|
--- # 监控中心配置
|
||||||
spring.boot.admin.client:
|
spring.boot.admin.client:
|
||||||
# 增加客户端开关
|
# 增加客户端开关
|
||||||
enabled: true
|
enabled: false
|
||||||
url: http://localhost:9090/admin
|
url: http://localhost:9090/admin
|
||||||
instance:
|
instance:
|
||||||
service-host-type: IP
|
service-host-type: IP
|
||||||
@@ -16,7 +16,7 @@ spring.boot.admin.client:
|
|||||||
|
|
||||||
--- # snail-job 配置
|
--- # snail-job 配置
|
||||||
snail-job:
|
snail-job:
|
||||||
enabled: true
|
enabled: false
|
||||||
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
|
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
|
||||||
group: "ruoyi_group"
|
group: "ruoyi_group"
|
||||||
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表
|
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config`表
|
||||||
@@ -50,9 +50,9 @@ spring:
|
|||||||
driverClassName: com.mysql.cj.jdbc.Driver
|
driverClassName: com.mysql.cj.jdbc.Driver
|
||||||
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
|
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
|
||||||
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
|
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
|
||||||
url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
url: jdbc:mysql://1Panel-mysql-TAXz:3306/ari?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
|
||||||
username: root
|
username: ari
|
||||||
password: root
|
password: fhWpsBYNxZfdAEph
|
||||||
# # 从库数据源
|
# # 从库数据源
|
||||||
# slave:
|
# slave:
|
||||||
# lazy: true
|
# lazy: true
|
||||||
@@ -99,13 +99,13 @@ spring:
|
|||||||
spring.data:
|
spring.data:
|
||||||
redis:
|
redis:
|
||||||
# 地址
|
# 地址
|
||||||
host: localhost
|
host: 1Panel-redis-HCyW
|
||||||
# 端口,默认为6379
|
# 端口,默认为6379
|
||||||
port: 6379
|
port: 6379
|
||||||
# 数据库索引
|
# 数据库索引
|
||||||
database: 0
|
database: 1
|
||||||
# redis 密码必须配置
|
# redis 密码必须配置
|
||||||
password: ruoyi123
|
password: redis_X7Ehme
|
||||||
# 连接超时时间
|
# 连接超时时间
|
||||||
timeout: 10s
|
timeout: 10s
|
||||||
# 是否开启ssl
|
# 是否开启ssl
|
||||||
|
|||||||
@@ -195,16 +195,16 @@ springdoc:
|
|||||||
enabled: true
|
enabled: true
|
||||||
info:
|
info:
|
||||||
# 标题
|
# 标题
|
||||||
title: '标题:RuoYi-Vue-Plus多租户管理系统_接口文档'
|
title: 'AR智能巡检平台-接口文档'
|
||||||
# 描述
|
# 描述
|
||||||
description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
|
description: 'AR智能巡检平台 接口文档'
|
||||||
# 版本
|
# 版本
|
||||||
version: '版本号: ${project.version}'
|
version: '版本号: ${project.version}'
|
||||||
# 作者信息
|
# 作者信息
|
||||||
contact:
|
contact:
|
||||||
name: Lion Li
|
name: YANG JIANKUAN
|
||||||
email: crazylionli@163.com
|
email: tim.yee@hotmail.com
|
||||||
url: https://gitee.com/dromara/RuoYi-Vue-Plus
|
url: https://www.njcqit.com
|
||||||
#这里定义了两个分组,可定义多个,也可以不定义
|
#这里定义了两个分组,可定义多个,也可以不定义
|
||||||
group-configs:
|
group-configs:
|
||||||
- group: 1.演示模块
|
- group: 1.演示模块
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.dromara.inspection.controller;
|
package org.dromara.inspection.controller;
|
||||||
|
|
||||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||||
|
import cn.dev33.satoken.annotation.SaIgnore;
|
||||||
import org.dromara.common.core.domain.R;
|
import org.dromara.common.core.domain.R;
|
||||||
import org.dromara.common.core.validate.AddGroup;
|
import org.dromara.common.core.validate.AddGroup;
|
||||||
import org.dromara.common.core.validate.EditGroup;
|
import org.dromara.common.core.validate.EditGroup;
|
||||||
@@ -13,6 +14,8 @@ import org.dromara.common.excel.utils.ExcelUtil;
|
|||||||
import org.dromara.common.log.annotation.Log;
|
import org.dromara.common.log.annotation.Log;
|
||||||
import org.dromara.common.log.enums.BusinessType;
|
import org.dromara.common.log.enums.BusinessType;
|
||||||
import org.dromara.inspection.domain.bo.ArExecutionBo;
|
import org.dromara.inspection.domain.bo.ArExecutionBo;
|
||||||
|
import org.dromara.inspection.domain.bo.ArExecutionSubmitBo;
|
||||||
|
import org.dromara.inspection.domain.vo.ArExecutionDetailVo;
|
||||||
import org.dromara.inspection.domain.vo.ArExecutionVo;
|
import org.dromara.inspection.domain.vo.ArExecutionVo;
|
||||||
import org.dromara.inspection.service.IArExecutionService;
|
import org.dromara.inspection.service.IArExecutionService;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -61,15 +64,16 @@ public class ArExecutionController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取任务执行记录详细信息
|
* 获取任务执行记录详细信息(包含关联对象和步骤树)
|
||||||
*
|
*
|
||||||
* @param id 执行ID
|
* @param id 执行ID
|
||||||
*/
|
*/
|
||||||
@SaCheckPermission("inspection:execution:query")
|
@SaCheckPermission("inspection:execution:query")
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
public R<ArExecutionVo> getInfo(@NotNull(message = "执行ID不能为空")
|
@SaIgnore
|
||||||
@PathVariable("id") Long id) {
|
public R<ArExecutionDetailVo> getInfo(@NotNull(message = "执行ID不能为空")
|
||||||
return R.ok(arExecutionService.queryById(id));
|
@PathVariable("id") Long id) {
|
||||||
|
return R.ok(arExecutionService.queryDetailById(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -94,6 +98,18 @@ public class ArExecutionController extends BaseController {
|
|||||||
return toAjax(arExecutionService.updateByBo(bo));
|
return toAjax(arExecutionService.updateByBo(bo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量提交任务执行结果
|
||||||
|
*/
|
||||||
|
@SaCheckPermission("inspection:execution:submit")
|
||||||
|
@Log(title = "提交任务执行结果", businessType = BusinessType.UPDATE)
|
||||||
|
@RepeatSubmit
|
||||||
|
@SaIgnore
|
||||||
|
@PostMapping("/submit")
|
||||||
|
public R<Void> submit(@Validated @RequestBody ArExecutionSubmitBo bo) {
|
||||||
|
return toAjax(arExecutionService.submitExecution(bo));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除任务执行记录
|
* 删除任务执行记录
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -40,9 +40,11 @@ public class ArStepRecordController extends BaseController {
|
|||||||
|
|
||||||
private final IArStepRecordService arStepRecordService;
|
private final IArStepRecordService arStepRecordService;
|
||||||
|
|
||||||
/**
|
|
||||||
|
/**
|
||||||
* 查询步骤执行记录列表
|
* 查询步骤执行记录列表
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@SaCheckPermission("inspection:stepRecord:list")
|
@SaCheckPermission("inspection:stepRecord:list")
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo<ArStepRecordVo> list(@Validated(QueryGroup.class) ArStepRecordBo bo, PageQuery pageQuery) {
|
public TableDataInfo<ArStepRecordVo> list(@Validated(QueryGroup.class) ArStepRecordBo bo, PageQuery pageQuery) {
|
||||||
|
|||||||
@@ -0,0 +1,51 @@
|
|||||||
|
package org.dromara.inspection.domain.bo;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务执行提交业务对象
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
* @date 2025-01-13
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ArExecutionSubmitBo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行ID
|
||||||
|
*/
|
||||||
|
@NotNull(message = "执行ID不能为空")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态(pending/in_progress/completed/cancelled)
|
||||||
|
*/
|
||||||
|
private String status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*/
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结束时间
|
||||||
|
*/
|
||||||
|
private Date endTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤执行树
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
private List<ArStepRecordTreeBo> stepTree;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
package org.dromara.inspection.domain.bo;
|
||||||
|
|
||||||
|
import jakarta.validation.Valid;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤执行记录树形业务对象
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
* @date 2025-01-13
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ArStepRecordTreeBo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤ID(仅用于引用)
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行记录ID(用于更新现有记录)
|
||||||
|
*/
|
||||||
|
private Long recordId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行状态(pending/completed/skipped)
|
||||||
|
*/
|
||||||
|
private String recordStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否完成(0否 1是)
|
||||||
|
*/
|
||||||
|
private String isDone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*/
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成时间
|
||||||
|
*/
|
||||||
|
private Date completionTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 耗时(秒)
|
||||||
|
*/
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本反馈
|
||||||
|
*/
|
||||||
|
private String textFeedback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音识别文本
|
||||||
|
*/
|
||||||
|
private String voiceText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI识别结果(JSON)
|
||||||
|
*/
|
||||||
|
private String aiResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行人ID
|
||||||
|
*/
|
||||||
|
private Long executorId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行人姓名
|
||||||
|
*/
|
||||||
|
private String executorName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子步骤列表
|
||||||
|
*/
|
||||||
|
@Valid
|
||||||
|
private List<ArStepRecordTreeBo> children;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
package org.dromara.inspection.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务执行详情视图对象
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
* @date 2025-01-13
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ArExecutionDetailVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行基本信息
|
||||||
|
*/
|
||||||
|
private ArExecutionVo execution;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 任务模板信息
|
||||||
|
*/
|
||||||
|
private ArTaskVo task;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 区域信息
|
||||||
|
*/
|
||||||
|
private ArRegionVo region;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设备信息
|
||||||
|
*/
|
||||||
|
private ArDeviceVo device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤执行树
|
||||||
|
*/
|
||||||
|
private List<ArStepRecordTreeVo> stepTree;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
package org.dromara.inspection.domain.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serial;
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤执行记录树形视图对象
|
||||||
|
*
|
||||||
|
* @author Lion Li
|
||||||
|
* @date 2025-01-13
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ArStepRecordTreeVo implements Serializable {
|
||||||
|
|
||||||
|
@Serial
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
// ========== 步骤模板信息(来自 ar_step) ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤ID
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 所属任务ID
|
||||||
|
*/
|
||||||
|
private Long taskId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 父步骤ID(0为顶级)
|
||||||
|
*/
|
||||||
|
private Long parentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 祖级列表
|
||||||
|
*/
|
||||||
|
private String ancestors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤名称
|
||||||
|
*/
|
||||||
|
private String stepName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤内容描述
|
||||||
|
*/
|
||||||
|
private String stepContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤语音文本
|
||||||
|
*/
|
||||||
|
private String contentVoice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 排序号
|
||||||
|
*/
|
||||||
|
private Integer orderNum;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 关联点位ID
|
||||||
|
*/
|
||||||
|
private Long pointId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要语音朗读(0否 1是)
|
||||||
|
*/
|
||||||
|
private String needVoiceRead;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要用户复述(0否 1是)
|
||||||
|
*/
|
||||||
|
private String needVoiceRephrase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复述提示文本
|
||||||
|
*/
|
||||||
|
private String rephraseContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复述语音文本
|
||||||
|
*/
|
||||||
|
private String rephraseVoice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要确认(0否 1是)
|
||||||
|
*/
|
||||||
|
private String needVoiceConfirm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认提示文本
|
||||||
|
*/
|
||||||
|
private String confirmContent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认语音文本
|
||||||
|
*/
|
||||||
|
private String confirmVoice;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 确认词
|
||||||
|
*/
|
||||||
|
private String confirmWord;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 需要AI识别(0否 1是)
|
||||||
|
*/
|
||||||
|
private String needAi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI目标名称
|
||||||
|
*/
|
||||||
|
private String aiTargetName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI配置数据(预留)
|
||||||
|
*/
|
||||||
|
private Map<String, Object> aiData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否操作步骤(0否 1是)
|
||||||
|
*/
|
||||||
|
private String isOperation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否叶子节点(0否 1是)
|
||||||
|
*/
|
||||||
|
private String isLeaf;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建时间
|
||||||
|
*/
|
||||||
|
private Date createTime;
|
||||||
|
|
||||||
|
// ========== 执行记录信息(来自 ar_step_record) ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行记录ID
|
||||||
|
*/
|
||||||
|
private Long recordId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行状态(pending/completed/skipped)
|
||||||
|
*/
|
||||||
|
private String recordStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否完成(0否 1是)
|
||||||
|
*/
|
||||||
|
private String isDone;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 开始时间
|
||||||
|
*/
|
||||||
|
private Date startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 完成时间
|
||||||
|
*/
|
||||||
|
private Date completionTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 耗时(秒)
|
||||||
|
*/
|
||||||
|
private Integer duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文本反馈
|
||||||
|
*/
|
||||||
|
private String textFeedback;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音识别文本
|
||||||
|
*/
|
||||||
|
private String voiceText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AI识别结果(JSON)
|
||||||
|
*/
|
||||||
|
private String aiResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行人ID
|
||||||
|
*/
|
||||||
|
private Long executorId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 执行人姓名
|
||||||
|
*/
|
||||||
|
private String executorName;
|
||||||
|
|
||||||
|
// ========== 树形结构 ==========
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子步骤列表
|
||||||
|
*/
|
||||||
|
private List<ArStepRecordTreeVo> children;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ package org.dromara.inspection.service;
|
|||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.inspection.domain.bo.ArExecutionBo;
|
import org.dromara.inspection.domain.bo.ArExecutionBo;
|
||||||
|
import org.dromara.inspection.domain.bo.ArExecutionSubmitBo;
|
||||||
|
import org.dromara.inspection.domain.vo.ArExecutionDetailVo;
|
||||||
import org.dromara.inspection.domain.vo.ArExecutionVo;
|
import org.dromara.inspection.domain.vo.ArExecutionVo;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -23,6 +25,22 @@ public interface IArExecutionService {
|
|||||||
*/
|
*/
|
||||||
ArExecutionVo queryById(Long id);
|
ArExecutionVo queryById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询任务执行详情(包含关联对象和步骤树)
|
||||||
|
*
|
||||||
|
* @param id 执行ID
|
||||||
|
* @return 任务执行详情VO
|
||||||
|
*/
|
||||||
|
ArExecutionDetailVo queryDetailById(Long id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量提交任务执行结果
|
||||||
|
*
|
||||||
|
* @param bo 提交业务对象
|
||||||
|
* @return 是否成功
|
||||||
|
*/
|
||||||
|
Boolean submitExecution(ArExecutionSubmitBo bo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询列表
|
* 查询列表
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -10,16 +10,21 @@ import org.dromara.common.core.utils.StringUtils;
|
|||||||
import org.dromara.common.mybatis.core.page.PageQuery;
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
||||||
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
||||||
import org.dromara.inspection.domain.ArExecution;
|
import org.dromara.inspection.domain.ArExecution;
|
||||||
|
import org.dromara.inspection.domain.ArStep;
|
||||||
|
import org.dromara.inspection.domain.ArStepRecord;
|
||||||
import org.dromara.inspection.domain.bo.ArExecutionBo;
|
import org.dromara.inspection.domain.bo.ArExecutionBo;
|
||||||
import org.dromara.inspection.domain.vo.ArExecutionVo;
|
import org.dromara.inspection.domain.bo.ArExecutionSubmitBo;
|
||||||
import org.dromara.inspection.mapper.ArExecutionMapper;
|
import org.dromara.inspection.domain.bo.ArStepRecordTreeBo;
|
||||||
|
import org.dromara.inspection.domain.vo.*;
|
||||||
|
import org.dromara.inspection.mapper.*;
|
||||||
import org.dromara.inspection.service.IArExecutionService;
|
import org.dromara.inspection.service.IArExecutionService;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.*;
|
||||||
import java.util.Date;
|
import java.util.stream.Collectors;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 任务执行记录Service业务层处理
|
* 任务执行记录Service业务层处理
|
||||||
@@ -32,6 +37,11 @@ import java.util.Map;
|
|||||||
public class ArExecutionServiceImpl implements IArExecutionService {
|
public class ArExecutionServiceImpl implements IArExecutionService {
|
||||||
|
|
||||||
private final ArExecutionMapper baseMapper;
|
private final ArExecutionMapper baseMapper;
|
||||||
|
private final ArTaskMapper taskMapper;
|
||||||
|
private final ArRegionMapper regionMapper;
|
||||||
|
private final ArDeviceMapper deviceMapper;
|
||||||
|
private final ArStepMapper stepMapper;
|
||||||
|
private final ArStepRecordMapper stepRecordMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ArExecutionVo queryById(Long id) {
|
public ArExecutionVo queryById(Long id) {
|
||||||
@@ -141,4 +151,253 @@ public class ArExecutionServiceImpl implements IArExecutionService {
|
|||||||
}
|
}
|
||||||
return baseMapper.deleteByIds(ids) > 0;
|
return baseMapper.deleteByIds(ids) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ArExecutionDetailVo queryDetailById(Long id) {
|
||||||
|
// 1. 查询执行记录
|
||||||
|
ArExecutionVo execution = baseMapper.selectVoById(id);
|
||||||
|
if (execution == null) {
|
||||||
|
throw new ServiceException("任务执行记录不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 查询关联对象
|
||||||
|
ArTaskVo task = execution.getTaskId() != null
|
||||||
|
? taskMapper.selectVoById(execution.getTaskId()) : null;
|
||||||
|
ArRegionVo region = execution.getRegionId() != null
|
||||||
|
? regionMapper.selectVoById(execution.getRegionId()) : null;
|
||||||
|
ArDeviceVo device = execution.getDeviceId() != null
|
||||||
|
? deviceMapper.selectVoById(execution.getDeviceId()) : null;
|
||||||
|
|
||||||
|
// 3. 查询步骤模板
|
||||||
|
List<ArStepVo> allSteps = new ArrayList<>();
|
||||||
|
if (execution.getTaskId() != null) {
|
||||||
|
LambdaQueryWrapper<ArStep> stepWrapper = Wrappers.lambdaQuery();
|
||||||
|
stepWrapper.eq(ArStep::getTaskId, execution.getTaskId());
|
||||||
|
stepWrapper.orderByAsc(ArStep::getOrderNum);
|
||||||
|
allSteps = stepMapper.selectVoList(stepWrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 查询执行记录
|
||||||
|
LambdaQueryWrapper<ArStepRecord> recordWrapper = Wrappers.lambdaQuery();
|
||||||
|
recordWrapper.eq(ArStepRecord::getExecutionId, id);
|
||||||
|
List<ArStepRecordVo> allRecords = stepRecordMapper.selectVoList(recordWrapper);
|
||||||
|
|
||||||
|
// 5. 构建步骤记录 Map
|
||||||
|
Map<Long, ArStepRecordVo> recordMap = allRecords.stream()
|
||||||
|
.collect(Collectors.toMap(ArStepRecordVo::getStepId, r -> r, (r1, r2) -> r1));
|
||||||
|
|
||||||
|
// 6. 构建步骤树
|
||||||
|
List<ArStepRecordTreeVo> stepTree = buildStepRecordTree(allSteps, recordMap, 0L);
|
||||||
|
|
||||||
|
// 7. 组装返回对象
|
||||||
|
ArExecutionDetailVo detail = new ArExecutionDetailVo();
|
||||||
|
detail.setExecution(execution);
|
||||||
|
detail.setTask(task);
|
||||||
|
detail.setRegion(region);
|
||||||
|
detail.setDevice(device);
|
||||||
|
detail.setStepTree(stepTree);
|
||||||
|
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归构建步骤执行记录树
|
||||||
|
*
|
||||||
|
* @param allSteps 所有步骤模板
|
||||||
|
* @param recordMap 执行记录Map (stepId -> record)
|
||||||
|
* @param parentId 父步骤ID
|
||||||
|
* @return 树形步骤执行记录列表
|
||||||
|
*/
|
||||||
|
private List<ArStepRecordTreeVo> buildStepRecordTree(
|
||||||
|
List<ArStepVo> allSteps,
|
||||||
|
Map<Long, ArStepRecordVo> recordMap,
|
||||||
|
Long parentId) {
|
||||||
|
|
||||||
|
List<ArStepRecordTreeVo> tree = new ArrayList<>();
|
||||||
|
for (ArStepVo step : allSteps) {
|
||||||
|
if (step.getParentId().equals(parentId)) {
|
||||||
|
ArStepRecordTreeVo treeNode = new ArStepRecordTreeVo();
|
||||||
|
|
||||||
|
// 复制步骤模板信息
|
||||||
|
BeanUtils.copyProperties(step, treeNode);
|
||||||
|
|
||||||
|
// 合并执行记录信息
|
||||||
|
ArStepRecordVo record = recordMap.get(step.getId());
|
||||||
|
if (record != null) {
|
||||||
|
treeNode.setRecordId(record.getId());
|
||||||
|
treeNode.setRecordStatus(record.getStatus());
|
||||||
|
treeNode.setIsDone(record.getIsDone());
|
||||||
|
treeNode.setStartTime(record.getStartTime());
|
||||||
|
treeNode.setCompletionTime(record.getCompletionTime());
|
||||||
|
treeNode.setDuration(record.getDuration());
|
||||||
|
treeNode.setTextFeedback(record.getTextFeedback());
|
||||||
|
treeNode.setVoiceText(record.getVoiceText());
|
||||||
|
treeNode.setAiResult(record.getAiResult());
|
||||||
|
treeNode.setExecutorId(record.getExecutorId());
|
||||||
|
treeNode.setExecutorName(record.getExecutorName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归查找子节点
|
||||||
|
List<ArStepRecordTreeVo> children = buildStepRecordTree(allSteps, recordMap, step.getId());
|
||||||
|
if (!children.isEmpty()) {
|
||||||
|
treeNode.setChildren(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
tree.add(treeNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public Boolean submitExecution(ArExecutionSubmitBo bo) {
|
||||||
|
// 1. 校验执行记录是否存在
|
||||||
|
ArExecution execution = baseMapper.selectById(bo.getId());
|
||||||
|
if (execution == null) {
|
||||||
|
throw new ServiceException("任务执行记录不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 收集所有需要更新的步骤记录
|
||||||
|
List<ArStepRecord> recordsToUpdate = new ArrayList<>();
|
||||||
|
if (bo.getStepTree() != null && !bo.getStepTree().isEmpty()) {
|
||||||
|
collectRecordsToUpdate(bo.getStepTree(), bo.getId(), recordsToUpdate);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 批量更新步骤记录
|
||||||
|
if (!recordsToUpdate.isEmpty()) {
|
||||||
|
boolean updateSuccess = stepRecordMapper.updateBatchById(recordsToUpdate);
|
||||||
|
if (!updateSuccess) {
|
||||||
|
throw new ServiceException("步骤记录更新失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. 计算总步骤数和已完成步骤数
|
||||||
|
StepCountResult countResult = countSteps(bo.getStepTree());
|
||||||
|
|
||||||
|
// 5. 更新执行记录
|
||||||
|
ArExecution updateExecution = new ArExecution();
|
||||||
|
updateExecution.setId(bo.getId());
|
||||||
|
|
||||||
|
// 设置状态
|
||||||
|
if (StringUtils.isNotBlank(bo.getStatus())) {
|
||||||
|
updateExecution.setStatus(bo.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置时间
|
||||||
|
if (bo.getStartTime() != null) {
|
||||||
|
updateExecution.setStartTime(bo.getStartTime());
|
||||||
|
}
|
||||||
|
if (bo.getEndTime() != null) {
|
||||||
|
updateExecution.setEndTime(bo.getEndTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动设置开始时间
|
||||||
|
if ("in_progress".equals(updateExecution.getStatus()) && execution.getStartTime() == null) {
|
||||||
|
updateExecution.setStartTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自动设置结束时间
|
||||||
|
if (("completed".equals(updateExecution.getStatus()) || "cancelled".equals(updateExecution.getStatus()))
|
||||||
|
&& execution.getEndTime() == null) {
|
||||||
|
updateExecution.setEndTime(new Date());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置步骤统计
|
||||||
|
updateExecution.setTotalSteps(countResult.getTotal());
|
||||||
|
updateExecution.setCompletedSteps(countResult.getCompleted());
|
||||||
|
|
||||||
|
return baseMapper.updateById(updateExecution) > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归收集所有需要更新的步骤记录
|
||||||
|
*
|
||||||
|
* @param stepTree 步骤树
|
||||||
|
* @param executionId 执行ID
|
||||||
|
* @param result 结果列表
|
||||||
|
*/
|
||||||
|
private void collectRecordsToUpdate(List<ArStepRecordTreeBo> stepTree, Long executionId, List<ArStepRecord> result) {
|
||||||
|
if (stepTree == null || stepTree.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ArStepRecordTreeBo stepBo : stepTree) {
|
||||||
|
// 只更新有 recordId 的记录
|
||||||
|
if (stepBo.getRecordId() != null) {
|
||||||
|
ArStepRecord record = new ArStepRecord();
|
||||||
|
record.setId(stepBo.getRecordId());
|
||||||
|
record.setExecutionId(executionId);
|
||||||
|
record.setStepId(stepBo.getId());
|
||||||
|
record.setStatus(stepBo.getRecordStatus());
|
||||||
|
record.setIsDone(stepBo.getIsDone());
|
||||||
|
record.setStartTime(stepBo.getStartTime());
|
||||||
|
record.setCompletionTime(stepBo.getCompletionTime());
|
||||||
|
record.setTextFeedback(stepBo.getTextFeedback());
|
||||||
|
record.setVoiceText(stepBo.getVoiceText());
|
||||||
|
record.setAiResult(stepBo.getAiResult());
|
||||||
|
record.setExecutorId(stepBo.getExecutorId());
|
||||||
|
record.setExecutorName(stepBo.getExecutorName());
|
||||||
|
|
||||||
|
// 自动计算耗时
|
||||||
|
if (stepBo.getStartTime() != null && stepBo.getCompletionTime() != null) {
|
||||||
|
long durationMillis = stepBo.getCompletionTime().getTime() - stepBo.getStartTime().getTime();
|
||||||
|
record.setDuration((int) (durationMillis / 1000));
|
||||||
|
} else if (stepBo.getDuration() != null) {
|
||||||
|
record.setDuration(stepBo.getDuration());
|
||||||
|
}
|
||||||
|
|
||||||
|
result.add(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归处理子步骤
|
||||||
|
if (stepBo.getChildren() != null && !stepBo.getChildren().isEmpty()) {
|
||||||
|
collectRecordsToUpdate(stepBo.getChildren(), executionId, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 递归统计步骤数
|
||||||
|
*
|
||||||
|
* @param stepTree 步骤树
|
||||||
|
* @return 统计结果
|
||||||
|
*/
|
||||||
|
private StepCountResult countSteps(List<ArStepRecordTreeBo> stepTree) {
|
||||||
|
int totalCount = 0;
|
||||||
|
int completedCount = 0;
|
||||||
|
|
||||||
|
if (stepTree == null || stepTree.isEmpty()) {
|
||||||
|
return new StepCountResult(totalCount, completedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ArStepRecordTreeBo stepBo : stepTree) {
|
||||||
|
// 只统计有 recordId 的步骤
|
||||||
|
if (stepBo.getRecordId() != null) {
|
||||||
|
totalCount++;
|
||||||
|
if ("1".equals(stepBo.getIsDone()) || "completed".equals(stepBo.getRecordStatus())) {
|
||||||
|
completedCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 递归统计子步骤
|
||||||
|
if (stepBo.getChildren() != null && !stepBo.getChildren().isEmpty()) {
|
||||||
|
StepCountResult childCounts = countSteps(stepBo.getChildren());
|
||||||
|
totalCount += childCounts.getTotal();
|
||||||
|
completedCount += childCounts.getCompleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StepCountResult(totalCount, completedCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 步骤统计结果内部类
|
||||||
|
*/
|
||||||
|
@lombok.Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
private static class StepCountResult {
|
||||||
|
private int total;
|
||||||
|
private int completed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
366
script/sql/DATABASE-INSTALL-GUIDE.md
Normal file
366
script/sql/DATABASE-INSTALL-GUIDE.md
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
# AR智能巡检平台 - 数据库安装指南
|
||||||
|
|
||||||
|
## 文件说明
|
||||||
|
|
||||||
|
本目录包含以下 SQL 文件:
|
||||||
|
|
||||||
|
### 数据库表结构文件
|
||||||
|
- **ar-inspection-tables.sql** - AR巡检模块数据库表结构(8个业务表)
|
||||||
|
- **ar-inspection-tables-rollback.sql** - 数据库表回滚脚本(删除所有巡检表)
|
||||||
|
|
||||||
|
### 菜单权限文件
|
||||||
|
- **ar-inspection-menu.sql** - 菜单和权限初始化SQL(49条权限配置)
|
||||||
|
- **ar-inspection-menu-rollback.sql** - 菜单权限回滚SQL
|
||||||
|
|
||||||
|
## 数据库表清单
|
||||||
|
|
||||||
|
| 序号 | 表名 | 说明 | 用途 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| 1 | ar_device | AR设备管理表 | 管理AR眼镜等设备信息 |
|
||||||
|
| 2 | ar_region | 巡检区域管理表 | 管理巡检区域划分 |
|
||||||
|
| 3 | ar_point | 巡检点位管理表 | 管理具体巡检点位 |
|
||||||
|
| 4 | ar_task | 巡检任务模板表 | 定义巡检任务模板 |
|
||||||
|
| 5 | ar_step | 巡检步骤表 | 定义任务的执行步骤(支持树形结构) |
|
||||||
|
| 6 | ar_step_media | 步骤媒体文件表 | 存储步骤相关的图片/视频/音频 |
|
||||||
|
| 7 | ar_execution | 任务执行记录表 | 记录任务的执行情况 |
|
||||||
|
| 8 | ar_step_record | 步骤执行记录表 | 记录每个步骤的执行详情 |
|
||||||
|
|
||||||
|
## 表关系图
|
||||||
|
|
||||||
|
```
|
||||||
|
ar_device (设备)
|
||||||
|
└─> ar_execution (执行记录)
|
||||||
|
|
||||||
|
ar_region (区域)
|
||||||
|
├─> ar_point (点位)
|
||||||
|
├─> ar_task (任务模板)
|
||||||
|
└─> ar_execution (执行记录)
|
||||||
|
|
||||||
|
ar_point (点位)
|
||||||
|
└─> ar_step (巡检步骤)
|
||||||
|
|
||||||
|
ar_task (任务模板)
|
||||||
|
├─> ar_step (巡检步骤)
|
||||||
|
└─> ar_execution (执行记录)
|
||||||
|
|
||||||
|
ar_step (巡检步骤)
|
||||||
|
├─> ar_step (父子关系-树形结构)
|
||||||
|
└─> ar_step_record (步骤记录)
|
||||||
|
|
||||||
|
ar_execution (执行记录)
|
||||||
|
└─> ar_step_record (步骤记录)
|
||||||
|
|
||||||
|
ar_step_record (步骤记录)
|
||||||
|
└─> ar_step_media (步骤媒体)
|
||||||
|
```
|
||||||
|
|
||||||
|
## 安装步骤
|
||||||
|
|
||||||
|
### 第一步: 创建数据库表
|
||||||
|
|
||||||
|
根据你的环境选择以下任一方式执行:
|
||||||
|
|
||||||
|
#### 方式1: 命令行导入
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 进入MySQL
|
||||||
|
mysql -u root -p
|
||||||
|
|
||||||
|
# 选择数据库(请根据实际情况修改数据库名)
|
||||||
|
use ry-vue;
|
||||||
|
|
||||||
|
# 导入表结构
|
||||||
|
source /path/to/ar-inspection/script/sql/ar-inspection-tables.sql;
|
||||||
|
|
||||||
|
# 验证表是否创建成功
|
||||||
|
show tables like 'ar_%';
|
||||||
|
|
||||||
|
# 查看表结构(以ar_device为例)
|
||||||
|
desc ar_device;
|
||||||
|
|
||||||
|
# 退出MySQL
|
||||||
|
exit;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 方式2: 直接执行命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 一条命令完成导入
|
||||||
|
mysql -u root -p -D ry-vue < /path/to/ar-inspection/script/sql/ar-inspection-tables.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 方式3: 使用 Navicat/DBeaver/DataGrip 等 GUI 工具
|
||||||
|
|
||||||
|
1. 打开工具并连接到数据库
|
||||||
|
2. 选择数据库 `ry-vue`
|
||||||
|
3. 打开 SQL 文件: `ar-inspection-tables.sql`
|
||||||
|
4. 点击"运行"或"执行"按钮
|
||||||
|
5. 验证表是否创建成功
|
||||||
|
|
||||||
|
### 第二步: 导入菜单权限数据
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 方式1: 命令行
|
||||||
|
mysql -u root -p -D ry-vue < /path/to/ar-inspection/script/sql/ar-inspection-menu.sql
|
||||||
|
|
||||||
|
# 方式2: MySQL客户端
|
||||||
|
mysql -u root -p
|
||||||
|
use ry-vue;
|
||||||
|
source /path/to/ar-inspection/script/sql/ar-inspection-menu.sql;
|
||||||
|
|
||||||
|
# 验证菜单是否导入成功
|
||||||
|
SELECT menu_id, menu_name, parent_id, menu_type, perms
|
||||||
|
FROM sys_menu
|
||||||
|
WHERE menu_id >= 2000 AND menu_id < 2200
|
||||||
|
ORDER BY menu_id;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 第三步: 分配权限给角色
|
||||||
|
|
||||||
|
1. 登录系统管理后台 (http://localhost:8080 或你的实际地址)
|
||||||
|
2. 进入 **系统管理 > 角色管理**
|
||||||
|
3. 选择需要授权的角色(如"管理员"),点击"修改"
|
||||||
|
4. 在菜单权限中勾选 **"AR巡检"** 及其子菜单
|
||||||
|
5. 点击"确定"保存设置
|
||||||
|
|
||||||
|
### 第四步: 验证安装
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 验证所有表是否创建成功
|
||||||
|
mysql -u root -p -D ry-vue -e "SHOW TABLES LIKE 'ar_%';"
|
||||||
|
|
||||||
|
# 验证菜单权限是否导入成功
|
||||||
|
mysql -u root -p -D ry-vue -e "SELECT COUNT(*) as menu_count FROM sys_menu WHERE menu_id >= 2000 AND menu_id < 2200;"
|
||||||
|
# 应该返回 49 条记录
|
||||||
|
|
||||||
|
# 验证表结构(查看ar_device表为例)
|
||||||
|
mysql -u root -p -D ry-vue -e "DESC ar_device;"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 回滚操作
|
||||||
|
|
||||||
|
如果需要删除所有巡检模块的表和菜单权限,按以下顺序执行:
|
||||||
|
|
||||||
|
### 删除菜单权限
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mysql -u root -p -D ry-vue < /path/to/ar-inspection/script/sql/ar-inspection-menu-rollback.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### 删除数据库表
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mysql -u root -p -D ry-vue < /path/to/ar-inspection/script/sql/ar-inspection-tables-rollback.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
**警告**: 回滚操作会永久删除所有表及其数据,请在执行前确保已备份重要数据!
|
||||||
|
|
||||||
|
## 技术特性
|
||||||
|
|
||||||
|
### 1. 多租户支持
|
||||||
|
- 所有表包含 `tenant_id` 字段
|
||||||
|
- 默认租户ID为 `000000`
|
||||||
|
- 支持数据隔离,不同租户数据互不干扰
|
||||||
|
|
||||||
|
### 2. 逻辑删除
|
||||||
|
- 所有表包含 `del_flag` 字段
|
||||||
|
- `0` = 存在, `1` = 已删除
|
||||||
|
- 删除操作不会物理删除数据,仅标记为已删除
|
||||||
|
|
||||||
|
### 3. 审计字段
|
||||||
|
所有表包含以下审计字段:
|
||||||
|
- `create_dept` - 创建部门
|
||||||
|
- `create_by` - 创建者
|
||||||
|
- `create_time` - 创建时间
|
||||||
|
- `update_by` - 更新者
|
||||||
|
- `update_time` - 更新时间
|
||||||
|
|
||||||
|
### 4. 主键策略
|
||||||
|
- 使用雪花ID算法(ASSIGN_ID)
|
||||||
|
- 由应用程序生成,不使用数据库自增
|
||||||
|
- 64位长整型,分布式友好
|
||||||
|
|
||||||
|
### 5. JSON字段支持
|
||||||
|
以下表包含JSON格式字段:
|
||||||
|
- `ar_region.region_data` - 区域业务数据
|
||||||
|
- `ar_point.position_data` - 点位坐标等数据
|
||||||
|
- `ar_step.ai_data` - AI配置数据
|
||||||
|
- `ar_step_record.ai_result` - AI识别结果
|
||||||
|
|
||||||
|
JSON字段由 MyBatis-Plus 的 `JacksonTypeHandler` 自动处理。
|
||||||
|
|
||||||
|
### 6. 树形结构支持
|
||||||
|
`ar_step` 表支持树形结构:
|
||||||
|
- `parent_id` - 父步骤ID(0为顶级)
|
||||||
|
- `ancestors` - 祖级列表(如: 0,1,2)
|
||||||
|
- `is_leaf` - 是否叶子节点
|
||||||
|
|
||||||
|
### 7. 索引优化
|
||||||
|
已根据常见查询场景配置索引:
|
||||||
|
- 主键索引 (PRIMARY KEY)
|
||||||
|
- 唯一索引 (UNIQUE KEY) - 防止重复数据
|
||||||
|
- 普通索引 (KEY) - 加速查询
|
||||||
|
|
||||||
|
## 数据字典
|
||||||
|
|
||||||
|
### 设备状态 (ar_device.status)
|
||||||
|
- `0` - 启用
|
||||||
|
- `1` - 停用
|
||||||
|
|
||||||
|
### 区域状态 (ar_region.status)
|
||||||
|
- `0` - 正常
|
||||||
|
- `1` - 停用
|
||||||
|
|
||||||
|
### 任务状态 (ar_task.status)
|
||||||
|
- `0` - 正常
|
||||||
|
- `1` - 停用
|
||||||
|
|
||||||
|
### 执行状态 (ar_execution.status)
|
||||||
|
- `pending` - 待执行
|
||||||
|
- `in_progress` - 执行中
|
||||||
|
- `completed` - 已完成
|
||||||
|
- `cancelled` - 已取消
|
||||||
|
|
||||||
|
### 步骤记录状态 (ar_step_record.status)
|
||||||
|
- `pending` - 待执行
|
||||||
|
- `completed` - 已完成
|
||||||
|
- `skipped` - 已跳过
|
||||||
|
|
||||||
|
### 媒体类型 (ar_step_media.media_type)
|
||||||
|
- `image` - 图片
|
||||||
|
- `video` - 视频
|
||||||
|
- `audio` - 音频
|
||||||
|
|
||||||
|
### Yes/No 标志
|
||||||
|
- `0` - 否/No
|
||||||
|
- `1` - 是/Yes
|
||||||
|
|
||||||
|
适用于以下字段:
|
||||||
|
- `need_voice_read` - 需要语音朗读
|
||||||
|
- `need_voice_rephrase` - 需要用户复述
|
||||||
|
- `need_voice_confirm` - 需要确认
|
||||||
|
- `need_ai` - 需要AI识别
|
||||||
|
- `is_operation` - 是否操作步骤
|
||||||
|
- `is_leaf` - 是否叶子节点
|
||||||
|
- `is_done` - 是否完成
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
### 1. 数据库版本要求
|
||||||
|
- **MySQL 8.0+** (推荐 8.0.28 或更高版本)
|
||||||
|
- 字符集: `utf8mb4`
|
||||||
|
- 排序规则: `utf8mb4_unicode_ci`
|
||||||
|
|
||||||
|
### 2. 执行顺序
|
||||||
|
必须按以下顺序执行:
|
||||||
|
1. 先创建表结构 (`ar-inspection-tables.sql`)
|
||||||
|
2. 再导入菜单权限 (`ar-inspection-menu.sql`)
|
||||||
|
|
||||||
|
回滚时按相反顺序:
|
||||||
|
1. 先删除菜单权限 (`ar-inspection-menu-rollback.sql`)
|
||||||
|
2. 再删除表结构 (`ar-inspection-tables-rollback.sql`)
|
||||||
|
|
||||||
|
### 3. 数据库名称
|
||||||
|
默认数据库名为 `ry-vue`,如果你的数据库名称不同,请在执行前修改:
|
||||||
|
```bash
|
||||||
|
# 使用你的实际数据库名
|
||||||
|
use your_database_name;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 权限要求
|
||||||
|
执行SQL的数据库用户需要以下权限:
|
||||||
|
- CREATE - 创建表
|
||||||
|
- DROP - 删除表
|
||||||
|
- INSERT - 插入数据(菜单权限)
|
||||||
|
- ALTER - 修改表结构
|
||||||
|
|
||||||
|
### 5. 备份建议
|
||||||
|
在生产环境执行前,强烈建议:
|
||||||
|
1. 完整备份现有数据库
|
||||||
|
2. 先在测试环境验证
|
||||||
|
3. 选择低峰期执行
|
||||||
|
|
||||||
|
备份命令:
|
||||||
|
```bash
|
||||||
|
# 备份整个数据库
|
||||||
|
mysqldump -u root -p ry-vue > backup_$(date +%Y%m%d_%H%M%S).sql
|
||||||
|
|
||||||
|
# 仅备份巡检模块表
|
||||||
|
mysqldump -u root -p ry-vue ar_device ar_region ar_point ar_task ar_step ar_step_media ar_execution ar_step_record > ar_inspection_backup_$(date +%Y%m%d_%H%M%S).sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 索引维护
|
||||||
|
大数据量情况下建议定期优化索引:
|
||||||
|
```sql
|
||||||
|
-- 分析表
|
||||||
|
ANALYZE TABLE ar_device, ar_region, ar_point, ar_task, ar_step, ar_step_media, ar_execution, ar_step_record;
|
||||||
|
|
||||||
|
-- 优化表
|
||||||
|
OPTIMIZE TABLE ar_device, ar_region, ar_point, ar_task, ar_step, ar_step_media, ar_execution, ar_step_record;
|
||||||
|
```
|
||||||
|
|
||||||
|
## 示例数据
|
||||||
|
|
||||||
|
SQL文件中已包含示例数据(默认注释),如需使用可取消注释:
|
||||||
|
|
||||||
|
```sql
|
||||||
|
-- 设备示例数据
|
||||||
|
INSERT INTO ar_device VALUES(1, '000000', 'AR眼镜-001', 'DEV001', 'HoloLens 2', '0', 'AR智能眼镜设备', '0', 103, 1, sysdate(), null, null);
|
||||||
|
|
||||||
|
-- 区域示例数据
|
||||||
|
INSERT INTO ar_region VALUES(1, '000000', '主控室', 'REGION001', null, '0', '电厂主控室区域', '0', 103, 1, sysdate(), null, null);
|
||||||
|
|
||||||
|
-- 点位示例数据
|
||||||
|
INSERT INTO ar_point VALUES(1, '000000', 1, '主控台', 'POINT001', null, '主控台点位', '0', 103, 1, sysdate(), null, null);
|
||||||
|
|
||||||
|
-- 任务模板示例数据
|
||||||
|
INSERT INTO ar_task VALUES(1, '000000', '日常巡检任务', 'TASK001', 1, 'daily', '0', '每日例行巡检任务', '0', 103, 1, sysdate(), null, null);
|
||||||
|
```
|
||||||
|
|
||||||
|
## 故障排查
|
||||||
|
|
||||||
|
### 问题1: 表已存在错误
|
||||||
|
```
|
||||||
|
ERROR 1050 (42S01): Table 'ar_device' already exists
|
||||||
|
```
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
1. 先执行回滚脚本删除旧表
|
||||||
|
2. 或手动删除冲突的表
|
||||||
|
3. 再重新执行创建脚本
|
||||||
|
|
||||||
|
### 问题2: 权限不足错误
|
||||||
|
```
|
||||||
|
ERROR 1142 (42000): CREATE command denied to user
|
||||||
|
```
|
||||||
|
|
||||||
|
**解决方案**: 使用具有足够权限的用户(如root)执行,或联系数据库管理员授予权限。
|
||||||
|
|
||||||
|
### 问题3: 菜单ID冲突
|
||||||
|
```
|
||||||
|
ERROR 1062 (23000): Duplicate entry '2000' for key 'PRIMARY'
|
||||||
|
```
|
||||||
|
|
||||||
|
**解决方案**:
|
||||||
|
1. 先执行菜单回滚脚本
|
||||||
|
2. 或手动删除冲突的菜单
|
||||||
|
3. 再重新执行菜单导入脚本
|
||||||
|
|
||||||
|
### 问题4: 字符集不匹配
|
||||||
|
```
|
||||||
|
ERROR 1115 (42000): Unknown character set: 'utf8mb4'
|
||||||
|
```
|
||||||
|
|
||||||
|
**解决方案**: 升级MySQL到5.5.3或更高版本,或修改SQL文件中的字符集为utf8。
|
||||||
|
|
||||||
|
## 技术支持
|
||||||
|
|
||||||
|
如有问题,请通过以下方式获取帮助:
|
||||||
|
|
||||||
|
1. 查看项目文档: `CLAUDE.md` 和 `AR-INSPECTION-SETUP.md`
|
||||||
|
2. 提交 Issue 到项目仓库
|
||||||
|
3. 联系开发团队
|
||||||
|
|
||||||
|
## 更新日志
|
||||||
|
|
||||||
|
- **2025-01-13**: 初始版本,创建8个业务表和49条权限配置
|
||||||
43
script/sql/ar-inspection-tables-rollback.sql
Normal file
43
script/sql/ar-inspection-tables-rollback.sql
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- AR智能巡检平台 - 数据库表回滚SQL
|
||||||
|
-- 用于删除所有巡检模块相关表
|
||||||
|
-- 创建日期: 2025-01-13
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 删除所有AR巡检模块表
|
||||||
|
-- 注意: 此操作会永久删除表及其数据,请谨慎执行!
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `ar_step_media`;
|
||||||
|
DROP TABLE IF EXISTS `ar_step_record`;
|
||||||
|
DROP TABLE IF EXISTS `ar_execution`;
|
||||||
|
DROP TABLE IF EXISTS `ar_step`;
|
||||||
|
DROP TABLE IF EXISTS `ar_task`;
|
||||||
|
DROP TABLE IF EXISTS `ar_point`;
|
||||||
|
DROP TABLE IF EXISTS `ar_region`;
|
||||||
|
DROP TABLE IF EXISTS `ar_device`;
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 回滚完成
|
||||||
|
-- ----------------------------
|
||||||
|
-- 已删除以下8个表:
|
||||||
|
-- 1. ar_device - AR设备管理表
|
||||||
|
-- 2. ar_region - 巡检区域管理表
|
||||||
|
-- 3. ar_point - 巡检点位管理表
|
||||||
|
-- 4. ar_task - 巡检任务模板表
|
||||||
|
-- 5. ar_step - 巡检步骤表
|
||||||
|
-- 6. ar_step_media - 步骤媒体文件表
|
||||||
|
-- 7. ar_execution - 任务执行记录表
|
||||||
|
-- 8. ar_step_record - 步骤执行记录表
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
|
-- 执行方式:
|
||||||
|
-- mysql -u root -p -D ry-vue < /path/to/ar-inspection-tables-rollback.sql
|
||||||
|
-- 或
|
||||||
|
-- mysql> use ry-vue;
|
||||||
|
-- mysql> source /path/to/ar-inspection-tables-rollback.sql;
|
||||||
334
script/sql/ar-inspection-tables.sql
Normal file
334
script/sql/ar-inspection-tables.sql
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
-- ----------------------------
|
||||||
|
-- AR智能巡检平台 - 数据库表结构SQL
|
||||||
|
-- 适用于 MySQL 8.0+
|
||||||
|
-- 创建日期: 2025-01-13
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
|
-- 设置字符集和排序规则
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
SET FOREIGN_KEY_CHECKS = 0;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 表1: AR设备管理表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ar_device`;
|
||||||
|
CREATE TABLE `ar_device` (
|
||||||
|
`id` bigint(20) NOT NULL COMMENT '设备ID',
|
||||||
|
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
|
||||||
|
`device_name` varchar(100) NOT NULL COMMENT '设备名称',
|
||||||
|
`device_no` varchar(50) NOT NULL COMMENT '设备编号',
|
||||||
|
`device_model` varchar(100) DEFAULT NULL COMMENT '设备型号',
|
||||||
|
`status` char(1) DEFAULT '0' COMMENT '状态(0启用 1停用)',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
|
||||||
|
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||||
|
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_device_no` (`device_no`, `tenant_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_status` (`status`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='AR设备管理表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 表2: 巡检区域管理表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ar_region`;
|
||||||
|
CREATE TABLE `ar_region` (
|
||||||
|
`id` bigint(20) NOT NULL COMMENT '区域ID',
|
||||||
|
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
|
||||||
|
`region_name` varchar(100) NOT NULL COMMENT '区域名称',
|
||||||
|
`region_code` varchar(50) NOT NULL COMMENT '区域编码',
|
||||||
|
`region_data` text DEFAULT NULL COMMENT '区域业务数据(JSON格式,预留)',
|
||||||
|
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
|
||||||
|
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||||
|
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_region_code` (`region_code`, `tenant_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_status` (`status`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检区域管理表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 表3: 巡检点位管理表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ar_point`;
|
||||||
|
CREATE TABLE `ar_point` (
|
||||||
|
`id` bigint(20) NOT NULL COMMENT '点位ID',
|
||||||
|
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
|
||||||
|
`region_id` bigint(20) NOT NULL COMMENT '所属区域ID',
|
||||||
|
`point_name` varchar(100) NOT NULL COMMENT '点位名称',
|
||||||
|
`point_code` varchar(50) NOT NULL COMMENT '点位编码',
|
||||||
|
`position_data` text DEFAULT NULL COMMENT '点位业务数据(JSON格式,包含坐标、预设等)',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
|
||||||
|
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||||
|
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_point_code` (`point_code`, `tenant_id`),
|
||||||
|
KEY `idx_region_id` (`region_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检点位管理表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 表4: 巡检任务模板表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ar_task`;
|
||||||
|
CREATE TABLE `ar_task` (
|
||||||
|
`id` bigint(20) NOT NULL COMMENT '任务ID',
|
||||||
|
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
|
||||||
|
`task_name` varchar(100) NOT NULL COMMENT '任务名称',
|
||||||
|
`task_code` varchar(50) NOT NULL COMMENT '任务编码',
|
||||||
|
`region_id` bigint(20) DEFAULT NULL COMMENT '关联区域ID',
|
||||||
|
`task_type` varchar(50) DEFAULT NULL COMMENT '任务类型',
|
||||||
|
`status` char(1) DEFAULT '0' COMMENT '状态(0正常 1停用)',
|
||||||
|
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||||||
|
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
|
||||||
|
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||||
|
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_task_code` (`task_code`, `tenant_id`),
|
||||||
|
KEY `idx_region_id` (`region_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_task_type` (`task_type`),
|
||||||
|
KEY `idx_status` (`status`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检任务模板表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 表5: 巡检步骤表(支持树形结构)
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ar_step`;
|
||||||
|
CREATE TABLE `ar_step` (
|
||||||
|
`id` bigint(20) NOT NULL COMMENT '步骤ID',
|
||||||
|
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
|
||||||
|
`task_id` bigint(20) NOT NULL COMMENT '所属任务ID',
|
||||||
|
`parent_id` bigint(20) DEFAULT 0 COMMENT '父步骤ID(0为顶级)',
|
||||||
|
`ancestors` varchar(500) DEFAULT '' COMMENT '祖级列表',
|
||||||
|
`step_name` varchar(100) NOT NULL COMMENT '步骤名称',
|
||||||
|
`step_content` text DEFAULT NULL COMMENT '步骤内容描述',
|
||||||
|
`content_voice` varchar(500) DEFAULT NULL COMMENT '步骤语音文本',
|
||||||
|
`order_num` int(11) DEFAULT 0 COMMENT '排序号',
|
||||||
|
`point_id` bigint(20) DEFAULT NULL COMMENT '关联点位ID',
|
||||||
|
`need_voice_read` char(1) DEFAULT '0' COMMENT '需要语音朗读(0否 1是)',
|
||||||
|
`need_voice_rephrase` char(1) DEFAULT '0' COMMENT '需要用户复述(0否 1是)',
|
||||||
|
`rephrase_content` text DEFAULT NULL COMMENT '复述提示文本',
|
||||||
|
`rephrase_voice` varchar(500) DEFAULT NULL COMMENT '复述语音文本',
|
||||||
|
`need_voice_confirm` char(1) DEFAULT '0' COMMENT '需要确认(0否 1是)',
|
||||||
|
`confirm_content` text DEFAULT NULL COMMENT '确认提示文本',
|
||||||
|
`confirm_voice` varchar(500) DEFAULT NULL COMMENT '确认语音文本',
|
||||||
|
`confirm_word` varchar(100) DEFAULT NULL COMMENT '确认词',
|
||||||
|
`need_ai` char(1) DEFAULT '0' COMMENT '需要AI识别(0否 1是)',
|
||||||
|
`ai_target_name` varchar(100) DEFAULT NULL COMMENT 'AI目标名称',
|
||||||
|
`ai_data` text DEFAULT NULL COMMENT 'AI配置数据(JSON格式,预留)',
|
||||||
|
`is_operation` char(1) DEFAULT '0' COMMENT '是否操作步骤(0否 1是)',
|
||||||
|
`is_leaf` char(1) DEFAULT '1' COMMENT '是否叶子节点(0否 1是)',
|
||||||
|
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
|
||||||
|
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||||
|
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_task_id` (`task_id`),
|
||||||
|
KEY `idx_parent_id` (`parent_id`),
|
||||||
|
KEY `idx_point_id` (`point_id`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_order_num` (`order_num`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='巡检步骤表(支持树形结构)';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 表6: 步骤媒体文件表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ar_step_media`;
|
||||||
|
CREATE TABLE `ar_step_media` (
|
||||||
|
`id` bigint(20) NOT NULL COMMENT '媒体ID',
|
||||||
|
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
|
||||||
|
`step_record_id` bigint(20) NOT NULL COMMENT '步骤记录ID',
|
||||||
|
`media_type` varchar(50) NOT NULL COMMENT '媒体类型(image/video/audio)',
|
||||||
|
`file_url` varchar(500) NOT NULL COMMENT '文件URL',
|
||||||
|
`file_name` varchar(200) DEFAULT NULL COMMENT '文件名称',
|
||||||
|
`file_size` bigint(20) DEFAULT NULL COMMENT '文件大小(字节)',
|
||||||
|
`upload_time` datetime DEFAULT NULL COMMENT '上传时间',
|
||||||
|
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
|
||||||
|
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||||
|
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_step_record_id` (`step_record_id`),
|
||||||
|
KEY `idx_media_type` (`media_type`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='步骤媒体文件表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 表7: 任务执行记录表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ar_execution`;
|
||||||
|
CREATE TABLE `ar_execution` (
|
||||||
|
`id` bigint(20) NOT NULL COMMENT '执行ID',
|
||||||
|
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
|
||||||
|
`task_id` bigint(20) NOT NULL COMMENT '任务模板ID',
|
||||||
|
`execution_code` varchar(50) NOT NULL COMMENT '执行编号',
|
||||||
|
`region_id` bigint(20) DEFAULT NULL COMMENT '区域ID',
|
||||||
|
`device_id` bigint(20) DEFAULT NULL COMMENT '使用设备ID',
|
||||||
|
`operator_id` bigint(20) DEFAULT NULL COMMENT '操作人ID',
|
||||||
|
`operator_name` varchar(50) DEFAULT NULL COMMENT '操作人姓名',
|
||||||
|
`custodian_id` bigint(20) DEFAULT NULL COMMENT '监护人ID',
|
||||||
|
`custodian_name` varchar(50) DEFAULT NULL COMMENT '监护人姓名',
|
||||||
|
`sender_id` bigint(20) DEFAULT NULL COMMENT '发令人ID',
|
||||||
|
`sender_name` varchar(50) DEFAULT NULL COMMENT '发令人姓名',
|
||||||
|
`recipient_id` bigint(20) DEFAULT NULL COMMENT '收令人ID',
|
||||||
|
`recipient_name` varchar(50) DEFAULT NULL COMMENT '收令人姓名',
|
||||||
|
`commander_id` bigint(20) DEFAULT NULL COMMENT '值长ID',
|
||||||
|
`commander_name` varchar(50) DEFAULT NULL COMMENT '值长姓名',
|
||||||
|
`status` varchar(20) DEFAULT 'pending' COMMENT '状态(pending待执行/in_progress执行中/completed已完成/cancelled已取消)',
|
||||||
|
`start_time` datetime DEFAULT NULL COMMENT '开始时间',
|
||||||
|
`end_time` datetime DEFAULT NULL COMMENT '结束时间',
|
||||||
|
`total_steps` int(11) DEFAULT 0 COMMENT '总步骤数',
|
||||||
|
`completed_steps` int(11) DEFAULT 0 COMMENT '已完成步骤数',
|
||||||
|
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
|
||||||
|
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||||
|
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_execution_code` (`execution_code`, `tenant_id`),
|
||||||
|
KEY `idx_task_id` (`task_id`),
|
||||||
|
KEY `idx_region_id` (`region_id`),
|
||||||
|
KEY `idx_device_id` (`device_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`),
|
||||||
|
KEY `idx_create_time` (`create_time`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='任务执行记录表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 表8: 步骤执行记录表
|
||||||
|
-- ----------------------------
|
||||||
|
DROP TABLE IF EXISTS `ar_step_record`;
|
||||||
|
CREATE TABLE `ar_step_record` (
|
||||||
|
`id` bigint(20) NOT NULL COMMENT '记录ID',
|
||||||
|
`tenant_id` varchar(20) DEFAULT '000000' COMMENT '租户编号',
|
||||||
|
`execution_id` bigint(20) NOT NULL COMMENT '任务执行ID',
|
||||||
|
`step_id` bigint(20) NOT NULL COMMENT '步骤ID',
|
||||||
|
`status` varchar(20) DEFAULT 'pending' COMMENT '状态(pending待执行/completed已完成/skipped已跳过)',
|
||||||
|
`is_done` char(1) DEFAULT '0' COMMENT '是否完成(0否 1是)',
|
||||||
|
`start_time` datetime DEFAULT NULL COMMENT '开始时间',
|
||||||
|
`completion_time` datetime DEFAULT NULL COMMENT '完成时间',
|
||||||
|
`duration` int(11) DEFAULT 0 COMMENT '耗时(秒)',
|
||||||
|
`text_feedback` text DEFAULT NULL COMMENT '文本反馈',
|
||||||
|
`voice_text` text DEFAULT NULL COMMENT '语音识别文本',
|
||||||
|
`ai_result` text DEFAULT NULL COMMENT 'AI识别结果(JSON格式)',
|
||||||
|
`executor_id` bigint(20) DEFAULT NULL COMMENT '执行人ID',
|
||||||
|
`executor_name` varchar(50) DEFAULT NULL COMMENT '执行人姓名',
|
||||||
|
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0存在 1删除)',
|
||||||
|
`create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门',
|
||||||
|
`create_by` bigint(20) DEFAULT NULL COMMENT '创建者',
|
||||||
|
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
|
||||||
|
`update_by` bigint(20) DEFAULT NULL COMMENT '更新者',
|
||||||
|
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_execution_id` (`execution_id`),
|
||||||
|
KEY `idx_step_id` (`step_id`),
|
||||||
|
KEY `idx_status` (`status`),
|
||||||
|
KEY `idx_tenant_id` (`tenant_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='步骤执行记录表';
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 插入示例数据(可选)
|
||||||
|
-- ----------------------------
|
||||||
|
|
||||||
|
-- 示例设备数据
|
||||||
|
-- INSERT INTO ar_device VALUES(1, '000000', 'AR眼镜-001', 'DEV001', 'HoloLens 2', '0', 'AR智能眼镜设备', '0', 103, 1, sysdate(), null, null);
|
||||||
|
-- INSERT INTO ar_device VALUES(2, '000000', 'AR眼镜-002', 'DEV002', 'HoloLens 2', '0', 'AR智能眼镜设备', '0', 103, 1, sysdate(), null, null);
|
||||||
|
|
||||||
|
-- 示例区域数据
|
||||||
|
-- INSERT INTO ar_region VALUES(1, '000000', '主控室', 'REGION001', null, '0', '电厂主控室区域', '0', 103, 1, sysdate(), null, null);
|
||||||
|
-- INSERT INTO ar_region VALUES(2, '000000', '设备间', 'REGION002', null, '0', '设备机房区域', '0', 103, 1, sysdate(), null, null);
|
||||||
|
|
||||||
|
-- 示例点位数据
|
||||||
|
-- INSERT INTO ar_point VALUES(1, '000000', 1, '主控台', 'POINT001', null, '主控台点位', '0', 103, 1, sysdate(), null, null);
|
||||||
|
-- INSERT INTO ar_point VALUES(2, '000000', 1, '监控屏', 'POINT002', null, '监控屏点位', '0', 103, 1, sysdate(), null, null);
|
||||||
|
|
||||||
|
-- 示例任务模板数据
|
||||||
|
-- INSERT INTO ar_task VALUES(1, '000000', '日常巡检任务', 'TASK001', 1, 'daily', '0', '每日例行巡检任务', '0', 103, 1, sysdate(), null, null);
|
||||||
|
-- INSERT INTO ar_task VALUES(2, '000000', '设备检修任务', 'TASK002', 2, 'maintenance', '0', '设备定期检修任务', '0', 103, 1, sysdate(), null, null);
|
||||||
|
|
||||||
|
SET FOREIGN_KEY_CHECKS = 1;
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 说明
|
||||||
|
-- ----------------------------
|
||||||
|
-- 1. 本SQL文件适用于 MySQL 8.0+ 版本
|
||||||
|
-- 2. 所有表均支持多租户功能,通过 tenant_id 字段隔离
|
||||||
|
-- 3. 所有表均支持逻辑删除,通过 del_flag 字段标识
|
||||||
|
-- 4. 主键采用雪花ID算法,由应用程序生成,不使用数据库自增
|
||||||
|
-- 5. 所有表包含标准审计字段: create_dept, create_by, create_time, update_by, update_time
|
||||||
|
-- 6. ar_step 表支持树形结构,通过 parent_id 和 ancestors 字段实现
|
||||||
|
-- 7. JSON字段使用 text 类型存储,由 MyBatis-Plus 的 JacksonTypeHandler 处理
|
||||||
|
-- 8. 索引已根据业务查询场景优化配置
|
||||||
|
-- 9. 字符集使用 utf8mb4,支持emoji等特殊字符
|
||||||
|
-- 10. 排序规则使用 utf8mb4_unicode_ci,确保多语言支持
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 导入说明
|
||||||
|
-- ----------------------------
|
||||||
|
-- 执行方式1: 命令行导入
|
||||||
|
-- mysql -u root -p -D ry-vue < /path/to/ar-inspection-tables.sql
|
||||||
|
--
|
||||||
|
-- 执行方式2: MySQL客户端执行
|
||||||
|
-- mysql> use ry-vue;
|
||||||
|
-- mysql> source /path/to/ar-inspection-tables.sql;
|
||||||
|
--
|
||||||
|
-- 执行方式3: Navicat等GUI工具
|
||||||
|
-- 打开SQL文件后点击"运行"按钮执行
|
||||||
|
--
|
||||||
|
-- 注意事项:
|
||||||
|
-- - 请确保已创建数据库 ry-vue (或根据实际情况修改数据库名)
|
||||||
|
-- - 建议先在测试环境验证后再在生产环境执行
|
||||||
|
-- - 执行前请备份现有数据库
|
||||||
|
-- - 示例数据默认已注释,如需使用请取消注释
|
||||||
|
|
||||||
|
-- ----------------------------
|
||||||
|
-- 表关系说明
|
||||||
|
-- ----------------------------
|
||||||
|
-- ar_device (设备)
|
||||||
|
-- └── ar_execution (执行记录) - 通过 device_id 关联
|
||||||
|
--
|
||||||
|
-- ar_region (区域)
|
||||||
|
-- ├── ar_point (点位) - 通过 region_id 关联
|
||||||
|
-- ├── ar_task (任务模板) - 通过 region_id 关联
|
||||||
|
-- └── ar_execution (执行记录) - 通过 region_id 关联
|
||||||
|
--
|
||||||
|
-- ar_point (点位)
|
||||||
|
-- └── ar_step (巡检步骤) - 通过 point_id 关联
|
||||||
|
--
|
||||||
|
-- ar_task (任务模板)
|
||||||
|
-- ├── ar_step (巡检步骤) - 通过 task_id 关联
|
||||||
|
-- └── ar_execution (执行记录) - 通过 task_id 关联
|
||||||
|
--
|
||||||
|
-- ar_step (巡检步骤)
|
||||||
|
-- ├── ar_step (父子关系) - 通过 parent_id 关联(树形结构)
|
||||||
|
-- └── ar_step_record (步骤记录) - 通过 step_id 关联
|
||||||
|
--
|
||||||
|
-- ar_execution (执行记录)
|
||||||
|
-- └── ar_step_record (步骤记录) - 通过 execution_id 关联
|
||||||
|
--
|
||||||
|
-- ar_step_record (步骤记录)
|
||||||
|
-- └── ar_step_media (步骤媒体) - 通过 step_record_id 关联
|
||||||
|
|
||||||
|
-- 创建完成!
|
||||||
Reference in New Issue
Block a user