# 前端交互域 - 详细设计

**文档类型**: 详细设计文档
**生成日期**: 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（项目选择器、用户信息、登出按钮）
- 中间：Content（router-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. 列表页面根据返回数据渲染，不额外过滤
