# 航线库编辑 / 删除设计 日期:2026-09-01 状态:已批准(对话确认) 范围:`laic-frontend` 航线库前端能力补齐 ## 背景 任务管理 → 航线库当前仅支持: - 列表展示与搜索 - 新建航线(地图点选航点 → `POST /v1/routes`) 卡片 `RouteCard` 为纯展示,无编辑 / 删除入口。 后端已具备完整 CRUD: | 能力 | 接口 | |------|------| | 列表 | `GET /v1/routes` | | 详情 | `GET /v1/routes/:id` | | 新建 | `POST /v1/routes` | | 更新 | `PUT /v1/routes/:id`(`waypoints` 有值则整体替换) | | 删除 | `DELETE /v1/routes/:id` | 缺口仅在前端接线。 ## 目标 1. 航线卡片提供 **编辑**、**删除** 操作。 2. 编辑复用现有航线编辑器(地图 + 航点侧栏),不新建第二套 UI。 3. 删除需二次确认。 4. 新建路径行为保持不变。 ## 非目标 - 航线复制、导入 / 导出、只读详情页 - 任务占用拦截(后端未暴露占用校验时前端不做) - 管理端特殊权限 UI(沿用接口 401/403) - 后端改动 - `description` 字段(当前新建流程也未采集) ## 交互 ### 列表卡片 - 每张 `RouteCard` 增加操作区:**编辑**、**删除** - 布局:卡片内容下方操作条(对齐设备 / 任务 `.row-actions` 文字按钮风格) - 删除使用危险色(`theme="danger"`) - 不采用「整卡点击进编辑」;操作显式按钮,避免误触 ### 编辑 1. 点击「编辑」 2. 请求 `GET /v1/routes/:id` 3. 成功后打开现有 `route-editor`: - 标题:`编辑航线` - 主按钮:`保存修改`(保存中:`保存中…`) 4. 回填: - 航线名称 - 航点列表与地图轨迹 - 默认高度 / 速度:取首航点;无航点时回退 `50` / `10` - `turnMode`:`holdSec > 0` → `stop`,否则 `auto` 5. 编辑器内仍可增删改航点、撤销、清空、应用到全部航点(与新建相同) 6. 保存校验与新建一致: - 名称必填 - 至少 2 个航点 7. 提交 `PUT /v1/routes/:id`,body: ```json { "name": "...", "waypoints": [ { "longitude": 0, "latitude": 0, "altitude": 0, "speed": 0, "yaw": 0, "holdSec": 0 } ] } ``` 8. 成功:toast「航线已更新」→ 关闭编辑器 → 刷新列表 9. 失败:编辑器内 `routeFormError` 展示错误,不关闭 ### 删除 1. 点击「删除」 2. `ui.confirm`: - 标题:`确认删除航线「{name}」?` - 说明:删除后不可恢复;已绑定该航线的任务需自行处理(简短文案即可) 3. 确认后 `DELETE /v1/routes/:id` 4. 成功:toast「航线已删除」→ 刷新列表 5. 失败:toast 错误信息 6. 删除入口仅在卡片;编辑器内不放删除(按已选交互) ### 新建(不变) - `editingRouteId = null` - 标题仍为「新建航线」 - 主按钮仍为「保存航线」 - 仍 `POST /v1/routes` ## 数据流与状态 ### URL `src/config/urls.js` 增补: ```js export const ROUTES = '/v1/routes' export const ROUTE = (id) => `/v1/routes/${id}` ``` ### 视图状态(TasksView) | 状态 | 含义 | |------|------| | `editingRouteId` | `null` = 新建;非空 = 正在编辑的航线 id | | `routeEditorOpen` | 编辑器显隐(已有) | | `routeForm` / `routePoints` | 已有表单与航点 | | `routeSaving` | 保存中禁用(已有) | 生命周期: - `openRouteEditor()`:reset → `editingRouteId=null` → open(新建) - `openRouteEditorForEdit(route)`:reset → GET 详情 → 填表 → `editingRouteId=id` → open - `closeRouteEditor()`:teardown map → close → `editingRouteId=null` + reset - `submitRoute()`:按 `editingRouteId` 分支 POST / PUT - `deleteRoute(route)`:confirm → DELETE → reload ### 航点映射 ``` API → UI: longitude/latitude/altitude/speed 原样 Number turnMode = holdSec > 0 ? 'stop' : 'auto' UI → API: yaw = 0 holdSec = turnMode === 'stop' ? 1 : 0 ``` 与现有 `submitRoute` 映射保持一致。 `PUT` **始终**携带全量 `waypoints`,触发后端整体替换。 ### 列表映射注意 当前列表用分页 records 映射卡片;列表项可能不含完整 waypoints(取决于后端 page 是否 embed)。 - 列表展示:继续用现有 fields(name、waypoints 计数、distance、collectedAt) - 编辑回填:**必须以详情接口为准**,不信任列表里的精简数据 - 若列表无 waypoints 导致 distance/`waypoints` 计数为 0,属既有问题,本需求不强制修 page API;编辑保存后 `load()` 刷新 ## 组件改动 ### `RouteCard.vue` Props 保持展示字段;新增: - emit:`edit`、`delete` - 模板底部操作条:编辑(primary text)、删除(danger text) - 点击操作 `@click.stop`,避免未来卡片可点时冒泡 ### `TasksView.vue` - 绑定 `@edit` / `@delete` - 实现上述 open/submit/delete 逻辑 - 编辑器 header 文案随 `editingRouteId` 切换 ### `prototype.css`(或 RouteCard 局部样式) - `.route-card-actions`:flex、间距、与卡片底部分隔 - 对齐现有 `.row-actions` 观感,不引入新视觉体系 ## 错误处理 | 场景 | 行为 | |------|------| | 详情加载失败 | toast,不打开编辑器 | | 保存校验失败 | editor 内错误文案 | | 保存接口失败 | editor 内错误文案,保持编辑态 | | 删除取消 | 无副作用 | | 删除接口失败 | toast | | 401/403 | 走现有 axios 拦截器 | ## 验收标准 1. 航线库卡片可见「编辑」「删除」。 2. 编辑:名称与航点回填正确,地图显示轨迹。 3. 修改后保存:列表名称 / 航点数更新。 4. 删除确认后卡片从列表消失。 5. 新建航线流程与文案不受影响。 6. 保存中按钮禁用,防止重复提交。 ## 测试建议 - 手工:本地 / 远端各走一遍新建、编辑、删除。 - 无需新增自动化测试套件(项目现无前端单测约定);若后续有 component test 基建再补。 ## 实现顺序建议 1. `urls.ROUTE` 2. `RouteCard` 操作 UI + emit 3. TasksView:delete 4. TasksView:edit open + submit 分支 5. 样式微调 6. 手工验收