diff --git a/.kiro/settings/mcp.json b/.kiro/settings/mcp.json index 89bc455..44e9fae 100644 --- a/.kiro/settings/mcp.json +++ b/.kiro/settings/mcp.json @@ -1,6 +1,6 @@ { "mcpServers": { - "api-sqlserver": { + "api-sqlserver": { "command": "node", "args": [ "C:/mcp/mssql-mcp-server/index.js" @@ -30,7 +30,8 @@ }, "autoApprove": [ "execute_sql" - ] + ], + "disabled": true } } -} +} \ No newline at end of file diff --git a/.kiro/specs/odf-v120-marker-pole/.config.kiro b/.kiro/specs/odf-v120-marker-pole/.config.kiro new file mode 100644 index 0000000..cfaf435 --- /dev/null +++ b/.kiro/specs/odf-v120-marker-pole/.config.kiro @@ -0,0 +1 @@ +{"specId": "9a943afb-7e20-40a1-98c9-071c4599edc6", "workflowType": "requirements-first", "specType": "feature"} \ No newline at end of file diff --git a/.kiro/specs/odf-v120-marker-pole/design.md b/.kiro/specs/odf-v120-marker-pole/design.md new file mode 100644 index 0000000..d31f8ca --- /dev/null +++ b/.kiro/specs/odf-v120-marker-pole/design.md @@ -0,0 +1,564 @@ +# 技术设计文档 — ODF v1.2.0 标石杆号牌及管理后台优化 + +## 概述 + +本设计文档覆盖 ODF v1.2.0 版本的全部功能模块,基于现有技术栈(UniApp 前端 + .NET 后端 + Vue 管理后台 + SQL Server 数据库)进行扩展。主要包含: + +1. **标石/杆号牌 CRUD**:新增数据库表 `odf_marker_poles`、`odf_marker_pole_images`,后端 Controller/Service/Model,UniApp 前端 4 个新页面(光缆类型页、列表页、详情页、新增页),管理后台 Vue 页面 +2. **搜索扩展**:在现有干线搜索 API 和搜索结果页中增加标石/杆号牌类型 +3. **光交箱 UI 优化**:修改光交箱详情页左右框体配色(左绿右橙) +4. **审计日志(修改统计)**:新增 `odf_audit_logs` 表,通过 .NET ActionFilter 自动记录增删改操作 +5. **组织架构权限**:基于 `DeptId` 的数据隔离、机房权限修复、分公司管理员角色 + +## 架构 + +### 整体架构 + +```mermaid +graph TB + subgraph 前端 + A[odf-uniapp
UniApp/Vue3] -->|HTTP REST| C + B[ZR.Vue
管理后台] -->|HTTP REST| C + end + subgraph 后端 + C[ZR.Admin.WebApi
.NET Controllers] --> D[ZR.Service
业务逻辑层] + D --> E[SqlSugar ORM] + C --> F[ActionFilter
审计日志拦截] + F --> E + end + subgraph 存储 + E --> G[(SQL Server)] + A -->|直传| H[腾讯云 COS
图片存储] + end +``` + +### 数据流 + +- **标石/杆号牌新增流程**:拍照 → 水印叠加 → COS 直传 → 获取 COS URL → 提交表单(含 URL)→ 后端入库 +- **审计日志流程**:Controller Action 执行 → AuditLogFilter 拦截 → 记录操作前后数据 → 写入 `odf_audit_logs` +- **数据隔离流程**:请求到达 → 从 JWT Token 提取 DeptId → Service 层查询 `sys_dept` 获取本级及下级部门 ID 列表 → 拼接 WHERE 条件过滤 + +## 组件与接口 + +### 后端组件 + +#### 1. 标石/杆号牌模块 + +| 组件 | 路径 | 职责 | +|------|------|------| +| `OdfMarkerPolesController` | `Controllers/Business/OdfMarkerPolesController.cs` | REST API 入口 | +| `OdfMarkerPolesService` | `Service/Business/OdfMarkerPolesService.cs` | 业务逻辑 | +| `IOdfMarkerPolesService` | `Service/Business/IBusinessService/IOdfMarkerPolesService.cs` | 服务接口 | +| `OdfMarkerPoles` | `Model/Business/OdfMarkerPoles.cs` | 实体模型 | +| `OdfMarkerPoleImages` | `Model/Business/OdfMarkerPoleImages.cs` | 图片实体 | +| `OdfMarkerPolesDto` | `Model/Business/Dto/OdfMarkerPolesDto.cs` | 查询/新增/编辑 DTO | + +#### 2. 审计日志模块 + +| 组件 | 路径 | 职责 | +|------|------|------| +| `OdfAuditLogsController` | `Controllers/Business/OdfAuditLogsController.cs` | 审计日志查询 API | +| `OdfAuditLogsService` | `Service/Business/OdfAuditLogsService.cs` | 审计日志业务逻辑 | +| `OdfAuditLogs` | `Model/Business/OdfAuditLogs.cs` | 审计日志实体 | +| `OdfAuditLogFilter` | `Filters/OdfAuditLogFilter.cs` | ActionFilter,自动拦截记录 | + +#### 3. 数据隔离组件 + +| 组件 | 路径 | 职责 | +|------|------|------| +| `DeptDataScopeHelper` | `Service/Business/DeptDataScopeHelper.cs` | 根据 DeptId 查询本级及下级部门 ID 列表 | + +### API 接口设计 + +#### 标石/杆号牌 API + +``` +GET /business/OdfMarkerPoles/list?cableId={id}&pageNum=1&pageSize=10 + 权限: odfmarkerpoles:list + 返回: PagedInfo + +GET /business/OdfMarkerPoles/{id} + 权限: odfmarkerpoles:query + 返回: OdfMarkerPoleDetailDto(含图片列表) + +POST /business/OdfMarkerPoles/add + 权限: odfmarkerpoles:add + Body: OdfMarkerPoleAddDto + 返回: int (新记录ID) + +PUT /business/OdfMarkerPoles/edit + 权限: odfmarkerpoles:edit + Body: OdfMarkerPoleEditDto + 返回: int (影响行数) + +DELETE /business/OdfMarkerPoles/delete/{ids} + 权限: odfmarkerpoles:delete + 返回: int (删除行数) +``` + +#### 搜索 API 扩展 + +``` +GET /business/OdfCables/search?deptId={id}&keyword={kw} + 现有接口,返回结构新增 markerPoles 字段: + { cables: [...], faults: [...], markerPoles: [...] } +``` + +#### 审计日志 API + +``` +GET /business/OdfAuditLogs/list?pageNum=1&pageSize=10&beginTime=&endTime=&operationType= + 权限: odfauditlogs:list + 返回: PagedInfo +``` + +### 前端组件(UniApp) + +| 页面 | 路由 | 职责 | +|------|------|------| +| 光缆类型页 | `pages/cable-type/index` | 展示【标石、杆号牌】和【故障列表】入口 | +| 标石杆号牌列表页 | `pages/marker-pole-list/index` | 展示某光缆下标石/杆号牌列表 | +| 标石杆号牌详情页 | `pages/marker-pole-detail/index` | 展示详情,支持导航 | +| 新增标石杆号牌页 | `pages/marker-pole-add/index` | 拍照+水印+表单提交 | + +服务层新增 `services/markerPole.js`,封装标石/杆号牌相关 API 调用。 + +### 管理后台组件(ZR.Vue) + +| 组件 | 路径 | 职责 | +|------|------|------| +| `OdfMarkerPoles.vue` | `views/business/OdfMarkerPoles.vue` | 标石/杆号牌 CRUD 管理页 | +| `OdfAuditLogs.vue` | `views/business/OdfAuditLogs.vue` | 修改统计查看页 | +| `odfmarkerpoles.js` | `api/business/odfmarkerpoles.js` | 标石/杆号牌 API 封装 | +| `odfauditlogs.js` | `api/business/odfauditlogs.js` | 审计日志 API 封装 | + + +## 数据模型 + +### 数据库表设计 + +#### 1. `odf_marker_poles` — 标石/杆号牌表 + +```sql +CREATE TABLE odf_marker_poles ( + Id INT IDENTITY(1,1) PRIMARY KEY, -- 主键 + CableId INT NOT NULL, -- 关联光缆ID (odf_cables.Id) + Name NVARCHAR(200) NOT NULL, -- 标石/杆号牌名称 + RecordTime DATETIME NOT NULL, -- 记录时间(拍照时间) + Personnel NVARCHAR(100) NULL, -- 责任人 + Latitude DECIMAL(10,7) DEFAULT 0, -- 纬度 + Longitude DECIMAL(10,7) DEFAULT 0, -- 经度 + ActualMileage NVARCHAR(100) NULL, -- 实际里程 + DeptId BIGINT NOT NULL, -- 所属公司/部门ID + DeptName NVARCHAR(200) NULL, -- 部门名称(冗余) + UserId BIGINT NULL, -- 提交人用户ID + CreatedAt DATETIME DEFAULT GETDATE(), -- 创建时间 + UpdatedAt DATETIME DEFAULT GETDATE() -- 更新时间 +); + +CREATE INDEX IX_odf_marker_poles_CableId ON odf_marker_poles(CableId); +CREATE INDEX IX_odf_marker_poles_DeptId ON odf_marker_poles(DeptId); +``` + +#### 2. `odf_marker_pole_images` — 标石/杆号牌图片表 + +```sql +CREATE TABLE odf_marker_pole_images ( + Id INT IDENTITY(1,1) PRIMARY KEY, + MarkerPoleId INT NOT NULL, -- 关联标石ID (odf_marker_poles.Id) + ImageUrl NVARCHAR(500) NOT NULL, -- COS 图片 URL + CreatedAt DATETIME DEFAULT GETDATE() +); + +CREATE INDEX IX_odf_marker_pole_images_MarkerPoleId ON odf_marker_pole_images(MarkerPoleId); +``` + +#### 3. `odf_audit_logs` — 审计日志表 + +```sql +CREATE TABLE odf_audit_logs ( + Id INT IDENTITY(1,1) PRIMARY KEY, + TableName NVARCHAR(100) NOT NULL, -- 操作的表名 + RecordId INT NULL, -- 操作的记录ID + OperationType NVARCHAR(20) NOT NULL, -- 操作类型: INSERT/UPDATE/DELETE + OperatorId BIGINT NOT NULL, -- 操作人用户ID + OperatorName NVARCHAR(100) NULL, -- 操作人用户名 + SourceClient NVARCHAR(20) NOT NULL, -- 操作来源: App/Admin + OldData NVARCHAR(MAX) NULL, -- 修改前数据 (JSON) + NewData NVARCHAR(MAX) NULL, -- 修改后数据 (JSON) + OperationTime DATETIME DEFAULT GETDATE(), -- 操作时间 + DeptId BIGINT NULL, -- 操作人所属部门 + Remark NVARCHAR(500) NULL -- 备注 +); + +CREATE INDEX IX_odf_audit_logs_OperationTime ON odf_audit_logs(OperationTime); +CREATE INDEX IX_odf_audit_logs_TableName ON odf_audit_logs(TableName); +CREATE INDEX IX_odf_audit_logs_OperationType ON odf_audit_logs(OperationType); +``` + +### 实体模型 + +#### OdfMarkerPoles.cs + +```csharp +[SugarTable("odf_marker_poles")] +public class OdfMarkerPoles +{ + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + public int CableId { get; set; } + public string Name { get; set; } + public DateTime RecordTime { get; set; } + public string? Personnel { get; set; } + public decimal Latitude { get; set; } + public decimal Longitude { get; set; } + public string? ActualMileage { get; set; } + public long DeptId { get; set; } + public string? DeptName { get; set; } + public long? UserId { get; set; } + public DateTime? CreatedAt { get; set; } + public DateTime? UpdatedAt { get; set; } +} +``` + +#### OdfMarkerPoleImages.cs + +```csharp +[SugarTable("odf_marker_pole_images")] +public class OdfMarkerPoleImages +{ + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + public int MarkerPoleId { get; set; } + public string ImageUrl { get; set; } + public DateTime? CreatedAt { get; set; } +} +``` + +#### OdfAuditLogs.cs + +```csharp +[SugarTable("odf_audit_logs")] +public class OdfAuditLogs +{ + [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] + public int Id { get; set; } + public string TableName { get; set; } + public int? RecordId { get; set; } + public string OperationType { get; set; } + public long OperatorId { get; set; } + public string? OperatorName { get; set; } + public string SourceClient { get; set; } + [SugarColumn(ColumnDataType = "nvarchar(max)")] + public string? OldData { get; set; } + [SugarColumn(ColumnDataType = "nvarchar(max)")] + public string? NewData { get; set; } + public DateTime? OperationTime { get; set; } + public long? DeptId { get; set; } + public string? Remark { get; set; } +} +``` + +### DTO 设计 + +#### OdfMarkerPolesDto.cs + +```csharp +// 查询 DTO +public class OdfMarkerPolesQueryDto : PagerInfo +{ + public int? CableId { get; set; } + public string? Keyword { get; set; } +} + +// 新增 DTO +public class OdfMarkerPoleAddDto +{ + public int CableId { get; set; } + public string Name { get; set; } + public string RecordTime { get; set; } + public string? Personnel { get; set; } + public decimal Latitude { get; set; } + public decimal Longitude { get; set; } + public string? ActualMileage { get; set; } + public long? UserId { get; set; } + public string[] ImageUrls { get; set; } +} + +// 编辑 DTO +public class OdfMarkerPoleEditDto +{ + public int Id { get; set; } + public string Name { get; set; } + public string? Personnel { get; set; } + public decimal Latitude { get; set; } + public decimal Longitude { get; set; } + public string? ActualMileage { get; set; } + public int CableId { get; set; } +} + +// 审计日志查询 DTO +public class OdfAuditLogsQueryDto : PagerInfo +{ + public DateTime? BeginTime { get; set; } + public DateTime? EndTime { get; set; } + public string? OperationType { get; set; } + public string? TableName { get; set; } +} +``` + +### 页面路由设计(UniApp pages.json 新增) + +```json +{ + "path": "pages/cable-type/index", + "style": { "navigationStyle": "custom", "navigationBarTitleText": "" } +}, +{ + "path": "pages/marker-pole-list/index", + "style": { "navigationStyle": "custom", "navigationBarTitleText": "" } +}, +{ + "path": "pages/marker-pole-detail/index", + "style": { "navigationStyle": "custom", "navigationBarTitleText": "" } +}, +{ + "path": "pages/marker-pole-add/index", + "style": { "navigationStyle": "custom", "navigationBarTitleText": "" } +} +``` + +### 页面导航流程 + +```mermaid +graph LR + A[光缆列表页
cable/index] -->|点击光缆| B[光缆类型页
cable-type/index] + B -->|标石杆号牌| C[标石列表页
marker-pole-list/index] + B -->|故障列表| D[故障列表页
fault-list/index] + C -->|点击记录| E[标石详情页
marker-pole-detail/index] + C -->|新增| F[新增标石页
marker-pole-add/index] + E -->|导航按钮| G[外部导航APP/地图网页] +``` + +### 权限与数据隔离方案 + +#### 数据隔离实现 + +`DeptDataScopeHelper` 工具类提供统一的部门范围查询: + +```csharp +public static class DeptDataScopeHelper +{ + /// + /// 获取当前用户可见的部门ID列表(本级 + 所有下级) + /// + public static List GetVisibleDeptIds(ISqlSugarClient db, long deptId) + { + var allDepts = db.Queryable().ToList(); + var result = new List { deptId }; + CollectChildDeptIds(allDepts, deptId, result); + return result; + } + + private static void CollectChildDeptIds(List all, long parentId, List result) + { + var children = all.Where(d => d.ParentId == parentId).ToList(); + foreach (var child in children) + { + result.Add(child.DeptId); + CollectChildDeptIds(all, child.DeptId, result); + } + } +} +``` + +在 Service 层查询时统一应用: + +```csharp +var deptIds = DeptDataScopeHelper.GetVisibleDeptIds(Context, currentDeptId); +predicate = predicate.And(it => deptIds.Contains(it.DeptId)); +``` + +需要应用数据隔离的模块: +- 标石/杆号牌列表查询 +- 干线故障列表查询(现有,需补充 DeptId 过滤) +- 光缆列表查询 + +#### 机房权限修复 + +现有机房模块的权限控制需与干线模块对齐: +- 在 `OdfPortsController` 的编辑接口上增加 `odfports:edit` 权限校验 +- 前端 UniApp 在端口编辑弹窗中根据用户权限(从 store 中读取)控制编辑按钮的显示/隐藏 +- 权限值通过登录接口返回,存储在 `store.permissions` 中 + +#### 分公司管理员角色 + +- 在 `sys_role` 表中新增「分公司管理员」角色记录 +- 角色权限包含:查看本公司及下属公司数据、管理本公司及下级公司人员账号 +- 后端在创建用户时校验:分公司管理员只能创建 DeptId 在其可见范围内的账号 +- 管理后台登录时校验:分公司账号必须拥有「分公司管理员」角色才允许登录 + +### 光交箱 UI 配色方案 + +修改 `odf-uniapp/pages/optical-box-detail/index.vue` 中的样式: + +| 区域 | 当前颜色 | 新颜色 | +|------|---------|--------| +| 左侧框体(配线端子)背景 | `#FFC0CB` (粉色) | `#C8E6C9` (浅绿) | +| 左侧行背景 | `#FFB6C1` | `#A5D6A7` | +| 右侧框体(局线端子)背景 | `#E0F7FA` (浅蓝) | `#FFE0B2` (浅橙) | +| 右侧行背景 | `#B3E5FC` | `#FFCC80` | + + +## 正确性属性 + +*正确性属性是在系统所有有效执行中都应成立的特征或行为——本质上是关于系统应该做什么的形式化陈述。属性是人类可读规范与机器可验证正确性保证之间的桥梁。* + +### 属性 1:标石记录列表渲染包含必要字段 + +*对于任意*标石/杆号牌记录,当在列表页(包括标石列表页和搜索结果页)渲染时,渲染输出应包含名称、时间、责任人、所属光缆名称。 + +**验证需求: 2.1, 5.3** + +### 属性 2:标石详情页展示完整信息 + +*对于任意*标石/杆号牌记录,当在详情页渲染时,渲染输出应包含照片、名称、时间、责任人、经纬度、所属公司、实际里程。 + +**验证需求: 3.1** + +### 属性 3:标石 CRUD round-trip + +*对于任意*有效的标石/杆号牌数据,创建后通过 API 查询应返回与提交数据一致的记录;编辑后查询应返回修改后的值。 + +**验证需求: 4.8, 6.4** + +### 属性 4:标石删除后不可查 + +*对于任意*已存在的标石/杆号牌记录,执行删除操作后,通过 API 查询该记录应返回空或不存在。 + +**验证需求: 6.5** + +### 属性 5:新增标石自动填充所属公司 + +*对于任意*用户,新增标石/杆号牌时,后端应自动将该记录的 DeptId 和 DeptName 设置为当前用户的所属公司信息。 + +**验证需求: 4.4** + +### 属性 6:搜索结果包含匹配的标石记录 + +*对于任意*关键词和标石/杆号牌数据集,当标石名称包含该关键词时,搜索 API 返回的 markerPoles 列表应包含该标石记录。 + +**验证需求: 5.1** + +### 属性 7:管理后台标石列表展示完整字段 + +*对于任意*标石/杆号牌记录,管理后台列表 API 返回的数据应包含名称、时间、责任人、经纬度、所属公司、所属光缆、实际里程。 + +**验证需求: 6.2** + +### 属性 8:业务操作产生完整审计日志 + +*对于任意*对 ODF/干线/标石相关数据的增删改操作,审计日志表中应存在对应记录,且该记录包含操作人、操作时间、操作类型、操作来源端;当操作类型为修改时,应同时包含修改前数据(OldData)和修改后数据(NewData)。 + +**验证需求: 8.2, 8.3, 8.4** + +### 属性 9:审计日志筛选正确性 + +*对于任意*时间范围和操作类型筛选条件,审计日志查询 API 返回的所有记录应满足:操作时间在指定范围内,且操作类型匹配筛选条件。 + +**验证需求: 8.5, 8.6** + +### 属性 10:数据隔离 — 查询结果仅包含可见部门数据 + +*对于任意*用户和任意数据查询(光缆、故障、标石),返回的所有记录的 DeptId 应属于该用户可见的部门 ID 集合(本级 + 所有下级部门)。 + +**验证需求: 9.1, 9.2, 9.3, 9.4** + +### 属性 11:机房操作权限与用户角色匹配 + +*对于任意*用户和机房操作请求,当用户权限为「仅查看」时,修改操作应被拒绝;当用户权限为「修改和查看」时,查看和修改操作应被允许。 + +**验证需求: 10.1, 10.2** + +### 属性 12:分公司管理员创建账号范围限制 + +*对于任意*分公司管理员创建用户账号操作,新账号的 DeptId 必须在该管理员可见的部门范围内(本公司及下级公司),否则操作应被拒绝。 + +**验证需求: 11.3, 11.5** + +### 属性 13:非分公司管理员禁止登录管理后台 + +*对于任意*分公司级别的账号,如果该账号不具有「分公司管理员」角色,则登录管理后台的请求应被拒绝。 + +**验证需求: 11.4** + +## 错误处理 + +### 前端错误处理(UniApp) + +| 场景 | 处理方式 | +|------|---------| +| 未拍照即提交 | `uni.showToast` 提示「请至少拍摄一张照片」,阻止提交 | +| 名称为空即提交 | `uni.showToast` 提示「请输入名称」,阻止提交 | +| 网络请求失败 | `uni.showToast` 提示错误信息,保留用户已填写数据 | +| GPS 定位失败 | 提示用户检查定位权限,不阻止表单提交(经纬度可为 0) | +| COS 图片上传失败 | 提示上传失败,允许重试 | +| 导航经纬度为空 | 隐藏导航按钮,不展示导航入口 | + +### 后端错误处理(.NET) + +| 场景 | HTTP 状态码 | 处理方式 | +|------|------------|---------| +| CableId 不存在 | 400 | 抛出 `CustomException("光缆不存在")` | +| 标石记录不存在 | 400 | 抛出 `CustomException("标石记录不存在")` | +| 无图片 URL | 400 | 抛出 `CustomException("请至少上传一张图片")` | +| 无权限访问 | 403 | 框架 `ActionPermissionFilter` 自动拦截 | +| 数据隔离越权 | 403 | Service 层校验 DeptId 范围,不在范围内返回空数据 | +| 分公司管理员越权创建账号 | 400 | 抛出 `CustomException("无权为该公司创建账号")` | +| 审计日志写入失败 | - | 记录错误日志,不影响主业务流程(异步/try-catch) | + +## 测试策略 + +### 双重测试方法 + +本项目采用单元测试 + 属性测试的双重测试策略: + +- **单元测试**:验证具体示例、边界条件和错误处理 +- **属性测试**:验证跨所有输入的通用属性 + +### 属性测试配置 + +- **测试库**:后端使用 [FsCheck](https://fscheck.github.io/FsCheck/) (.NET 属性测试库);前端使用 [fast-check](https://github.com/dubzzz/fast-check) (JavaScript 属性测试库) +- **每个属性测试最少运行 100 次迭代** +- **每个属性测试必须通过注释引用设计文档中的属性编号** +- **标签格式**:`Feature: odf-v120-marker-pole, Property {number}: {property_text}` +- **每个正确性属性由单个属性测试实现** + +### 单元测试覆盖 + +| 测试类别 | 覆盖内容 | +|---------|---------| +| API 示例测试 | 标石 CRUD 接口的正常流程验证 | +| 边界条件 | 空列表状态、经纬度为零、未拍照提交、上传失败 | +| 权限测试 | 仅查看用户无法修改、非管理员无法登录后台 | +| 数据隔离 | 跨公司数据不可见 | +| 搜索测试 | 关键词匹配、无结果场景 | +| UI 样式 | 光交箱左绿右橙配色验证 | + +### 属性测试覆盖 + +| 属性编号 | 测试内容 | 测试库 | +|---------|---------|--------| +| 属性 1 | 标石列表渲染字段完整性 | fast-check | +| 属性 2 | 标石详情渲染字段完整性 | fast-check | +| 属性 3 | 标石 CRUD round-trip | FsCheck | +| 属性 4 | 标石删除后不可查 | FsCheck | +| 属性 5 | 新增标石自动填充公司 | FsCheck | +| 属性 6 | 搜索结果包含匹配标石 | FsCheck | +| 属性 7 | 管理后台列表字段完整性 | FsCheck | +| 属性 8 | 审计日志完整性 | FsCheck | +| 属性 9 | 审计日志筛选正确性 | FsCheck | +| 属性 10 | 数据隔离正确性 | FsCheck | +| 属性 11 | 机房权限匹配 | FsCheck | +| 属性 12 | 创建账号范围限制 | FsCheck | +| 属性 13 | 非管理员登录拒绝 | FsCheck | diff --git a/.kiro/specs/odf-v120-marker-pole/requirements.md b/.kiro/specs/odf-v120-marker-pole/requirements.md new file mode 100644 index 0000000..9767599 --- /dev/null +++ b/.kiro/specs/odf-v120-marker-pole/requirements.md @@ -0,0 +1,174 @@ +# 需求文档 — ODF v1.2.0 标石杆号牌及管理后台优化 + +## 简介 + +ODF(光缆资源管理)v1.2.0 版本在现有 odf-uniapp(UniApp/Vue)前端和 .NET 后端基础上进行功能扩展。本次更新包含三大模块:新增标石/杆号牌完整 CRUD 功能(含拍照水印、GPS 定位、导航)、光交箱机房详情页 UI 优化、管理后台修改统计与组织架构权限优化。H5 与 APP 同步更新。 + +## 需求来源 + +#[[file:docs/1.2.0/1.2.0.md]] + +## 术语表 + +- **App**:odf-uniapp 前端应用,基于 UniApp + Vue 构建,运行于安卓和 H5 平台 +- **管理后台**:基于 ZR.Vue(Vue.js)构建的 Web 管理系统,用于数据配置和管理 +- **后端**:基于 .NET 的 ZR.Admin.WebApi 服务端,提供 RESTful API +- **光缆列表页**:展示某公司下所有光缆的页面(现有 pages/cable/index) +- **光缆类型页**:点击光缆后进入的中间页面,展示【标石、杆号牌】和【故障列表】两个入口按钮 +- **标石杆号牌列表页**:展示某光缆下所有标石/杆号牌记录的页面 +- **标石杆号牌详情页**:展示单条标石/杆号牌完整信息的页面 +- **新增标石杆号牌页**:用于创建新标石/杆号牌记录的表单页面 +- **水印照片**:拍摄后在照片上叠加坐标、时间、责任人、所属光缆等信息文字的照片 +- **导航点**:标石/杆号牌的 GPS 经纬度坐标,用于地图导航 +- **实际里程**:标石/杆号牌在光缆上的实际里程数值 +- **光交箱详情页**:光交箱类型机架的详情页面(现有 pages/optical-box-detail/index) +- **修改统计**:管理后台记录所有增删改操作的审计功能 +- **组织架构权限**:基于公司层级的数据隔离和访问控制机制 +- **分公司管理员**:分公司级别的管理角色,可管理本公司及下属公司人员账号 + +## 需求 + +### 需求 1:光缆类型页入口 + +**用户故事:** 作为用户,我希望点击光缆后看到功能分类入口,以便分别进入标石杆号牌管理或故障管理。 + +#### 验收标准 + +1. WHEN 用户在光缆列表页点击任意光缆,THE App SHALL 跳转至光缆类型页 +2. THE 光缆类型页 SHALL 展示【标石、杆号牌】和【故障列表】两个入口按钮 +3. WHEN 用户点击【标石、杆号牌】按钮,THE App SHALL 跳转至该光缆的标石杆号牌列表页 +4. WHEN 用户点击【故障列表】按钮,THE App SHALL 跳转至该光缆的故障列表页(现有页面) +5. THE 光缆类型页 SHALL 在导航栏显示当前光缆名称 + +### 需求 2:标石杆号牌列表页 + +**用户故事:** 作为用户,我希望查看某光缆下的所有标石/杆号牌记录,以便了解标石分布情况并新增记录。 + +#### 验收标准 + +1. THE 标石杆号牌列表页 SHALL 展示标石/杆号牌记录列表,每条记录显示名称、时间、责任人、导航点、实际里程 +2. WHEN 用户点击任意标石/杆号牌记录,THE App SHALL 跳转至该记录的标石杆号牌详情页 +3. THE 标石杆号牌列表页 SHALL 提供【新增】按钮 +4. WHEN 用户点击【新增】按钮,THE App SHALL 跳转至新增标石杆号牌页 +5. WHILE 该光缆下无标石/杆号牌记录,THE 标石杆号牌列表页 SHALL 展示空状态提示文字 + +### 需求 3:标石杆号牌详情页 + +**用户故事:** 作为用户,我希望查看标石/杆号牌的完整信息并导航至该位置,以便进行现场巡检。 + +#### 验收标准 + +1. THE 标石杆号牌详情页 SHALL 展示以下信息:照片、名称、时间、责任人、导航点(经纬度)、所属公司、实际里程 +2. WHEN 用户点击照片,THE App SHALL 以全屏模式放大展示该照片 +3. THE 标石杆号牌详情页 SHALL 提供【导航】按钮 +4. WHEN 用户点击【导航】按钮,THE App SHALL 根据导航点经纬度拉起导航应用 +5. IF 导航点经纬度为空或为零,THEN THE 标石杆号牌详情页 SHALL 隐藏【导航】按钮 + +### 需求 4:新增标石杆号牌页 + +**用户故事:** 作为用户,我希望在现场拍照记录标石/杆号牌信息并提交,以便及时上报标石数据。 + +#### 验收标准 + +1. THE 新增标石杆号牌页 SHALL 提供拍照功能,仅支持相机拍摄(不支持从相册选择) +2. WHEN 用户拍摄照片,THE App SHALL 在照片上叠加水印信息,水印内容包含:当前坐标、拍摄时间、责任人、所属光缆名称 +3. WHEN 用户拍摄照片完成,THE App SHALL 自动获取拍摄时间并填充至时间字段 +4. THE 新增标石杆号牌页 SHALL 自动填充所属公司(取当前用户所属公司) +5. THE 新增标石杆号牌页 SHALL 提供以下手动输入字段:名称、责任人、实际里程 +6. THE 新增标石杆号牌页 SHALL 提供【获取经纬度】按钮 +7. WHEN 用户点击【获取经纬度】按钮,THE App SHALL 调用设备定位功能获取当前经纬度,并在页面上显示经纬度数值 +8. WHEN 用户点击【提交】按钮,THE App SHALL 将所有数据(照片、名称、时间、责任人、经纬度、所属公司、所属光缆、实际里程)上传至后端 +9. WHEN 数据上传成功,THE App SHALL 弹出系统提示「提交成功」并自动返回标石杆号牌列表页 +10. IF 数据上传失败,THEN THE App SHALL 弹出错误提示信息,保留用户已填写的数据 +11. IF 用户未拍摄照片即点击提交,THEN THE App SHALL 提示用户至少拍摄一张照片 + +### 需求 5:搜索结果页支持标石杆号牌类型 + +**用户故事:** 作为用户,我希望搜索结果中能展示标石/杆号牌类型,以便在搜索时快速定位标石信息。 + +#### 验收标准 + +1. WHEN 用户在光缆列表页搜索关键词,THE App SHALL 在搜索范围中包含标石/杆号牌记录 +2. THE 搜索结果页 SHALL 新增「标石、杆号牌」分类区域,展示匹配的标石/杆号牌记录 +3. WHEN 搜索结果中包含匹配的标石/杆号牌记录,THE 搜索结果页 SHALL 在「标石、杆号牌」分类下展示名称、时间、责任人、所属光缆 +4. WHEN 用户点击搜索结果中的标石/杆号牌项,THE App SHALL 跳转至该记录的标石杆号牌详情页 + +### 需求 6:管理后台标石杆号牌增删改 + +**用户故事:** 作为管理员,我希望在管理后台对标石/杆号牌数据进行增删改操作,以便维护标石数据的准确性。 + +#### 验收标准 + +1. THE 管理后台 SHALL 提供标石/杆号牌管理页面,展示标石/杆号牌数据列表 +2. THE 管理后台标石杆号牌列表 SHALL 展示以下字段:名称、时间、责任人、经纬度、所属公司、所属光缆、实际里程 +3. THE 管理后台 SHALL 提供新增标石/杆号牌功能,支持填写名称、责任人、经纬度、所属光缆、实际里程 +4. THE 管理后台 SHALL 提供编辑标石/杆号牌功能,支持修改已有记录的所有字段 +5. THE 管理后台 SHALL 提供删除标石/杆号牌功能,支持删除单条记录 +6. WHEN 管理员执行删除操作,THE 管理后台 SHALL 弹出确认对话框,确认后执行删除 + +### 需求 7:光交箱机房详情页 UI 优化 + +**用户故事:** 作为用户,我希望光交箱详情页的左右两侧用不同颜色区分,以便快速识别光交箱端子和 ODF 端子。 + +#### 验收标准 + +1. THE 光交箱详情页 SHALL 将左侧框体背景色设置为绿色 +2. THE 光交箱详情页 SHALL 将右侧框体背景色设置为橙色 +3. THE 光交箱详情页 SHALL 仅对光交箱类型机架应用此配色方案,ODF 类型机架保持现有样式不变 + +### 需求 8:管理后台修改统计功能 + +**用户故事:** 作为管理员,我希望查看所有数据修改记录,以便追溯数据变更历史和责任人。 + +#### 验收标准 + +1. THE 管理后台 SHALL 提供修改统计页面,展示所有增删改操作记录 +2. WHEN 前端 App 或管理后台对 ODF、干线相关内容执行新增、修改、删除操作,THE 后端 SHALL 记录该操作的审计日志 +3. THE 修改统计记录 SHALL 包含以下信息:修改人、修改时间、具体修改内容、操作来源端(App 端或管理后台端) +4. WHEN 操作类型为修改,THE 修改统计记录 SHALL 保存修改前和修改后的数据,支持对比查看 +5. THE 管理后台修改统计页面 SHALL 支持按时间范围筛选查看记录 +6. THE 管理后台修改统计页面 SHALL 支持按操作类型(新增、修改、删除)筛选查看记录 + +### 需求 9:组织架构权限 — 公司数据隔离 + +**用户故事:** 作为管理员,我希望每个账号只能看到所属公司的数据,以便实现数据安全隔离。 + +#### 验收标准 + +1. THE 后端 SHALL 根据当前登录账号的所属公司过滤返回数据,每个账号仅能查看所属公司的信息 +2. WHILE 当前账号为上级公司账号,THE 后端 SHALL 允许该账号查看本公司及所有下级公司的信息 +3. THE 后端 SHALL 对干线故障数据执行公司隔离,管理后台仅展示当前账号有权限查看的公司故障数据 +4. THE 后端 SHALL 对标石/杆号牌数据执行公司隔离,遵循与干线故障相同的公司层级权限规则 + +### 需求 10:组织架构权限 — 机房权限修复 + +**用户故事:** 作为管理员,我希望机房内容的查看/修改权限与干线权限保持一致,以便权限控制准确生效。 + +#### 验收标准 + +1. WHILE 当前账号权限为「仅查看」,THE App SHALL 禁止该账号对机房内容执行任何修改操作 +2. WHILE 当前账号权限为「修改和查看」,THE App SHALL 允许该账号对机房内容执行查看和修改操作 +3. THE App 机房权限控制 SHALL 与干线版块的「仅查看」「修改和查看」权限逻辑保持一致 + +### 需求 11:组织架构权限 — 分公司管理员角色 + +**用户故事:** 作为分公司管理员,我希望管理本公司及下属公司的人员账号,以便实现分级管理。 + +#### 验收标准 + +1. THE 管理后台 SHALL 新增「分公司管理员」角色 +2. THE 分公司管理员 SHALL 能查看本公司及下属公司的所有信息 +3. THE 分公司管理员 SHALL 能新增所属分公司和下级公司的人员账号 +4. WHILE 分公司账号角色不是「分公司管理员」,THE 管理后台 SHALL 禁止该账号登录管理后台 +5. THE 后端 SHALL 在分公司管理员创建账号时,限制新账号的所属公司范围为本公司及下级公司 + +### 需求 12:平台兼容性 + +**用户故事:** 作为用户,我希望在安卓和 H5 平台上使用相同的标石杆号牌功能,以便在不同设备上获得一致的体验。 + +#### 验收标准 + +1. THE App SHALL 在安卓平台和 H5 平台同步提供标石杆号牌的所有功能 +2. WHEN App 在新增标石杆号牌页使用拍照功能,THE App SHALL 在安卓平台调用原生相机 API,在 H5 平台调用浏览器媒体 API +3. WHEN App 在新增标石杆号牌页使用定位功能,THE App SHALL 在安卓平台调用原生定位 API,在 H5 平台调用浏览器 Geolocation API +4. WHEN App 在标石杆号牌详情页调用导航功能,THE App SHALL 在安卓平台弹出已安装的导航 APP 列表,在 H5 平台打开地图网页进行导航 diff --git a/.kiro/specs/odf-v120-marker-pole/tasks.md b/.kiro/specs/odf-v120-marker-pole/tasks.md new file mode 100644 index 0000000..df92118 --- /dev/null +++ b/.kiro/specs/odf-v120-marker-pole/tasks.md @@ -0,0 +1,219 @@ +# 实现计划:ODF v1.2.0 标石杆号牌及管理后台优化 + +## 概述 + +基于需求文档和设计文档,按照数据库 → 后端模型 → 后端服务/接口 → 前端 UniApp → 管理后台 Vue 的顺序实现。涵盖标石/杆号牌 CRUD、搜索扩展、光交箱 UI 优化、审计日志、组织架构权限五大模块。 + +## 任务 + +- [x] 1. 数据库迁移脚本 + - [x] 1.1 创建标石/杆号牌相关表 + - 创建 `sql/v1.2.0/` 目录 + - 编写 `01_create_odf_marker_poles.sql`:创建 `odf_marker_poles` 表及索引(CableId, DeptId) + - 编写 `02_create_odf_marker_pole_images.sql`:创建 `odf_marker_pole_images` 表及索引(MarkerPoleId) + - _需求: 2.1, 4.8, 6.1_ + - [x] 1.2 创建审计日志表 + - 编写 `03_create_odf_audit_logs.sql`:创建 `odf_audit_logs` 表及索引(OperationTime, TableName, OperationType) + - _需求: 8.1, 8.2_ + - [x] 1.3 创建菜单和权限数据脚本 + - 编写 `04_insert_marker_pole_menus_permissions.sql`:插入标石/杆号牌管理菜单、审计日志菜单及对应按钮权限(odfmarkerpoles:list/query/add/edit/delete, odfauditlogs:list) + - 编写 `05_insert_branch_admin_role.sql`:插入「分公司管理员」角色记录到 `sys_role`,并配置角色权限 + - _需求: 6.1, 8.1, 11.1_ + +- [x] 2. 后端模型层(ZR.Model) + - [x] 2.1 创建标石/杆号牌实体模型 + - 创建 `server/ZR.Model/Business/OdfMarkerPoles.cs`:定义 `OdfMarkerPoles` 实体,映射 `odf_marker_poles` 表 + - 创建 `server/ZR.Model/Business/OdfMarkerPoleImages.cs`:定义 `OdfMarkerPoleImages` 实体,映射 `odf_marker_pole_images` 表 + - _需求: 2.1, 3.1, 4.8_ + - [x] 2.2 创建标石/杆号牌 DTO + - 创建 `server/ZR.Model/Business/Dto/OdfMarkerPolesDto.cs`:定义 `OdfMarkerPolesQueryDto`、`OdfMarkerPoleAddDto`、`OdfMarkerPoleEditDto`、`OdfMarkerPoleListDto`、`OdfMarkerPoleDetailDto` + - _需求: 2.1, 3.1, 4.8, 6.2, 6.3, 6.4_ + - [x] 2.3 创建审计日志实体和 DTO + - 创建 `server/ZR.Model/Business/OdfAuditLogs.cs`:定义 `OdfAuditLogs` 实体,映射 `odf_audit_logs` 表 + - 创建 `server/ZR.Model/Business/Dto/OdfAuditLogsDto.cs`:定义 `OdfAuditLogsQueryDto` + - _需求: 8.2, 8.3_ + +- [x] 3. 后端服务层与 API — 标石/杆号牌模块 + - [x] 3.1 创建数据隔离工具类 + - 创建 `server/ZR.Service/Business/DeptDataScopeHelper.cs`:实现 `GetVisibleDeptIds` 方法,根据 DeptId 递归查询本级及所有下级部门 ID 列表 + - _需求: 9.1, 9.2_ + - [x] 3.2 创建标石/杆号牌服务接口和实现 + - 创建 `server/ZR.Service/Business/IBusinessService/IOdfMarkerPolesService.cs`:定义 GetList、GetDetail、Add、Update、Delete 接口方法 + - 创建 `server/ZR.Service/Business/OdfMarkerPolesService.cs`:实现标石/杆号牌 CRUD 逻辑,查询时应用 DeptDataScopeHelper 进行数据隔离,新增时自动填充 DeptId/DeptName + - _需求: 2.1, 3.1, 4.4, 4.8, 6.3, 6.4, 6.5, 9.4_ + - [x] 3.3 创建标石/杆号牌图片服务 + - 创建 `server/ZR.Service/Business/IBusinessService/IOdfMarkerPoleImagesService.cs` + - 创建 `server/ZR.Service/Business/OdfMarkerPoleImagesService.cs`:实现图片批量插入、按 MarkerPoleId 查询、按 MarkerPoleId 删除 + - _需求: 3.1, 4.1, 4.8_ + - [x] 3.4 创建标石/杆号牌 Controller + - 创建 `server/ZR.Admin.WebApi/Controllers/Business/OdfMarkerPolesController.cs`:实现 list/query/add/edit/delete 五个接口,配置 `ActionPermissionFilter` 权限校验 + - 新增时校验 CableId 存在性和 ImageUrls 非空 + - _需求: 2.1, 3.1, 4.8, 6.3, 6.4, 6.5_ + - [ ]* 3.5 编写标石/杆号牌 CRUD 属性测试 + - **属性 3: 标石 CRUD round-trip** + - **属性 4: 标石删除后不可查** + - **属性 5: 新增标石自动填充所属公司** + - **验证需求: 4.4, 4.8, 6.4, 6.5** + +- [x] 4. 后端服务层与 API — 搜索扩展 + - [x] 4.1 扩展搜索接口支持标石/杆号牌 + - 修改 `server/ZR.Service/Business/OdfCablesService.cs` 的 `Search` 方法:在搜索结果中新增 `markerPoles` 字段,按关键词匹配标石名称 + - 修改 `server/ZR.Admin.WebApi/Controllers/Business/OdfCablesController.cs` 对应接口返回结构 + - _需求: 5.1, 5.2_ + - [ ]* 4.2 编写搜索属性测试 + - **属性 6: 搜索结果包含匹配的标石记录** + - **验证需求: 5.1** + +- [x] 5. 后端服务层与 API — 审计日志模块 + - [x] 5.1 创建审计日志服务 + - 创建 `server/ZR.Service/Business/IBusinessService/IOdfAuditLogsService.cs` + - 创建 `server/ZR.Service/Business/OdfAuditLogsService.cs`:实现分页查询(支持时间范围、操作类型筛选)和写入方法 + - _需求: 8.1, 8.5, 8.6_ + - [x] 5.2 创建审计日志 ActionFilter + - 创建 `server/ZR.Admin.WebApi/Filters/OdfAuditLogFilter.cs`:实现 `IAsyncActionFilter`,拦截标石/ODF/干线相关 Controller 的增删改操作 + - 在 `OnActionExecutionAsync` 中记录操作前数据(OldData),在操作后记录新数据(NewData) + - 通过 `SourceClient` 区分 App 端和管理后台端(从请求 Header 或路由判断) + - 审计日志写入失败时 try-catch 不影响主业务 + - _需求: 8.2, 8.3, 8.4_ + - [x] 5.3 创建审计日志 Controller + - 创建 `server/ZR.Admin.WebApi/Controllers/Business/OdfAuditLogsController.cs`:实现 list 查询接口,配置 `odfauditlogs:list` 权限 + - _需求: 8.1, 8.5_ + - [x] 5.4 在现有 Controller 上应用审计日志 Filter + - 在 `OdfMarkerPolesController`、`OdfCablesController`、`OdfCableFaultsController`、`OdfPortsController`、`OdfRacksController` 的增删改 Action 上添加 `[ServiceFilter(typeof(OdfAuditLogFilter))]` + - _需求: 8.2_ + - [ ]* 5.5 编写审计日志属性测试 + - **属性 8: 业务操作产生完整审计日志** + - **属性 9: 审计日志筛选正确性** + - **验证需求: 8.2, 8.3, 8.4, 8.5, 8.6** + +- [x] 6. 后端 — 数据隔离与权限修复 + - [x] 6.1 应用数据隔离到现有模块 + - 修改 `server/ZR.Service/Business/OdfCableFaultsService.cs`:在查询方法中应用 `DeptDataScopeHelper` 过滤 DeptId + - 修改 `server/ZR.Service/Business/OdfCablesService.cs`:在查询方法中应用 `DeptDataScopeHelper` 过滤 DeptId + - _需求: 9.1, 9.2, 9.3_ + - [x] 6.2 修复机房权限控制 + - 修改 `server/ZR.Admin.WebApi/Controllers/Business/OdfPortsController.cs`:在编辑接口上增加 `odfports:edit` 权限校验 + - _需求: 10.1, 10.2, 10.3_ + - [x] 6.3 实现分公司管理员登录限制 + - 修改后端登录逻辑:分公司级别账号登录管理后台时,校验是否拥有「分公司管理员」角色,无该角色则拒绝登录 + - _需求: 11.4_ + - [x] 6.4 实现分公司管理员创建账号范围限制 + - 修改后端用户创建逻辑:分公司管理员创建用户时,校验新账号 DeptId 是否在管理员可见部门范围内 + - _需求: 11.3, 11.5_ + - [ ]* 6.5 编写数据隔离与权限属性测试 + - **属性 10: 数据隔离 — 查询结果仅包含可见部门数据** + - **属性 11: 机房操作权限与用户角色匹配** + - **属性 12: 分公司管理员创建账号范围限制** + - **属性 13: 非分公司管理员禁止登录管理后台** + - **验证需求: 9.1, 9.2, 9.3, 9.4, 10.1, 10.2, 11.3, 11.4, 11.5** + +- [x] 7. 检查点 — 后端完成验证 + - 确保所有后端代码编译通过,所有测试通过,如有问题请向用户确认。 + +- [x] 8. UniApp 前端 — 标石/杆号牌服务层 + - [x] 8.1 创建标石/杆号牌 API 服务 + - 创建 `odf-uniapp/services/markerPole.js`:封装 getMarkerPoleList、getMarkerPoleDetail、addMarkerPole、searchMarkerPoles 等 API 调用方法 + - _需求: 2.1, 3.1, 4.8, 5.1_ + +- [x] 9. UniApp 前端 — 光缆类型页 + - [x] 9.1 创建光缆类型页 + - 创建 `odf-uniapp/pages/cable-type/index.vue`:展示【标石、杆号牌】和【故障列表】两个入口按钮 + - 导航栏显示当前光缆名称 + - 点击按钮分别跳转至标石列表页和故障列表页,传递 cableId 和 cableName 参数 + - _需求: 1.1, 1.2, 1.3, 1.4, 1.5_ + - [x] 9.2 修改光缆列表页跳转逻辑 + - 修改 `odf-uniapp/pages/cable/index.vue`:点击光缆时跳转至光缆类型页(而非直接跳转故障列表页) + - _需求: 1.1_ + - [x] 9.3 注册新页面路由 + - 修改 `odf-uniapp/pages.json`:添加 cable-type、marker-pole-list、marker-pole-detail、marker-pole-add 四个页面路由配置 + - _需求: 1.1, 2.1, 3.1, 4.1_ + +- [x] 10. UniApp 前端 — 标石/杆号牌列表页 + - [x] 10.1 创建标石/杆号牌列表页 + - 创建 `odf-uniapp/pages/marker-pole-list/index.vue`:展示标石/杆号牌记录列表,每条显示名称、时间、责任人、导航点、实际里程 + - 点击记录跳转详情页,点击【新增】按钮跳转新增页 + - 无数据时展示空状态提示 + - _需求: 2.1, 2.2, 2.3, 2.4, 2.5_ + - [ ]* 10.2 编写标石列表渲染属性测试 + - **属性 1: 标石记录列表渲染包含必要字段** + - **验证需求: 2.1, 5.3** + +- [x] 11. UniApp 前端 — 标石/杆号牌详情页 + - [x] 11.1 创建标石/杆号牌详情页 + - 创建 `odf-uniapp/pages/marker-pole-detail/index.vue`:展示照片、名称、时间、责任人、导航点(经纬度)、所属公司、实际里程 + - 照片支持点击全屏预览(uni.previewImage) + - 提供【导航】按钮,经纬度为空或为零时隐藏 + - 点击导航按钮:安卓端弹出导航 APP 列表,H5 端打开地图网页 + - _需求: 3.1, 3.2, 3.3, 3.4, 3.5, 12.4_ + - [ ]* 11.2 编写标石详情渲染属性测试 + - **属性 2: 标石详情页展示完整信息** + - **验证需求: 3.1** + +- [x] 12. UniApp 前端 — 新增标石/杆号牌页 + - [x] 12.1 创建新增标石/杆号牌页 + - 创建 `odf-uniapp/pages/marker-pole-add/index.vue` + - 拍照功能:调用 uni.chooseImage(sourceType: ['camera']),拍摄后叠加水印(坐标、时间、责任人、所属光缆) + - 自动填充拍摄时间和所属公司 + - 手动输入字段:名称、责任人、实际里程 + - 【获取经纬度】按钮:调用 uni.getLocation 获取 GPS 坐标 + - 提交前校验:名称非空、至少一张照片 + - 照片上传至腾讯云 COS,获取 URL 后提交表单 + - 提交成功后提示并返回列表页 + - _需求: 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 4.10, 4.11, 12.1, 12.2, 12.3_ + +- [x] 13. UniApp 前端 — 搜索扩展 + - [x] 13.1 扩展搜索结果页支持标石/杆号牌 + - 修改 `odf-uniapp/pages/trunk-search/index.vue`(或对应搜索结果页):新增「标石、杆号牌」分类区域 + - 展示匹配的标石记录(名称、时间、责任人、所属光缆) + - 点击标石记录跳转至详情页 + - _需求: 5.1, 5.2, 5.3, 5.4_ + - [x] 13.2 修改搜索服务调用 + - 修改 `odf-uniapp/services/search.js`:适配搜索 API 返回的 markerPoles 新字段 + - _需求: 5.1_ + +- [x] 14. UniApp 前端 — 光交箱 UI 优化与机房权限修复 + - [x] 14.1 修改光交箱详情页配色 + - 修改 `odf-uniapp/pages/optical-box-detail/index.vue`:左侧框体背景改为浅绿(#C8E6C9 / #A5D6A7),右侧框体背景改为浅橙(#FFE0B2 / #FFCC80) + - 仅光交箱类型应用新配色,ODF 类型保持不变 + - _需求: 7.1, 7.2, 7.3_ + - [x] 14.2 修复机房端口编辑权限控制 + - 修改 `odf-uniapp/components/port-edit-dialog.vue`(或对应端口编辑组件):根据 store 中用户权限控制编辑按钮显示/隐藏 + - 「仅查看」权限用户隐藏编辑入口,「修改和查看」权限用户显示编辑入口 + - _需求: 10.1, 10.2, 10.3_ + +- [x] 15. 检查点 — UniApp 前端完成验证 + - 确保所有 UniApp 页面编译通过,页面导航流程正确,如有问题请向用户确认。 + +- [x] 16. 管理后台 Vue — 标石/杆号牌管理页 + - [x] 16.1 创建标石/杆号牌 API 封装 + - 创建 `server/ZR.Vue/src/api/business/odfmarkerpoles.js`:封装 list、get、add、update、del 接口调用 + - _需求: 6.1_ + - [x] 16.2 创建标石/杆号牌管理页面 + - 创建 `server/ZR.Vue/src/views/business/OdfMarkerPoles.vue`:实现数据列表(名称、时间、责任人、经纬度、所属公司、所属光缆、实际里程)、新增对话框、编辑对话框、删除确认 + - _需求: 6.1, 6.2, 6.3, 6.4, 6.5, 6.6_ + - [ ]* 16.3 编写管理后台标石列表属性测试 + - **属性 7: 管理后台标石列表展示完整字段** + - **验证需求: 6.2** + +- [x] 17. 管理后台 Vue — 审计日志页 + - [x] 17.1 创建审计日志 API 封装 + - 创建 `server/ZR.Vue/src/api/business/odfauditlogs.js`:封装 list 查询接口 + - _需求: 8.1_ + - [x] 17.2 创建审计日志管理页面 + - 创建 `server/ZR.Vue/src/views/business/OdfAuditLogs.vue`:实现审计日志列表(操作人、时间、操作类型、操作来源、表名)、时间范围筛选、操作类型筛选、修改前后数据对比展示 + - _需求: 8.1, 8.3, 8.4, 8.5, 8.6_ + +- [x] 18. 管理后台 Vue — 分公司管理员登录限制 + - [x] 18.1 管理后台登录页增加分公司管理员校验 + - 修改管理后台登录流程:登录成功后检查返回的角色信息,分公司账号若无「分公司管理员」角色则提示无权登录并阻止进入 + - _需求: 11.4_ + +- [x] 19. 最终检查点 — 全部完成验证 + - 确保所有后端编译通过、前端编译通过、管理后台编译通过,所有测试通过,如有问题请向用户确认。 + +## 备注 + +- 标记 `*` 的子任务为可选测试任务,可跳过以加快 MVP 进度 +- 每个任务引用了具体的需求编号,确保需求全覆盖 +- 检查点任务用于阶段性验证,确保增量开发的正确性 +- 属性测试验证设计文档中定义的正确性属性 diff --git a/docs/1.2.0/1.2.0.md b/docs/1.2.0/1.2.0.md new file mode 100644 index 0000000..61b6442 --- /dev/null +++ b/docs/1.2.0/1.2.0.md @@ -0,0 +1,94 @@ +# odf(光缆资源管理)v1.2.0需求文档 + +# 需求大纲 + + +1. H5、APP同步更新。 +2. 新增标石、杆号牌相关功能。 +3. 优化后台相关功能。 + +# 标石、杆号牌入口 + + ![](attachments/895d5b87-4235-4a0d-a6a4-a0ce8cc82d18.png) + + +1. 干线,光缆列表,点击任意光缆,跳转进"光缆类型页"。 +2. 展示【标石、杆号牌】【故障列表】入口按钮。 +3. 点击【标石、杆号牌】按钮,跳转至"标石、杆号牌列表页" +4. 点击【故障列表】按钮,跳转至原故障列表页 + +# 标石、杆号牌列表页 + + ![](attachments/290c3dda-14b9-4a8c-8233-0994b3488cfc.png) + + +1. 展示名称、时间、责任人、导航点、实际里程。 +2. 点击任一区域,跳转至对应"标石、杆号牌详情页"。 +3. 点击【新增】按钮,跳转至"新增标石、杆号牌页"。 + +# 标石、杆号牌详情页 + + ![](attachments/f13df494-322c-4c04-9ee9-693fa4cba2cf.png) + + +1. 展示照片、名称、时间、责任人、导航点、所属公司、实际里程。 +2. 点击【导航】按钮,根据导航点经纬度,拉起导航。 + +# 新增标石、杆号牌页 + + ![](attachments/9c560e3d-6da7-4811-85ec-ffb19b639663.png) + + +1. 点击【拍照】,呼出相机。 +2. 照片增加水印信息:坐标、时间、责任人、所属光缆。 +3. 输入"标石、杆号牌"名称、责任人、实际里程。 +4. 时间,拍照上传后自动填写。 +5. 所属公司,自动填写。 +6. 点击【获取经纬度】按钮,获取当前经纬度。 +7. 点击【提交】按钮,提交信息,自动返回上一级页面。 +8. 管理后台支持增删改。 + +# 搜索结果页 + + ![](attachments/55220979-83e5-4ff3-949a-6cbf5e9053f5.png) + + +1. 搜索结果页,可展示"标石、杆号牌"搜索结果类型。 + +# 光交箱机房详情页 + + +1. 修改光交箱详情页,左右两框的颜色。 +2. 左边为绿色,右边为橙色,参考如下图。 + + ![](attachments/efa7641d-c66b-4702-b1b7-5f5d1cb78f4b.jpg) + +# 管理后台优化 + +## 修改统计 + + +1. 后台新增修改统计功能。 +2. 前端或管理后台新增、修改、删除ODF、干线内容时,可在管理后台查看记录。 + + + 1. 可查看修改前后的对比数据。 + 2. 记录包含修改人、时间、具体修改内容、从哪个端修改。 + 3. 可根据时间查看。 + +## 组织架构权限 + + +1. 每个账号,只能看到自己所属公司的信息。 +2. 上级公司账号,可查看本公司、所属下级公司的信息。 + + + 1. 干线故障,现在后台能看见所有的信息,没有进行分公司隔离,需进行公司隔离。 +3. 前端查看"机房"内容时,该账号的权限为"仅查看""修改和查看"时,权限不正确,应同步修改干线时的"仅查看""修改和查看"账号权限。 + + + 1. 现在"仅查看"权限,能对"机房"内容修改,应只能查看。 +4. 分公司新增"分公司管理员"权限,能查看本公司及下属公司信息、能新增所属分公司、下级公司人员账号。 + + + 1. 分公司中,只有分公司管理员账号允许登录管理后台。 \ No newline at end of file diff --git a/docs/1.2.0/attachments/290c3dda-14b9-4a8c-8233-0994b3488cfc.png b/docs/1.2.0/attachments/290c3dda-14b9-4a8c-8233-0994b3488cfc.png new file mode 100644 index 0000000..6fb048b Binary files /dev/null and b/docs/1.2.0/attachments/290c3dda-14b9-4a8c-8233-0994b3488cfc.png differ diff --git a/docs/1.2.0/attachments/55220979-83e5-4ff3-949a-6cbf5e9053f5.png b/docs/1.2.0/attachments/55220979-83e5-4ff3-949a-6cbf5e9053f5.png new file mode 100644 index 0000000..161a5cd Binary files /dev/null and b/docs/1.2.0/attachments/55220979-83e5-4ff3-949a-6cbf5e9053f5.png differ diff --git a/docs/1.2.0/attachments/895d5b87-4235-4a0d-a6a4-a0ce8cc82d18.png b/docs/1.2.0/attachments/895d5b87-4235-4a0d-a6a4-a0ce8cc82d18.png new file mode 100644 index 0000000..42fd60b Binary files /dev/null and b/docs/1.2.0/attachments/895d5b87-4235-4a0d-a6a4-a0ce8cc82d18.png differ diff --git a/docs/1.2.0/attachments/9c560e3d-6da7-4811-85ec-ffb19b639663.png b/docs/1.2.0/attachments/9c560e3d-6da7-4811-85ec-ffb19b639663.png new file mode 100644 index 0000000..d0e979a Binary files /dev/null and b/docs/1.2.0/attachments/9c560e3d-6da7-4811-85ec-ffb19b639663.png differ diff --git a/docs/1.2.0/attachments/efa7641d-c66b-4702-b1b7-5f5d1cb78f4b.jpg b/docs/1.2.0/attachments/efa7641d-c66b-4702-b1b7-5f5d1cb78f4b.jpg new file mode 100644 index 0000000..a21713e Binary files /dev/null and b/docs/1.2.0/attachments/efa7641d-c66b-4702-b1b7-5f5d1cb78f4b.jpg differ diff --git a/docs/1.2.0/attachments/f13df494-322c-4c04-9ee9-693fa4cba2cf.png b/docs/1.2.0/attachments/f13df494-322c-4c04-9ee9-693fa4cba2cf.png new file mode 100644 index 0000000..89ef0c3 Binary files /dev/null and b/docs/1.2.0/attachments/f13df494-322c-4c04-9ee9-693fa4cba2cf.png differ diff --git a/odf-uniapp/components/port-edit-dialog.vue b/odf-uniapp/components/port-edit-dialog.vue index 1a33018..64eede2 100644 --- a/odf-uniapp/components/port-edit-dialog.vue +++ b/odf-uniapp/components/port-edit-dialog.vue @@ -24,9 +24,9 @@