ether-docs/02-DESIGN/detail/DETAIL-FRONTEND.md

1434 lines
40 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 前端交互域 - 详细设计
**文档类型**: 详细设计文档
**生成日期**: 2026-05-18
**数据来源**: ether-admin 代码库分析 + REVERSE-AUTH.md + 路由/状态管理/API层源码
---
## 一、功能点清单
| 编号 | 模块 | 功能点 | 页面文件 | 实现状态 |
|------|------|--------|---------|---------|
| FE-001 | 认证 | 用户登录 | auth/Login.vue | 已实现 |
| FE-002 | 布局 | 主框架布局 | Layout.vue | 已实现 |
| FE-003 | 仪表盘 | 数据概览 | Dashboard.vue | 已实现 |
| FE-004 | 系统管理 | 用户管理 | system/Users.vue | 已实现 |
| FE-005 | 系统管理 | 用户详情 | system/UserDetail.vue | 已实现 |
| FE-006 | 系统管理 | 角色管理 | system/Roles.vue | 已实现 |
| FE-007 | 系统管理 | 权限管理 | system/Permissions.vue | 已实现 |
| FE-008 | 系统管理 | 组织架构 | system/Depts.vue | 已实现 |
| FE-009 | 系统管理 | 审计日志 | system/Audit.vue | 已实现 |
| FE-010 | 系统管理 | 系统设置 | system/Settings.vue | 已实现 |
| FE-011 | 项目管理 | 项目列表 | project/List.vue | 已实现 |
| FE-012 | 项目管理 | 项目选择器 | project/components/ProjectSelector.vue | 已实现 |
| FE-013 | 设备管理 | 设备列表 | equipment/EquipmentList.vue | 已实现 |
| FE-014 | 设备管理 | 设备详情 | equipment/EquipmentDetail.vue | 已实现 |
| FE-015 | 设备管理 | 设备健康预测 | equipment/EquipmentHealth.vue | 已实现 |
| FE-016 | 设备管理 | 维保计划 | equipment/MaintenancePlan.vue | 已实现 |
| FE-017 | 设备管理 | 维保工单 | equipment/MaintenanceTask.vue | 已实现 |
| FE-018 | 设备管理 | 巡检管理 | equipment/Inspection.vue | 已实现 |
| FE-019 | 点检管理 | 点检模板 | inspection/TemplateList.vue | 已实现 |
| FE-020 | 维保管理 | 维保计划 | maintenance/PlanList.vue | 已实现 |
| FE-021 | 维保管理 | 维保任务 | maintenance/TaskList.vue | 已实现 |
| FE-022 | 能耗管理 | 计量点管理 | energy/MeterList.vue | 已实现 |
| FE-023 | 能耗管理 | 能耗录入 | energy/ConsumptionRecord.vue | 已实现 |
| FE-024 | 能耗管理 | 能耗统计 | energy/EnergyStatistics.vue | 已实现 |
| FE-025 | 备件管理 | 备件列表 | sparepart/SparePartList.vue | 已实现 |
| FE-026 | 备件管理 | 备件详情 | sparepart/SparePartDetail.vue | 已实现 |
| FE-027 | 备件管理 | 入库/出库 | sparepart/StockOperation.vue | 已实现 |
| FE-028 | 工单管理 | 工单列表 | ops/WorkOrder.vue | 已实现 |
| FE-029 | 空间管理 | 空间抽屉 | space/SpaceDrawer.vue | 已实现 |
| FE-030 | 设备组件 | 照片管理 | equipment/components/PhotoManager.vue | 已实现 |
| FE-031 | 设备组件 | 文档管理 | equipment/components/DocumentManager.vue | 已实现 |
---
## 二、技术架构
### 2.1 技术栈
| 技术 | 版本 | 用途 |
|------|------|------|
| Vue | 3.x | 前端框架Composition API |
| TypeScript | 5.x | 类型安全 |
| Ant Design Vue | 4.x | UI组件库 |
| Pinia | 2.x | 状态管理 |
| Vue Router | 4.x | 路由管理 |
| Vite | 5.x | 构建工具 |
| Axios | 1.x | HTTP客户端 |
| ECharts | 5.x | 图表可视化 |
### 2.2 目录结构
```
ether-admin/src/
├── api/ # API调用层
│ ├── auth.ts # 认证API
│ ├── user.ts # 用户管理API
│ ├── role.ts # 角色管理API
│ ├── permission.ts # 权限管理API
│ ├── dept.ts # 部门管理API
│ ├── audit.ts # 审计日志API
│ ├── system.ts # 系统配置API
│ ├── project.ts # 项目管理API
│ ├── space.ts # 空间管理API
│ ├── equipment.ts # 设备管理API
│ ├── equipment-health.ts # 设备健康API
│ ├── maintenance-plan.ts # 维保计划API
│ ├── maintenance-task.ts # 维保工单API
│ ├── inspection-template.ts # 点检模板API
│ ├── inspection-record.ts # 巡检记录API
│ ├── inspection-item.ts # 巡检项API
│ ├── energy.ts # 能耗管理API
│ ├── sparepart.ts # 备件管理API
│ ├── work-order.ts # 工单管理API
│ ├── maintenance.ts # 维保API
│ └── userManagement.ts # 用户管理API
├── stores/ # Pinia状态管理
│ └── user.ts # 用户状态Store
├── types/ # TypeScript类型定义
│ ├── index.ts # 全局类型
│ ├── project.ts # 项目相关类型
│ ├── space.ts # 空间相关类型
│ └── projectMember.ts # 项目成员类型
├── utils/ # 工具函数
│ └── request.ts # Axios封装
├── router/ # 路由配置
│ └── index.ts # 路由表+守卫
└── views/ # 页面组件
├── auth/ # 认证页面
├── system/ # 系统管理页面
├── project/ # 项目管理页面
├── equipment/ # 设备管理页面
├── inspection/ # 点检管理页面
├── maintenance/ # 维保管理页面
├── energy/ # 能耗管理页面
├── sparepart/ # 备件管理页面
├── ops/ # 运营管理页面
└── space/ # 空间管理页面
```
### 2.3 路由设计
#### 2.3.1 路由表
| 路径 | 路由名 | 组件 | 标题 | 权限要求 |
|------|--------|------|------|---------|
| `/login` | Login | auth/Login.vue | 登录 | 无 |
| `/dashboard` | Dashboard | Dashboard.vue | 仪表盘 | 已登录 |
| `/system/users` | Users | system/Users.vue | 用户管理 | SYS_ADMIN |
| `/system/roles` | Roles | system/Roles.vue | 角色管理 | SYS_ADMIN |
| `/system/permissions` | Permissions | system/Permissions.vue | 权限管理 | SYS_ADMIN |
| `/system/depts` | Depts | system/Depts.vue | 组织架构 | SYS_ADMIN |
| `/system/audit` | Audit | system/Audit.vue | 审计日志 | SYS_ADMIN |
| `/system/settings` | Settings | system/Settings.vue | 系统设置 | SYS_ADMIN |
| `/project/list` | ProjectList | project/List.vue | 项目管理 | 已登录 |
| `/equipment/list` | EquipmentList | equipment/EquipmentList.vue | 设备管理 | 已登录 |
| `/equipment/detail/:id` | EquipmentDetail | equipment/EquipmentDetail.vue | 设备详情 | 已登录 |
| `/equipment/health` | EquipmentHealth | equipment/EquipmentHealth.vue | 设备健康预测 | 已登录 |
| `/equipment/maintenance-plan` | MaintenancePlan | equipment/MaintenancePlan.vue | 维保计划 | 已登录 |
| `/equipment/maintenance-task` | MaintenanceTask | equipment/MaintenanceTask.vue | 维保工单 | 已登录 |
| `/equipment/inspection` | Inspection | equipment/Inspection.vue | 巡检管理 | 已登录 |
| `/inspection/templates` | InspectionTemplates | inspection/TemplateList.vue | 点检模板 | 已登录 |
| `/maintenance/plans` | MaintenancePlans | maintenance/PlanList.vue | 维保计划 | 已登录 |
| `/maintenance/tasks` | MaintenanceTasks | maintenance/TaskList.vue | 维保任务 | 已登录 |
| `/energy/meters` | EnergyMeters | energy/MeterList.vue | 计量点管理 | 已登录 |
| `/energy/consumption` | EnergyConsumption | energy/ConsumptionRecord.vue | 能耗录入 | 已登录 |
| `/energy/statistics` | EnergyStatistics | energy/EnergyStatistics.vue | 能耗统计 | 已登录 |
| `/sparepart/list` | SparePartList | sparepart/SparePartList.vue | 备件管理 | 已登录 |
| `/sparepart/detail/:id` | SparePartDetail | sparepart/SparePartDetail.vue | 备件详情 | 已登录 |
| `/sparepart/stock/in` | SparePartInStock | sparepart/StockOperation.vue | 备件入库 | 已登录 |
| `/sparepart/stock/out` | SparePartOutStock | sparepart/StockOperation.vue | 备件出库 | 已登录 |
#### 2.3.2 路由守卫
```typescript
router.beforeEach((to, _from, next) => {
const userStore = useUserStore()
// 1. 白名单路由直接放行(/login
if (to.path === '/login') return next()
// 2. 未登录跳转登录页
if (!userStore.isLoggedIn()) return next('/login')
// 3. 检查角色权限meta.requiredRoles
const requiredRoles = to.meta?.requiredRoles as string[] | undefined
if (requiredRoles?.length && !userStore.hasAnyRole(requiredRoles)) {
return next({ path: '/', query: { from: to.fullPath } })
}
next()
})
```
#### 2.3.3 懒加载策略
所有路由组件均使用动态导入(`() => import()`Vite自动代码分割
```typescript
component: () => import('@/views/system/Users.vue')
```
#### 2.3.4 权限控制
- **路由级权限**: 通过 `meta.requiredRoles` 声明所需角色,守卫中校验
- **系统管理模块**: 统一要求 `SYS_ADMIN` 角色
- **业务模块**: 仅要求已登录(无特定角色限制)
- **无权限处理**: 重定向到首页,通过 query.from 记录来源路径
---
### 2.4 状态管理
#### 2.4.1 Pinia Store设计
**useUserStore**当前唯一Store
| 状态 | 类型 | 说明 | 持久化 |
|------|------|------|--------|
| token | `ref<string>` | JWT Token | localStorage |
| userInfo | `ref<{username, realName} \| null>` | 用户基本信息 | localStorage |
| roles | `ref<string[]>` | 角色列表 | localStorage |
| 计算属性 | 类型 | 说明 |
|---------|------|------|
| isAdmin | `computed<boolean>` | 是否SYS_ADMIN角色 |
| 方法 | 参数 | 返回值 | 说明 |
|------|------|--------|------|
| hasRole | role: string | boolean | 判断是否拥有指定角色 |
| hasAnyRole | checkRoles: string[] | boolean | 判断是否拥有任一角色 |
| login | data: LoginRequest | Promise<void> | 登录并存储Token/角色/用户信息 |
| logout | -- | Promise<void> | 登出并清除所有状态 |
| isLoggedIn | -- | boolean | 检查登录状态含Token过期校验 |
| initFromStorage | -- | void | 从localStorage恢复状态 |
#### 2.4.2 持久化策略
| 数据 | 存储位置 | Key | 格式 |
|------|---------|-----|------|
| Token | localStorage | `token` | 字符串 |
| 用户信息 | localStorage | `userInfo` | JSON字符串 |
| 角色列表 | localStorage | `roles` | JSON数组字符串 |
**Token过期校验**:
```typescript
isLoggedIn() {
// 1. 检查Token存在性
// 2. 检查JWT三段式格式
// 3. 解析payload.exp检查过期
// 4. 过期则自动logout
}
```
---
### 2.5 API层设计
#### 2.5.1 请求封装request.ts
**Axios实例配置**:
| 配置项 | 值 | 说明 |
|--------|-----|------|
| baseURL | `VITE_API_BASE_URL` | 环境变量配置 |
| timeout | `VITE_REQUEST_TIMEOUT \|\| 10000` | 请求超时 |
**请求拦截器**:
1. 从localStorage获取Token
2. 注入 `Authorization: Bearer {token}` Header
3. 初始化重试计数器 `__retryCount`
**响应拦截器**:
1. **业务错误处理**: 检查 `ApiResponse.code`非200/0/00000视为业务错误
2. **HTTP错误分类处理**:
| 状态码 | 处理方式 |
|--------|---------|
| 400 | message.error("请求参数错误") |
| 401 | 清除Token跳转/login |
| 403 | message.error("没有权限执行此操作") |
| 404 | message.error("请求的资源不存在") |
| 422 | message.error("数据验证失败") |
| 429 | message.error("操作太频繁") |
| 500 | message.error("服务器内部错误") |
| 502/503/504 | message.error("服务暂时不可用") |
3. **网络错误处理**: ERR_NETWORK / ECONNABORTED / ERR_CANCELED
4. **自动重试**: GET请求在5xx/网络错误/超时时自动重试最多2次间隔1秒
#### 2.5.2 错误处理策略
| 错误类型 | 处理方式 | 用户感知 |
|---------|---------|---------|
| 业务错误(ApiResponse.code != 0) | message.error(res.message) | 顶部错误提示 |
| 401未授权 | 清除Token + 跳转登录 | 自动跳转登录页 |
| 403无权限 | message.error | 顶部错误提示 |
| 网络错误 | message.error | 顶部错误提示 |
| 请求超时 | 自动重试1次 + message.error | 顶部错误提示 |
| 请求取消 | 静默处理 | 无感知 |
#### 2.5.3 类型安全
**统一响应类型**:
```typescript
interface ApiResponse<T> {
code: number
message: string
data: T
}
```
**API函数类型约束**: 所有API函数显式指定 `ApiResponse<T>` 泛型参数
```typescript
export const getUsers = (params?) => {
return request.get<ApiResponse<any>>('/api/auth/users', { params })
}
```
#### 2.5.4 分页封装
**分页响应类型**(多版本共存):
```typescript
// 通用版本project.ts定义
interface PageResponse<T> {
content: T[]
totalElements: number
totalPages: number
size: number
number: number
first: boolean
last: boolean
empty: boolean
}
// 工单版本work-order.ts定义
interface PageResponse<T> {
content: T[]
page: number
size: number
totalElements: number
totalPages: number
first: boolean
last: boolean
}
```
**分页请求参数**:
```typescript
params: { page?: number; size?: number; keyword?: string; status?: string }
```
---
## 三、页面设计
### 3.1 登录页
| 属性 | 值 |
|------|-----|
| 页面路径 | `/login` |
| 路由名 | Login |
| 组件 | `views/auth/Login.vue` |
| 权限要求 | 无 |
| 布局 | 独立页面不使用Layout |
**功能描述**: 用户名+密码登录,调用 `POST /api/auth/login`
**核心组件**: Ant Design Vue Form + Input + Button
**数据流**:
1. 用户输入用户名和密码
2. 调用 `userStore.login({username, password})`
3. login内部调用 `auth.ts -> loginApi()`
4. 成功后存储Token/角色/用户信息到localStorage
5. 路由跳转到 `/dashboard`
---
### 3.2 仪表盘
| 属性 | 值 |
|------|-----|
| 页面路径 | `/dashboard` |
| 路由名 | Dashboard |
| 组件 | `views/Dashboard.vue` |
| 权限要求 | 已登录 |
**功能描述**: 系统数据概览,展示关键指标
**核心组件**: Ant Design Vue Card + Statistic + ECharts图表
**数据流**: 汇总各模块统计数据
---
### 3.3 用户管理
| 属性 | 值 |
|------|-----|
| 页面路径 | `/system/users` |
| 路由名 | Users |
| 组件 | `views/system/Users.vue` |
| 权限要求 | SYS_ADMIN |
**功能描述**: 用户列表CRUD、角色分配、项目关联
**核心组件**: Table + Modal + Form + Select
**数据流**:
- 列表: `GET /api/auth/users` -> Table渲染
- 创建: Form提交 -> `POST /api/auth/users`
- 编辑: Form提交 -> `PUT /api/auth/users/{id}`
- 删除: 确认弹窗 -> `DELETE /api/auth/users/{id}`
- 角色分配: 多选Modal -> `POST /api/auth/users/{id}/roles`
- 项目查看: `GET /api/auth/users/{id}/projects`
---
### 3.4 用户详情
| 属性 | 值 |
|------|-----|
| 页面路径 | 从用户管理跳转 |
| 路由名 | UserDetail |
| 组件 | `views/system/UserDetail.vue` |
| 权限要求 | SYS_ADMIN |
**功能描述**: 用户详细信息查看、密码修改
**核心组件**: Descriptions + Form + Modal
**数据流**:
- 详情: `GET /api/auth/users/{id}`
- 修改密码: `PUT /api/auth/users/{id}/password`
---
### 3.5 角色管理
| 属性 | 值 |
|------|-----|
| 页面路径 | `/system/roles` |
| 路由名 | Roles |
| 组件 | `views/system/Roles.vue` |
| 权限要求 | SYS_ADMIN |
**功能描述**: 角色CRUD、权限分配
**核心组件**: Table + Modal + Form + Tree权限树
**数据流**:
- 列表: `GET /api/auth/roles`
- 创建: `POST /api/auth/roles`
- 权限分配: `POST /api/auth/roles/{id}/permissions`
- 角色用户: `GET /api/auth/roles/{id}/users`
---
### 3.6 权限管理
| 属性 | 值 |
|------|-----|
| 页面路径 | `/system/permissions` |
| 路由名 | Permissions |
| 组件 | `views/system/Permissions.vue` |
| 权限要求 | SYS_ADMIN |
**功能描述**: 权限CRUD、按类型筛选
**核心组件**: Table + Modal + Form + Select类型筛选
**数据流**:
- 列表: `GET /api/auth/permissions`
- 创建: `POST /api/auth/permissions`
- 按模块查询: `GET /api/auth/permissions/module/{module}`
---
### 3.7 组织架构
| 属性 | 值 |
|------|-----|
| 页面路径 | `/system/depts` |
| 路由名 | Depts |
| 组件 | `views/system/Depts.vue` |
| 权限要求 | SYS_ADMIN |
**功能描述**: 部门树展示、CRUD、成员查看
**核心组件**: Tree + Modal + Form + Table
**数据流**:
- 部门树: `GET /api/auth/depts/tree`
- 创建: `POST /api/auth/depts`
- 成员: `GET /api/auth/depts/{deptId}/members`
- 按类型: `GET /api/auth/depts/by-type/{deptType}`
---
### 3.8 审计日志
| 属性 | 值 |
|------|-----|
| 页面路径 | `/system/audit` |
| 路由名 | Audit |
| 组件 | `views/system/Audit.vue` |
| 权限要求 | SYS_ADMIN |
**功能描述**: 操作日志查询、统计
**核心组件**: Table + DatePicker + Select模块/操作类型)
**数据流**:
- 日志列表: `GET /api/audit-logs` (分页+筛选)
- 模块列表: `GET /api/audit-logs/modules`
- 操作类型: `GET /api/audit-logs/actions`
- 统计: `GET /api/audit-logs/stats`
---
### 3.9 系统设置
| 属性 | 值 |
|------|-----|
| 页面路径 | `/system/settings` |
| 路由名 | Settings |
| 组件 | `views/system/Settings.vue` |
| 权限要求 | SYS_ADMIN |
**功能描述**: 系统配置键值对管理
**核心组件**: Form + Input + Button
**数据流**:
- 获取配置: `GET /api/config`
- 更新配置: `PUT /api/config`
---
### 3.10 项目管理
| 属性 | 值 |
|------|-----|
| 页面路径 | `/project/list` |
| 路由名 | ProjectList |
| 组件 | `views/project/List.vue` |
| 权限要求 | 已登录 |
**功能描述**: 项目CRUD、状态管理、成员管理、配置管理
**核心组件**: Table + Modal + Form + Tabs
**数据流**:
- 列表: `GET /api/mdm/projects` (分页)
- 创建: `POST /api/mdm/projects`
- 状态变更: `PUT /api/mdm/projects/{id}/status`
- 成员管理: `GET/POST/DELETE /api/auth/projects/{projectId}/members`
- 编码生成: `GET /api/mdm/projects/generate-code`
- 删除检查: `GET /api/mdm/projects/{id}/delete-check`
- 配置: `GET/PUT /api/mdm/projects/{id}/config`
- 选择器: `GET /api/mdm/projects/selector`
---
### 3.11 设备列表
| 属性 | 值 |
|------|-----|
| 页面路径 | `/equipment/list` |
| 路由名 | EquipmentList |
| 组件 | `views/equipment/EquipmentList.vue` |
| 权限要求 | 已登录 |
**功能描述**: 设备CRUD、按项目/类型/归属筛选、导入导出
**核心组件**: Table + Modal + Form + Upload + Select
**数据流**:
- 列表: `GET /api/asset/equipment/by-project/{projectId}`
- 创建: `POST /api/asset/equipment`
- 按类型: `GET /api/asset/equipment/by-type`
- 按归属: `GET /api/asset/equipment/by-ownership`
- 导入: `POST /api/asset/equipment/import`
- 导出: `GET /api/asset/equipment/export`
- 统计: `GET /api/asset/equipment/stats/by-type/{projectId}`
---
### 3.12 设备详情
| 属性 | 值 |
|------|-----|
| 页面路径 | `/equipment/detail/:id` |
| 路由名 | EquipmentDetail |
| 组件 | `views/equipment/EquipmentDetail.vue` |
| 权限要求 | 已登录 |
**功能描述**: 设备完整信息展示、扩展信息编辑、照片/文档管理
**核心组件**: Tabs + Descriptions + Form + PhotoManager + DocumentManager
**数据流**:
- 详情: `GET /api/asset/equipment/{id}`
- 电梯扩展: `GET/PUT /api/asset/equipment/{id}/elevator`
- 暖通扩展: `GET/PUT /api/asset/equipment/{id}/hvac`
- 能源扩展: `GET/PUT /api/asset/equipment/{id}/energy`
- 消防扩展: `GET/PUT /api/asset/equipment/{id}/fire`
---
### 3.13 设备健康预测
| 属性 | 值 |
|------|-----|
| 页面路径 | `/equipment/health` |
| 路由名 | EquipmentHealth |
| 组件 | `views/equipment/EquipmentHealth.vue` |
| 权限要求 | 已登录 |
**功能描述**: 设备健康度评分、故障历史、MTBF/MTTR分析
**核心组件**: Card + ECharts + Table
**数据流**:
- 健康度: `GET /api/asset/equipment-health/{equipmentId}`
- 历史趋势: `GET /api/asset/equipment-health/{id}/history`
- 计算: `POST /api/asset/equipment-health/calculate`
- 故障历史: `GET /api/asset/equipment-health/failure-history/{id}`
- MTBF: `GET /api/asset/equipment-health/mtbf/{id}`
- MTTR: `GET /api/asset/equipment-health/mttr/{id}`
---
### 3.14 维保计划(设备模块)
| 属性 | 值 |
|------|-----|
| 页面路径 | `/equipment/maintenance-plan` |
| 路由名 | MaintenancePlan |
| 组件 | `views/equipment/MaintenancePlan.vue` |
| 权限要求 | 已登录 |
**功能描述**: 维保计划CRUD
**核心组件**: Table + Modal + Form
**数据流**:
- 列表: `GET /api/mdm/maintenance-plans?projectId=`
- 创建: `POST /api/mdm/maintenance-plans`
- 更新: `PUT /api/mdm/maintenance-plans/{id}`
- 删除: `DELETE /api/mdm/maintenance-plans/{id}`
---
### 3.15 维保工单(设备模块)
| 属性 | 值 |
|------|-----|
| 页面路径 | `/equipment/maintenance-task` |
| 路由名 | MaintenanceTask |
| 组件 | `views/equipment/MaintenanceTask.vue` |
| 权限要求 | 已登录 |
**功能描述**: 维保工单管理、状态流转
**核心组件**: Table + Modal + Form + Steps
**数据流**:
- 列表: `GET /api/ops/maintenance-tasks?projectId=`
- 派单: `POST /api/ops/maintenance-tasks/{id}/assign`
- 开始: `POST /api/ops/maintenance-tasks/{id}/start`
- 完成: `POST /api/ops/maintenance-tasks/{id}/complete-details`
- 验收: `POST /api/ops/maintenance-tasks/{id}/verify`
- 取消: `POST /api/ops/maintenance-tasks/{id}/cancel`
- 统计: `GET /api/ops/maintenance-tasks/stats`
---
### 3.16 巡检管理(设备模块)
| 属性 | 值 |
|------|-----|
| 页面路径 | `/equipment/inspection` |
| 路由名 | Inspection |
| 组件 | `views/equipment/Inspection.vue` |
| 权限要求 | 已登录 |
**功能描述**: 巡检记录管理
**核心组件**: Table + Modal + Form
**数据流**:
- 记录列表: `GET /api/mdm/inspection-records?projectId=`
- 创建: `POST /api/mdm/inspection-records`
- 完成: `POST /api/mdm/inspection-records/{id}/complete`
---
### 3.17 点检模板
| 属性 | 值 |
|------|-----|
| 页面路径 | `/inspection/templates` |
| 路由名 | InspectionTemplates |
| 组件 | `views/inspection/TemplateList.vue` |
| 权限要求 | 已登录 |
**功能描述**: 点检模板CRUD、检查项管理
**核心组件**: Table + Modal + Form + DynamicFormItems
**数据流**:
- 列表: `GET /api/ops/inspection-templates?projectId=`
- 创建: `POST /api/ops/inspection-templates`
- 更新: `PUT /api/ops/inspection-templates/{id}`
- 删除: `DELETE /api/ops/inspection-templates/{id}`
---
### 3.18 维保计划(维保模块)
| 属性 | 值 |
|------|-----|
| 页面路径 | `/maintenance/plans` |
| 路由名 | MaintenancePlans |
| 组件 | `views/maintenance/PlanList.vue` |
| 权限要求 | 已登录 |
**功能描述**: 维保计划列表与设备模块维保计划共享API
---
### 3.19 维保任务(维保模块)
| 属性 | 值 |
|------|-----|
| 页面路径 | `/maintenance/tasks` |
| 路由名 | MaintenanceTasks |
| 组件 | `views/maintenance/TaskList.vue` |
| 权限要求 | 已登录 |
**功能描述**: 维保任务列表与设备模块维保工单共享API
---
### 3.20 计量点管理
| 属性 | 值 |
|------|-----|
| 页面路径 | `/energy/meters` |
| 路由名 | EnergyMeters |
| 组件 | `views/energy/MeterList.vue` |
| 权限要求 | 已登录 |
**功能描述**: 能源计量点CRUD
**核心组件**: Table + Modal + Form + Select
**数据流**:
- 列表: `GET /api/ops/energy/meters?projectId=`
- 创建: `POST /api/ops/energy/meters`
- 更新: `PUT /api/ops/energy/meters/{id}`
- 删除: `DELETE /api/ops/energy/meters/{id}`
---
### 3.21 能耗录入
| 属性 | 值 |
|------|-----|
| 页面路径 | `/energy/consumption` |
| 路由名 | EnergyConsumption |
| 组件 | `views/energy/ConsumptionRecord.vue` |
| 权限要求 | 已登录 |
**功能描述**: 能耗数据录入与查看
**核心组件**: Table + Modal + Form + InputNumber
**数据流**:
- 录入: `POST /api/ops/energy/consumption`
- 记录: `GET /api/ops/energy/consumption/{meterId}`
---
### 3.22 能耗统计
| 属性 | 值 |
|------|-----|
| 页面路径 | `/energy/statistics` |
| 路由名 | EnergyStatistics |
| 组件 | `views/energy/EnergyStatistics.vue` |
| 权限要求 | 已登录 |
**功能描述**: 按类型统计、单方能耗
**核心组件**: Card + ECharts + DatePicker
**数据流**:
- 按类型统计: `GET /api/ops/energy/statistics/by-type`
- 单方能耗: `GET /api/ops/energy/statistics/unit-consumption`
---
### 3.23 备件列表
| 属性 | 值 |
|------|-----|
| 页面路径 | `/sparepart/list` |
| 路由名 | SparePartList |
| 组件 | `views/sparepart/SparePartList.vue` |
| 权限要求 | 已登录 |
**功能描述**: 备件CRUD、低库存预警
**核心组件**: Table + Modal + Form + Badge
**数据流**:
- 列表: `GET /api/ops/spare-parts?projectId=`
- 创建: `POST /api/ops/spare-parts`
- 低库存: `GET /api/ops/spare-parts/low-stock`
---
### 3.24 备件详情
| 属性 | 值 |
|------|-----|
| 页面路径 | `/sparepart/detail/:id` |
| 路由名 | SparePartDetail |
| 组件 | `views/sparepart/SparePartDetail.vue` |
| 权限要求 | 已登录 |
**功能描述**: 备件详情、库存记录
**核心组件**: Descriptions + Table
**数据流**:
- 详情: `GET /api/ops/spare-parts/{id}`
- 记录: `GET /api/ops/spare-parts/{id}/records`
---
### 3.25 入库/出库
| 属性 | 值 |
|------|-----|
| 页面路径 | `/sparepart/stock/in``/sparepart/stock/out` |
| 路由名 | SparePartInStock / SparePartOutStock |
| 组件 | `views/sparepart/StockOperation.vue`(共用) |
| 权限要求 | 已登录 |
**功能描述**: 备件入库/出库操作
**核心组件**: Form + InputNumber + Select
**数据流**:
- 入库: `POST /api/ops/spare-parts/in-stock`
- 出库: `POST /api/ops/spare-parts/out-stock`
---
### 3.26 工单管理
| 属性 | 值 |
|------|-----|
| 页面路径 | 通过路由未直接注册,从其他入口跳转 |
| 路由名 | WorkOrder |
| 组件 | `views/ops/WorkOrder.vue` |
| 权限要求 | 已登录 |
**功能描述**: 工单全生命周期管理
**核心组件**: Table + Modal + Form + Steps + Rate
**数据流**:
- 列表: `GET /api/wo/work-orders` (分页+多条件筛选)
- 创建: `POST /api/wo/work-orders`
- 派单: `POST /api/wo/work-orders/{id}/assign`
- 开始: `POST /api/wo/work-orders/{id}/start`
- 完成: `POST /api/wo/work-orders/{id}/complete`
- 验收: `POST /api/wo/work-orders/{id}/verify`
- 挂起: `POST /api/wo/work-orders/{id}/suspend`
- 恢复: `POST /api/wo/work-orders/{id}/resume`
- 退回: `POST /api/wo/work-orders/{id}/return`
- 取消: `POST /api/wo/work-orders/{id}/cancel`
- 统计: `GET /api/wo/work-orders/stats`
- 工单项: `GET/POST /api/wo/work-orders/{id}/items`
---
### 3.27 空间抽屉
| 属性 | 值 |
|------|-----|
| 页面路径 | 作为组件被其他页面引用 |
| 组件 | `views/space/SpaceDrawer.vue` |
| 权限要求 | 已登录 |
**功能描述**: 空间树选择抽屉
**核心组件**: Drawer + Tree
**数据流**:
- 空间树: `GET /api/mdm/space-nodes/project/{projectId}/tree`
---
## 四、组件设计
### 4.1 公共组件
#### 4.1.1 Layout主框架布局
**文件**: `views/Layout.vue`
**功能**: 系统主布局框架,包含侧边栏菜单、顶部导航、内容区域
**核心结构**:
- 左侧侧边栏菜单Ant Design Vue Layout.Sider + Menu
- 顶部Header项目选择器、用户信息、登出按钮
- 中间Contentrouter-view渲染区域
**菜单分组**:
| 菜单组 | 子菜单 |
|--------|--------|
| 仪表盘 | Dashboard |
| 系统管理 | 用户管理、角色管理、权限管理、组织架构、审计日志、系统设置 |
| 项目管理 | 项目列表 |
| 设备管理 | 设备列表、设备健康预测、维保计划、维保工单、巡检管理 |
| 点检管理 | 点检模板 |
| 维保管理 | 维保计划、维保任务 |
| 能耗管理 | 计量点管理、能耗录入、能耗统计 |
| 备件管理 | 备件列表、备件入库、备件出库 |
#### 4.1.2 ProjectSelector项目选择器
**文件**: `views/project/components/ProjectSelector.vue`
**功能**: 全局项目切换组件切换后所有API请求自动携带新项目ID
**核心交互**:
1. 下拉选择项目
2. 切换后设置 `X-Project-ID` Header
3. 刷新当前页面数据
**数据流**:
- 项目列表: `GET /api/mdm/projects/selector`
#### 4.1.3 SpaceDrawer空间选择抽屉
**文件**: `views/space/spaceDrawer.vue`
**功能**: 树形空间选择器,用于设备关联空间、账单关联房产等场景
**核心交互**:
1. 点击触发打开Drawer
2. 加载空间树
3. 点击节点选中
4. 确认后返回选中的SpaceNode
**数据流**:
- 空间树: `GET /api/mdm/space-nodes/project/{projectId}/tree`
---
### 4.2 业务组件
#### 4.2.1 PhotoManager照片管理
**文件**: `views/equipment/components/PhotoManager.vue`
**功能**: 设备照片上传、预览、删除
**核心交互**:
1. 按类型分类(外观、铭牌、安装位置、环境)
2. 上传照片调用uploadFile模拟
3. 预览大图
4. 删除照片
**数据结构**:
```typescript
interface EquipmentPhoto {
type: string // 照片类型
url: string // 照片URL
remark?: string // 备注
}
```
#### 4.2.2 DocumentManager文档管理
**文件**: `views/equipment/components/DocumentManager.vue`
**功能**: 设备电子文档上传、下载、删除
**核心交互**:
1. 按类型分类手册manual、证书certificate、合同contract、其他other
2. 上传文档
3. 下载文档
4. 删除文档
**数据结构**:
```typescript
interface EquipmentDocument {
name: string
url: string
size?: number
type: 'manual' | 'certificate' | 'contract' | 'other'
remark?: string
}
```
---
## 五、类型定义
### 5.1 全局类型types/index.ts
```typescript
// API统一响应
interface ApiResponse<T> {
code: number
message: string
data: T
}
// 分页信息
interface PaginationInfo {
current: number
pageSize: number
total?: number
}
// 登录请求
interface LoginRequest {
username: string
password: string
}
// 登录响应
interface LoginResponse {
token: string
userId: string
username: string
realName: string
roles: string[]
}
// 用户
interface User {
id: string
username: string
realName?: string
phone?: string
email?: string
avatar?: string
status: 'ACTIVE' | 'LOCKED' | 'DISABLED'
lastLoginTime?: string
lastLoginIp?: string
roles?: Role[]
employeeNo?: string
position?: string
staffType?: StaffType
projectId?: string
}
// 角色
interface Role {
id: string
code: string
name: string
description?: string
type?: string
status: 'ACTIVE' | 'DISABLED'
dataScope?: string
permissions?: Permission[]
}
// 权限
interface Permission {
id: string
code: string
name: string
type: string
path?: string
component?: string
icon?: string
resource?: string
method?: string
description?: string
sortOrder?: number
visible?: boolean
}
// 项目
interface Project {
id: string
code: string
name: string
description?: string
address?: string
projectType?: 'RESIDENTIAL' | 'OFFICE' | 'INDUSTRIAL_PARK'
province?: string
city?: string
district?: string
status: 'ACTIVE' | 'DISABLED' | 'PENDING' | 'ARCHIVED'
createdAt?: string
updatedAt?: string
}
```
### 5.2 各模块类型
#### 5.2.1 用户相关类型
```typescript
type UserType = 'ENTERPRISE' | 'PROJECT_STAFF' | 'RESIDENT' | 'CUSTOMER'
type EmployeeCategory = 'ENTERPRISE' | 'MANAGEMENT'
type StaffType = 'SECURITY' | 'CLEANING' | 'GARDEN' | 'MAINTENANCE' | 'CUSTOMER_SERVICE' | 'GENERAL'
type ResidentType = 'OWNER' | 'FAMILY' | 'TENANT'
```
#### 5.2.2 项目相关类型types/project.ts
```typescript
type ProjectStatus = 'ACTIVE' | 'DISABLED' | 'PENDING' | 'ARCHIVED'
type ProjectType = 'RESIDENTIAL' | 'OFFICE' | 'INDUSTRIAL_PARK'
interface ProjectQuery {
keyword?: string
status?: ProjectStatus
page?: number
size?: number
sort?: string
}
interface PageResponse<T> {
content: T[]
totalElements: number
totalPages: number
size: number
number: number
first: boolean
last: boolean
empty: boolean
}
interface ProjectStatistics {
memberCount: number
buildingCount: number
roomCount: number
ownerCount: number
tenantCount: number
activeTaskCount: number
completedTaskCount: number
}
interface ProjectMember {
id: string
projectId: string
userId: string
userName: string
realName?: string
phone?: string
roleInProject: string
joinedAt: string
status: 'ACTIVE' | 'INACTIVE'
}
interface ProjectConfig {
id: string
projectId: string
enableReservation: boolean
enableVisitor: boolean
enableComplaint: boolean
enablePayment: boolean
enableAnnouncement: boolean
enableSurvey: boolean
enableVote: boolean
enableMaintenance: boolean
enableAsset: boolean
customConfig?: string
updatedAt: string
}
interface ProjectDeleteCheckVO {
canDelete: boolean
reason?: string
statistics: ProjectDeleteStatistics
}
```
#### 5.2.3 空间相关类型types/space.ts
```typescript
type SpaceNodeCategory = 'BUILDING' | 'PARKING' | 'FACILITY' | 'AREA'
type SpaceNodeType = 'BUILDING' | 'UNIT' | 'FLOOR' | 'ROOM' | 'SHOP' | 'GARAGE' |
'PARKING_AREA' | 'PARKING_SPACE' | 'EQUIPMENT_ROOM' | 'PROPERTY_OFFICE' |
'SECURITY_ROOM' | 'PUBLIC_AREA' | 'GREEN_AREA' | 'ROAD'
interface SpaceNode {
id: string
projectId: string
code: string
name: string
fullName?: string
nodeCategory: SpaceNodeCategory
nodeType: SpaceNodeType
parentId?: string
treePath?: string
level?: number
buildingArea?: number
usableArea?: number
status?: string
// ...更多字段
}
interface SpaceNodeTree extends SpaceNode {
children: SpaceNodeTree[]
}
```
#### 5.2.4 设备相关类型api/equipment.ts内联
```typescript
type SystemType = 'ELEVATOR' | 'HVAC' | 'FIRE_PROTECTION' | 'PLUMBING' |
'ELECTRICAL' | 'SECURITY' | 'LANDSCAPE' | 'ENERGY_METER'
type EquipmentType = 'ELEVATOR' | 'HVAC' | 'FIRE_PROTECTION' | 'PLUMBING' |
'ELECTRICAL' | 'ENERGY_METER' | 'SECURITY' | 'LANDSCAPE' | 'KITCHEN' | 'OTHER'
type OwnershipType = 'PROJECT' | 'COMPANY' | 'OWNER' | 'RENTAL'
interface Equipment {
id: string
equipmentCode: string
equipmentName: string
projectId: string
equipmentType?: EquipmentType
systemType?: SystemType
ownershipType?: OwnershipType
status?: string
operationStatus?: string
// ...更多字段
photos?: EquipmentPhoto[]
documents?: EquipmentDocument[]
}
```
#### 5.2.5 工单相关类型api/work-order.ts内联
```typescript
type WorkOrderSource = 'OWNER' | 'MAINTENANCE' | 'INSPECTION' | 'FAULT' | 'REGULATORY' | 'MANUAL'
type WorkOrderType = 'REPAIR' | 'INSPECTION' | 'SECURITY' | 'CLEANING' | 'PROPERTY' | 'CONSULTATION'
type WorkOrderPriority = 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT'
type WorkOrderStatus = 'PENDING' | 'ASSIGNED' | 'IN_PROGRESS' | 'SUSPENDED' |
'RETURNED' | 'COMPLETED' | 'VERIFIED' | 'CANCELLED'
interface WorkOrder {
id?: string
workNo?: string
source: WorkOrderSource
type: WorkOrderType
title: string
priority: WorkOrderPriority
status: WorkOrderStatus
projectId?: string
equipmentId?: string
assignedTo?: string
// ...更多字段
}
```
#### 5.2.6 维保相关类型api/maintenance-*.ts内联
```typescript
type PlanType = 'PREVENTIVE' | 'CORRECTIVE'
type PlanStatus = 'ACTIVE' | 'INACTIVE' | 'SUSPENDED'
type TaskType = 'PREVENTIVE' | 'CORRECTIVE' | 'EMERGENCY'
type TaskPriority = 'LOW' | 'MEDIUM' | 'HIGH' | 'URGENT'
type TaskStatus = 'PENDING' | 'ASSIGNED' | 'IN_PROGRESS' | 'COMPLETED' | 'VERIFIED' | 'CANCELLED'
type TriggerType = 'PLAN' | 'INSPECTION' | 'FAULT' | 'MANUAL'
```
#### 5.2.7 能耗相关类型api/energy.ts内联
```typescript
interface EnergyMeter {
id?: string
meterCode: string
meterName: string
energyType: string
installationLocation?: string
ratedCapacity?: number
unitPrice?: number
status?: string
}
interface EnergyConsumption {
id?: string
meterId: string
consumptionDate: string
previousReading: number
currentReading: number
consumption: number
amount?: number
recordMethod?: string
}
```
#### 5.2.8 备件相关类型api/sparepart.ts内联
```typescript
interface SparePart {
id: string
name: string
code: string
categoryId?: string
projectId: string
unit?: string
currentStock?: number
safeStock?: number
lowStockWarning?: boolean
}
interface StockRecord {
id: string
sparePartId: string
operationType: 'IN' | 'OUT'
quantity: number
beforeStock?: number
afterStock?: number
relatedOrderId?: string
}
```
---
## 六、交互规范
### 6.1 表单验证规范
| 场景 | 验证规则 | 组件 |
|------|---------|------|
| 必填字段 | `required: true, message: '请输入xxx'` | a-form-item + rules |
| 字符串长度 | `min: 2, max: 50, message: '长度2-50位'` | a-input |
| 手机号 | `pattern: /^1[3-9]\d{9}$/, message: '请输入正确手机号'` | a-input |
| 邮箱 | `type: 'email', message: '请输入正确邮箱'` | a-input |
| 数字范围 | `type: 'number', min: 0, max: 99999` | a-input-number |
| 唯一性 | 异步验证,调用后端接口 | 自定义validator |
| 提交前验证 | `form.validate()` 全量校验 | a-form |
### 6.2 列表查询规范
| 规范项 | 实现方式 |
|--------|---------|
| 分页 | 后端分页,参数 `page`从0开始+ `size` |
| 搜索 | 关键词搜索参数 `keyword`,模糊匹配用户名/姓名/编码 |
| 筛选 | 下拉选择参数status/type等多条件组合 |
| 排序 | 后端默认排序通常按createdAt DESC |
| 刷新 | 切换页码/筛选条件后自动重新查询 |
| 空状态 | Ant Design Vue Table `locale.emptyText` |
### 6.3 状态展示规范
**颜色映射表**:
| 状态类型 | 映射规则 | Tag颜色 |
|---------|---------|---------|
| 用户状态 | ACTIVE=green, LOCKED=red, DISABLED=gray | a-tag color |
| 项目状态 | ACTIVE=success, DISABLED=error, PENDING=warning, ARCHIVED=default | a-tag color |
| 工单状态 | PENDING=default, ASSIGNED=blue, IN_PROGRESS=orange, COMPLETED=green, VERIFIED=cyan, CANCELLED=red | a-tag color |
| 工单优先级 | LOW=green, MEDIUM=blue, HIGH=orange, URGENT=red | a-tag color |
| 工单来源 | OWNER=purple, MAINTENANCE=blue, INSPECTION=cyan, FAULT=red | a-tag color |
| 维保任务状态 | PENDING=default, ASSIGNED=blue, IN_PROGRESS=orange, COMPLETED=green, VERIFIED=cyan, CANCELLED=red | a-tag color |
| 巡检状态 | NORMAL=green, WARNING=orange, ABNORMAL=red | a-tag color |
| 设备状态 | NORMAL=green, WARNING=orange, ABNORMAL=red | a-tag color |
### 6.4 操作确认规范
| 操作类型 | 确认方式 | 说明 |
|---------|---------|------|
| 删除 | `Modal.confirm` + 红色警告 | "确定要删除xxx吗此操作不可恢复" |
| 状态变更 | `Modal.confirm` | "确定要将状态从xxx变更为yyy吗" |
| 批量操作 | `Modal.confirm` + 数量提示 | "确定要删除选中的N条记录吗" |
| 取消工单 | `Modal.confirm` + 原因输入 | 需填写取消原因 |
| 表单提交 | 无确认 | 直接提交 |
| 登出 | 无确认 | 直接登出 |
---
## 七、权限控制
### 7.1 路由级权限meta.requiredRoles
**实现方式**: Vue Router `beforeEach` 守卫
```typescript
// 路由定义
{
path: 'system/users',
meta: { title: '用户管理', requiredRoles: ['SYS_ADMIN'] }
}
// 守卫校验
const requiredRoles = to.meta?.requiredRoles as string[] | undefined
if (requiredRoles?.length && !userStore.hasAnyRole(requiredRoles)) {
return next({ path: '/', query: { from: to.fullPath } })
}
```
**当前权限配置**:
| 路由 | requiredRoles |
|------|--------------|
| /system/* (6个页面) | `['SYS_ADMIN']` |
| 其他业务页面 | 无(仅要求已登录) |
### 7.2 按钮级权限v-if + hasRole
**实现方式**: Pinia Store `hasRole` / `hasAnyRole` 方法
```html
<a-button v-if="userStore.hasRole('SYS_ADMIN')" @click="handleDelete">
删除
</a-button>
```
**当前使用场景**: 有限,大部分页面未做按钮级权限控制
**建议增强**:
| 操作 | 建议权限检查 |
|------|------------|
| 创建/编辑/删除 | `userStore.hasAnyRole(['SYS_ADMIN', 'PROJECT_ADMIN'])` |
| 审批操作 | `userStore.hasRole('FINANCE_STAFF')` |
| 系统配置 | `userStore.hasRole('SYS_ADMIN')` |
### 7.3 数据级权限(后端控制)
**实现方式**: 后端 DataScopeService + X-Project-ID Header
| 数据范围 | 编码 | 后端过滤逻辑 |
|---------|------|------------|
| 全部数据 | ALL | 不做数据过滤 |
| 项目数据 | PROJECT | 过滤 project_id = X-Project-ID |
| 部门数据 | DEPARTMENT | 过滤 project_id + dept_id |
| 本人数据 | SELF | 过滤 assigned_to / created_by = 当前用户ID |
**前端配合**:
1. 请求拦截器自动注入 `X-Project-ID` Header从ProjectSelector获取
2. 前端不做数据过滤,完全依赖后端返回
3. 列表页面根据返回数据渲染,不额外过滤