前端结构
修改记录
日期 |
变更 |
|---|---|
2026-07-18 |
全量重写:同步实际代码结构,新增数据流图与交叉引用 |
1. 架构总览
前端为 Vue 3 + TypeScript + Vite SPA,状态管理使用 Pinia(setup 语法),HTTP 客户端使用 Axios,路由使用 Vue Router(hash-free history 模式)。
架构特点:
全量 TypeScript:frontend/src 下全部为 .ts / .vue 文件,API 类型由 openapi-typescript 从后端 OpenAPI 规范生成
Composable 模式:将 POI 搜索、编辑表格、打字机效果等分离为独立 composable
SSE 流式渲染:Agent 聊天使用 EventSource 实现打字机效果
模块化组件:地图(AmapMap)、行程(SchedulePanel)、聊天(ChatMessage)互相独立
2. 目录结构
frontend/
├── index.html # SPA 入口 HTML
├── vite.config.js # Vite 构建配置 + /api 代理
├── tsconfig.json # TypeScript 配置
├── eslint.config.js # ESLint 扁平化配置
├── package.json # 依赖与脚本
├── .npmrc # npm 镜像配置
├── .prettierrc # Prettier 格式化配置
│
├── public/ # 公共静态资源
├── dist/ # 构建产物(gitignored)
│
└── src/
├── main.ts # Vue 应用入口(挂载 Pinia + Router)
├── App.vue # 根组件:全局导航栏 + <router-view>
├── style.css # 全局样式
│
├── pages/ # 页面级组件(5 个路由页面)
│ ├── HomePage.vue 首页:城市输入 + 参数配置
│ ├── SuggestPage.vue 方案建议列表(ca_suggest 结果展示)
│ ├── PlanPage.vue 核心规划展示页(地图 + 行程 + 评语)
│ ├── AgentPage.vue LLM Agent 聊天页(SSE 流式对话)
│ └── HistoryPage.vue 历史记录分享站(API 分页列表)
│
├── components/ # 可复用组件
│ ├── AmapMap.vue 高德 2D 地图(路线 + 景点标记)
│ ├── SchedulePanel.vue 每日行程表(折叠 + 高显联动)
│ └── ChatMessage.vue 单条聊天消息(打字机效果)
│
├── composables/ # 组合式函数
│ ├── useEditTable.ts 规划点编辑表格(增删改 + 确认)
│ ├── usePoiSearch.ts POI 搜索(自动确认、无需勾选)
│ └── useTypewriter.ts 打字机效果(逐字 + 追加模式)
│
├── router/
│ └── index.ts Vue Router 路由表(5 条懒加载路由)
│
├── services/
│ └── api.ts Axios 封装(7 个后端 API 函数 + History 类型)
│
├── stores/
│ └── plan.ts Pinia store(输入参数 + 方案 + 结果状态)
│
├── types.ts # 手工维护的类型定义
│
└── api/
└── types.generated.ts # openapi-typescript 自动生成(OpenAPI 驱动)
3. 页面组件
全部路由使用懒加载(() => import(...)),5 个页面组件:
HomePage.vue(
/) 城市输入、酒店选择、景点编辑、参数配置(惩罚/起程时间/最小天数),触发/api/suggest。SuggestPage.vue(
/suggest) 展示 ca_suggest 多方案卡片(按天数分组)。 fast 模式前端合成 PlanResult 跳转 /plan;deep 模式调/api/plan后跳转。PlanPage.vue(
/plan) 纯展示页:指标栏(成本/距离/等待)、评语、AmapMap 地图、SchedulePanel 行程表、原始请求参数折叠面板。AgentPage.vue(
/agent)LLM Agent 对话:输入框 + SSE 流式消息列表 + 打字机效果 + 左侧待选栏。 后端协议详见
agent.md。HistoryPage.vue(
/history) 历史记录分页列表,点击拉取完整数据跳转 /plan。
4. 可复用组件
AmapMap.vue(PlanPage) 高德 2D 地图渲染:展示 routes 路线、spots 景点标记、真实 polylines 轨迹。 支持多日高显(
highlightDays)和景点高亮(highlightSpot)。SchedulePanel.vue(PlanPage) 每日行程表:按天折叠/展开,行程项含到达/离开时间及状态。 高显联动展开,地图点击高亮对应景点。
ChatMessage.vue(AgentPage) 单条消息渲染组件:支持打字机逐字效果(
useTypewriter),区分用户/助手角色样式。
5. Composables
useEditTable 管理 HomePage 规划点编辑表格(酒店 + N 景点),维护
editRows临时数组,确认时同步 store。 关键方法:editRows,editHint,confirmEdit,deleteRow。usePoiSearch POI 搜索逻辑:根据城市+名称列表调
postPoiLookup,自动填充坐标和时间窗。 关键方法:searchHotel,searchSpots,loading。useTypewriter 打字机效果:
start(text)逐字播放,append(chunk)SSE 流式追加,reset()清空。 关键方法:displayText,start,append,reset。
6. 状态管理
单一 Pinia store plan(setup 语法),三组状态:
输入状态
字段 |
类型 |
说明 |
|---|---|---|
|
|
城市及酒店 |
|
|
每日启程时间(距午夜分钟数) |
|
|
景点列表(名称/坐标/时间窗/停留) |
|
|
惩罚权重参数 |
|
|
最小天数(null 为引擎自动推断) |
|
|
用户是否已完成参数确认 |
方案状态
字段 |
类型 |
说明 |
|---|---|---|
|
|
ca_suggest 返回到多组方案 |
|
|
suggest 返回的景点字典(含 original_tw) |
|
|
成本/距离矩阵,deep 模式复用 |
|
|
真实路径坐标字典 |
结果状态
字段 |
类型 |
说明 |
|---|---|---|
|
|
当前展示的规划结果 |
|
|
深度模式生成的规划结果列表 |
|
|
从历史加载的记录 ID(防重复分享) |
|
|
历史记录原始请求参数 |
关键方法:buildRequest(nDays) 构造请求体,reset() 清空全部状态。
7. API 层
后端 API base URL 由 Vite 代理(/api → localhost:8000)。
核心 API
函数 |
端点 |
用途 |
|---|---|---|
|
|
批量查询 POI 坐标 / 营业时间 |
|
|
获取多组候选方案(ca_suggest) |
|
|
指定天数执行深度规划(VNS) |
|
|
Agent SSE 流式对话 |
历史记录 API
函数 |
端点 |
用途 |
|---|---|---|
|
|
分页获取历史记录摘要 |
|
|
获取完整规划结果及请求参数 |
|
|
保存当前方案到分享站 |
|
|
删除记录(device_id 鉴权) |
|
纯前端 |
生成/读取匿名设备标识 |
8. 类型定义
类型体系分两层:
api/types.generated.ts ← openapi-typescript 自动生成(后端 schema 驱动)
types.ts ← 手工补充(前端专用类型 + 生成类型的扩展)
类型 |
来源 |
说明 |
|---|---|---|
|
types.ts |
扩展生成的 PlanRequest,增加 cost_matrix/dist_matrix |
|
types.ts |
从 generated 重新导出 |
|
types.ts |
手工维护(ca_suggest 返回结构) |
|
types.ts |
完整规划结果(含 solution/schedules/commentary/polylines) |
|
types.ts |
routes / total_cost / total_dist / valid |
|
types.ts |
单日行程项(到达/离开/状态) |
|
types.ts |
纯前端表单景点项(twStart/twEnd/expectedArrival) |
|
types.ts |
后端返回的景点字典项(x/y/tw/original_tw) |
|
types.ts |
聊天消息(user/assistant) |
9. 构建与配置
配置文件 |
说明 |
|---|---|
|
Vite 构建:Vue 插件、@ 别名、devServer → |
|
TypeScript 严格模式配置 |
|
ESLint 扁平化配置(Flat Config) |
|
Prettier 格式化规则 |
|
npm registry 镜像配置 |
开发命令(通过根目录 Makefile):
make dev # 启动 Vite 开发服务器(port 5173)
make build # 生产构建到 dist/
make lint # ESLint 检查
make typecheck # vue-tsc 类型检查
10. 数据流图
页面间数据流转
HomePage SuggestPage PlanPage
| | |
|-- POST /api/suggest -----------> | |
| ← suggestions + spots | |
| + cost_matrix + dist_matrix | |
| + polylines + amap keys | |
| | |
|-- router.push(/suggest) -------> | |
| | |
| |--- fast: 点击卡片 ---------> |
| | onCardClick(s) |
| | buildPlanResult(s) |
| | store.planResult = ... |
| | router.push(/plan) |
| | |
| |--- deep: 点"获取规划" ----> |
| | POST /api/plan (mode=deep) |
| | ← PlanResult |
| | store.deepResults.push(r) |
| | 再点卡片 → router.push |
| | |
| | PlanPage |
| | 只读 store |
| | 不调 API |
| | |
HistoryPage | |
| | |
|-- GET /api/history --------------| |
|-- 点击: GET /api/history/{id} --| |
| store.planResult = detail | |
| router.push(/plan) ----------->| |
状态流向
buildRequest() → POST /api/suggest → store.suggestions + suggestSpots
+ suggestCostMatrix + suggestPolylines
↓
SuggestPage 分组展示卡片
↓
onCardClick → buildPlanResultFromSuggestion
+ store.suggestSpots ← sugget 响应缓存
+ store.suggestPolylines
↓
store.planResult
↓
PlanPage 渲染
详见 backend.md 第 8 章的引擎链路与规划流程。
11. 与后端交叉引用
HomePage → POST /api/suggest
routes.py suggest→pipeline.run_planning(n_days=None)后端参考:backend.md#7.3SuggestPage → POST /api/plan
routes.py plan→pipeline.run_planning(n_days指定)后端参考:backend.md#7.4AgentPage → POST /api/chat
routes.py chat→agent.planner.PlannerAgent后端参考:backend.md#5PlanPage 渲染数据
pipeline.run_planning返回PlanResult后端参考:backend.md#8.3历史记录 POST /api/history
routes.py create_history后端参考:backend.md#7.5