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. 优化后台相关功能。
+
+# 标石、杆号牌入口
+
+ 
+
+
+1. 干线,光缆列表,点击任意光缆,跳转进"光缆类型页"。
+2. 展示【标石、杆号牌】【故障列表】入口按钮。
+3. 点击【标石、杆号牌】按钮,跳转至"标石、杆号牌列表页"
+4. 点击【故障列表】按钮,跳转至原故障列表页
+
+# 标石、杆号牌列表页
+
+ 
+
+
+1. 展示名称、时间、责任人、导航点、实际里程。
+2. 点击任一区域,跳转至对应"标石、杆号牌详情页"。
+3. 点击【新增】按钮,跳转至"新增标石、杆号牌页"。
+
+# 标石、杆号牌详情页
+
+ 
+
+
+1. 展示照片、名称、时间、责任人、导航点、所属公司、实际里程。
+2. 点击【导航】按钮,根据导航点经纬度,拉起导航。
+
+# 新增标石、杆号牌页
+
+ 
+
+
+1. 点击【拍照】,呼出相机。
+2. 照片增加水印信息:坐标、时间、责任人、所属光缆。
+3. 输入"标石、杆号牌"名称、责任人、实际里程。
+4. 时间,拍照上传后自动填写。
+5. 所属公司,自动填写。
+6. 点击【获取经纬度】按钮,获取当前经纬度。
+7. 点击【提交】按钮,提交信息,自动返回上一级页面。
+8. 管理后台支持增删改。
+
+# 搜索结果页
+
+ 
+
+
+1. 搜索结果页,可展示"标石、杆号牌"搜索结果类型。
+
+# 光交箱机房详情页
+
+
+1. 修改光交箱详情页,左右两框的颜色。
+2. 左边为绿色,右边为橙色,参考如下图。
+
+ 
+
+# 管理后台优化
+
+## 修改统计
+
+
+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 @@