Browse Source

docs: 航线库编辑删除设计规格

补齐 RouteCard 编辑/删除与复用现有编辑器的前端设计,后端 CRUD 已具备仅接线。
main
xiaosi 3 weeks ago
parent
commit
6d3bd3b5c7
  1. 201
      docs/superpowers/specs/2026-09-01-route-library-edit-delete-design.md

201
docs/superpowers/specs/2026-09-01-route-library-edit-delete-design.md

@ -0,0 +1,201 @@
# 航线库编辑 / 删除设计
日期: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. 手工验收
Loading…
Cancel
Save