# 交互式命令
**本文引用的文件**
- [src/command/index.ts](file://src/command/index.ts)
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts)
- [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts)
- [src/command/handlers/start.ts](file://src/command/handlers/start.ts)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts)
- [package.json](file://package.json)
## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)
## 简介
本文件聚焦于交互式命令的实现与设计,围绕以下命令展开:
- /events:列出最近的摄影活动,并以“/event_{id}”链接引导查看详情
- /event_{id}:展示活动详情、时间槽与预约入口
- /history:展示用户的预约历史,并提供“/cancel_{booking_id}”取消入口
- /book_{event_id}_{slot_index}:基于回调的优惠券选择与最终预约
- /login、/logout:认证与凭证管理
- /cancel_{booking_id} 及确认回调:取消流程的二次确认
文档将深入解释动态参数(正则表达式匹配与参数解析)、命令与用户交互的设计模式(分页/菜单/状态保持),并提供开发模板与用户体验优化建议。
## 项目结构
该项目采用按功能模块划分的目录结构,命令注册集中在入口文件,各命令处理器位于独立文件中,底层通过客户端封装调用第三方 API。
```mermaid
graph TB
subgraph "命令层"
IDX["src/command/index.ts"]
H1["handlers/events.ts"]
H2["handlers/eventDetails.ts"]
H3["handlers/history.ts"]
H4["handlers/bookEvent.ts"]
H5["handlers/login.ts"]
H6["handlers/cancel.ts"]
H7["handlers/logout.ts"]
H8["handlers/start.ts"]
end
subgraph "客户端"
C1["src/client/cosmoe.ts"]
end
IDX --> H1
IDX --> H2
IDX --> H3
IDX --> H4
IDX --> H5
IDX --> H6
IDX --> H7
IDX --> H8
H1 --> C1
H2 --> C1
H3 --> C1
H4 --> C1
H5 --> C1
H6 --> C1
H7 --> C1
```
图表来源
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L1-L27)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L1-L61)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L1-L107)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L1-L226)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L1-L75)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L1-L132)
- [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts#L1-L34)
- [src/command/handlers/start.ts](file://src/command/handlers/start.ts#L1-L6)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503)
章节来源
- [src/command/index.ts](file://src/command/index.ts#L1-L110)
- [package.json](file://package.json#L1-L24)
## 核心组件
- 命令注册与路由
- 在入口文件中安装对话插件与 KV 存储,注册命令与正则监听器,绑定回调处理器
- 事件列表与详情
- 列表命令返回最近若干活动,详情命令解析动态路径并渲染时间槽与预约入口
- 预约与优惠券
- 通过回调键盘展示多张可用优惠券,支持“无优惠券”选项
- 历史与取消
- 历史命令读取用户凭证并拉取历史,提供取消入口;取消流程二次确认
- 认证与登出
- 对话式登录,KV 存储凭证;登出删除凭证
章节来源
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L1-L27)
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L1-L61)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L1-L107)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L1-L226)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L1-L75)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L1-L132)
- [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts#L1-L34)
## 架构总览
整体采用“命令入口 + 处理器 + 客户端 + KV 存储”的分层架构。命令入口负责路由与上下文管理,处理器负责业务逻辑与用户交互,客户端封装 API 调用,KV 存储用于会话与凭证持久化。
```mermaid
graph TB
U["用户"]
B["Telegram Bot"]
C["命令入口
src/command/index.ts"]
E["事件列表处理器
events.ts"]
D["事件详情处理器
eventDetails.ts"]
Y["历史处理器
history.ts"]
BK["预约处理器
bookEvent.ts"]
L["登录处理器
login.ts"]
X["取消处理器
cancel.ts"]
LOG["登出处理器
logout.ts"]
CL["Cosmoe 客户端
src/client/cosmoe.ts"]
KV["KV 存储
COSMOE_STORAGE/COSMOE_CREDENTIALS"]
U --> B
B --> C
C --> E
C --> D
C --> Y
C --> BK
C --> L
C --> X
C --> LOG
E --> CL
D --> CL
Y --> CL
BK --> CL
L --> CL
X --> CL
LOG --> CL
C --> KV
L --> KV
Y --> KV
BK --> KV
X --> KV
LOG --> KV
```
图表来源
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L113-L503)
## 详细组件分析
### /events:最近活动列表
- 功能要点
- 调用客户端获取活动列表,取最新若干条
- 将每条活动拼接为“/event_{id}”的可点击链接,便于跳转详情
- 参数与路由
- 命令形式:/events
- 输出包含动态链接,用户点击后进入 /event_{id}
- 错误处理
- 空数据时提示无活动;异常时提示网络错误
- 用户体验
- 限制输出数量,避免过长消息
- 使用 Markdown 格式增强可读性
```mermaid
sequenceDiagram
participant U as "用户"
participant B as "Bot"
participant H as "handleEventsCommand"
participant CL as "CosmoeClient"
U->>B : "/events"
B->>H : 调用处理器
H->>CL : 获取活动列表
CL-->>H : 返回结果
H->>U : 发送最近活动列表含 /event_{id} 链接
```
图表来源
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L1-L27)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L177-L184)
章节来源
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L1-L27)
### /event_{id}:活动详情与预约入口
- 动态参数解析
- 使用正则 /^\/event_(.+)$/ 提取 id
- 业务逻辑
- 拉取活动详情,排序时间槽,判断是否可预约(剩余位数>0且活动未过期)
- 对每个可预约时间槽生成“/book_{event_id}_{slot_index}”的预约入口
- 时间与状态
- 使用北京时间(UTC+8)比较活动日期与当前时间,决定是否激活预约入口
- 错误处理
- 详情接口失败时提示错误;异常时统一兜底
```mermaid
sequenceDiagram
participant U as "用户"
participant B as "Bot"
participant H as "handleEventDetails"
participant CL as "CosmoeClient"
U->>B : "/event_{id}"
B->>H : 解析 id 并调用处理器
H->>CL : 获取活动详情
CL-->>H : 返回详情含时间槽
H->>U : 发送活动详情与可预约入口
```
图表来源
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L1-L61)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L191-L199)
章节来源
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L1-L61)
### /history:预约历史与取消入口
- 动态参数解析
- 无需动态参数,直接读取上下文中的用户标识
- 凭证与鉴权
- 从 KV 中读取用户凭证,设置到客户端;若未登录则提示先登录
- 数据处理
- 拉取历史,按时间倒序取前若干条,格式化输出
- 对可取消的历史项生成“/cancel_{booking_id}”入口
- 时间与状态
- 使用北京时间比较活动日期与当前时间,仅对未完成且未来日期的记录开放取消
- 错误处理
- 无历史、鉴权失败、接口异常均给出明确提示
```mermaid
sequenceDiagram
participant U as "用户"
participant B as "Bot"
participant H as "handleHistoryCommand"
participant KV as "KV 存储"
participant CL as "CosmoeClient"
U->>B : "/history"
B->>H : 调用处理器
H->>KV : 读取用户凭证
KV-->>H : 返回凭证
H->>CL : 设置凭证并获取历史
CL-->>H : 返回历史
H->>U : 发送历史列表含可取消入口
```
图表来源
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L1-L107)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L226-L239)
章节来源
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L1-L107)
### /book_{event_id}_{slot_index}:预约与优惠券选择
- 动态参数解析
- 使用正则 /^\/book_(\d+)_(\d+)$/ 提取 event_id 与 slot_index
- 凭证校验
- 从 KV 读取用户凭证,设置到客户端;未登录则提示先登录
- 时间槽校验
- 重新拉取活动详情,排序时间槽,校验索引有效性与剩余位数
- 优惠券策略
- 若存在多张可用优惠券,弹出内联键盘供用户选择;支持“不使用优惠券”
- 若仅一张或无优惠券,则自动使用或不使用
- 最终预约
- 调用客户端执行预约,返回最终价格、预约编号等信息
```mermaid
sequenceDiagram
participant U as "用户"
participant B as "Bot"
participant H as "handleBookEvent"
participant KV as "KV 存储"
participant CL as "CosmoeClient"
U->>B : "/book_{event_id}_{slot_index}"
B->>H : 解析参数并调用处理器
H->>KV : 读取用户凭证
KV-->>H : 返回凭证
H->>CL : 设置凭证并获取活动详情
CL-->>H : 返回详情含时间槽
alt 多张优惠券
H->>U : 弹出优惠券选择键盘
U->>B : 回调选择优惠券
B->>H : 触发优惠券选择回调
else 单张/无优惠券
H->>CL : 执行预约
CL-->>H : 返回预约结果
end
H->>U : 发送预约成功/失败信息
```
图表来源
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L1-L226)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L247-L270)
章节来源
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L1-L226)
### /login:对话式登录与凭证存储
- 交互模式
- 使用对话插件,分步询问用户名与密码,等待用户输入
- 凭证管理
- 成功获取 token 后,将 user_id、token、时间戳写入 KV,键为 Telegram 用户 id
- 错误处理
- 输入缺失、认证失败、KV 写入异常均有相应提示
```mermaid
sequenceDiagram
participant U as "用户"
participant B as "Bot"
participant C as "对话插件"
participant H as "handleInteractiveLogin"
participant CL as "CosmoeClient"
participant KV as "KV 存储"
U->>B : "/login"
B->>C : 进入 login 对话
C->>H : 触发对话处理器
H->>U : 请求用户名
U->>C : 输入用户名
H->>U : 请求密码
U->>C : 输入密码
H->>CL : 获取 token
CL-->>H : 返回 token
alt 成功
H->>KV : 写入凭证
KV-->>H : 成功
H->>U : 登录成功提示
else 失败
H->>U : 登录失败提示
end
```
图表来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L1-L75)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L124-L140)
章节来源
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L1-L75)
### /cancel_{booking_id} 与确认回调:取消流程
- 动态参数解析
- 使用正则 /^\/cancel_(\d+)$/ 提取 booking_id
- 取消入口生成
- 在历史命令中对可取消的记录生成“/cancel_{booking_id}”入口
- 二次确认
- 弹出“确认/取消”内联键盘;用户点击“确认”触发回调
- 回调处理
- 解析回调动作,读取凭证,调用取消接口,更新消息文本反馈结果
```mermaid
sequenceDiagram
participant U as "用户"
participant B as "Bot"
participant H1 as "handleCancelCommand"
participant H2 as "handleCancelConfirmation"
participant KV as "KV 存储"
participant CL as "CosmoeClient"
U->>B : "/cancel_{booking_id}"
B->>H1 : 解析参数并调用处理器
H1->>KV : 读取用户凭证
KV-->>H1 : 返回凭证
H1->>CL : 设置凭证并获取历史
CL-->>H1 : 返回历史
H1->>U : 发送取消确认键盘
U->>B : 点击“确认”
B->>H2 : 触发回调处理器
H2->>KV : 读取用户凭证
KV-->>H2 : 返回凭证
H2->>CL : 取消预约
CL-->>H2 : 返回结果
H2->>U : 更新消息为成功/失败
```
图表来源
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L1-L132)
- [src/client/cosmoe.ts](file://src/client/cosmoe.ts#L405-L422)
章节来源
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L1-L132)
### /logout:登出与凭证清理
- 行为
- 读取 KV 中的用户凭证,存在则删除,不存在则提示先登录
- 错误处理
- KV 读取/删除异常时统一提示
章节来源
- [src/command/handlers/logout.ts](file://src/command/handlers/logout.ts#L1-L34)
### /start:欢迎与命令指引
- 行为
- 返回欢迎语与可用命令列表,便于新用户快速上手
章节来源
- [src/command/handlers/start.ts](file://src/command/handlers/start.ts#L1-L6)
## 依赖关系分析
- 插件与存储
- 使用 @grammyjs/conversations 提供对话能力,@grammyjs/storage-cloudflare 提供 KV 存储适配
- 命令入口中自定义 KV 读写包装,确保 JSON 序列化/反序列化一致性
- 客户端依赖
- 所有处理器依赖 CosmoeClient,后者封装 API 调用、鉴权与数据模型
- 命令与回调
- 命令通过正则监听器接收动态参数;回调通过内联键盘触发,解析动作字符串
```mermaid
graph LR
P["@grammyjs/conversations"] --> IDX["src/command/index.ts"]
S["@grammyjs/storage-cloudflare"] --> IDX
IDX --> H1["events.ts"]
IDX --> H2["eventDetails.ts"]
IDX --> H3["history.ts"]
IDX --> H4["bookEvent.ts"]
IDX --> H5["login.ts"]
IDX --> H6["cancel.ts"]
IDX --> H7["logout.ts"]
H1 --> C["src/client/cosmoe.ts"]
H2 --> C
H3 --> C
H4 --> C
H5 --> C
H6 --> C
H7 --> C
```
图表来源
- [src/command/index.ts](file://src/command/index.ts#L1-L11)
- [package.json](file://package.json#L18-L22)
章节来源
- [src/command/index.ts](file://src/command/index.ts#L1-L11)
- [package.json](file://package.json#L18-L22)
## 性能考量
- 消息长度控制
- 历史命令在发送前截断超长内容,避免 Telegram API 限制
- 数据量限制
- 列表与历史默认只取最近若干条,降低渲染与传输成本
- KV 访问
- 登录/取消/预约等关键流程均需 KV 读写,应关注并发与延迟;可考虑缓存短期会话状态
- 网络请求
- 客户端封装统一的 fetch 调用,建议在高频场景下增加本地缓存与去抖策略
章节来源
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L94-L98)
- [src/command/handlers/events.ts](file://src/command/handlers/events.ts#L9-L10)
## 故障排查指南
- 常见问题定位
- 动态参数解析失败:检查正则是否与用户输入一致(如 /event_123、/book_1_0)
- 未登录:KV 中无凭证或凭证失效,需先执行 /login
- 接口异常:客户端返回非 200 或数据结构变化,需查看具体错误消息
- KV 读写异常:检查命名空间权限与键名一致性
- 日志与回退
- 处理器中对异常进行捕获并回复友好提示,便于用户自助排查
- 建议
- 为关键流程添加重试与降级策略(如网络波动时的缓存读取)
章节来源
- [src/command/handlers/eventDetails.ts](file://src/command/handlers/eventDetails.ts#L23-L26)
- [src/command/handlers/history.ts](file://src/command/handlers/history.ts#L103-L106)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L114-L117)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L80-L83)
## 结论
该交互式命令体系通过清晰的命令路由、正则参数解析与回调交互,实现了从活动浏览、详情查看、预约下单到历史管理与取消的完整闭环。结合 KV 存储与对话插件,既保证了状态保持,也提升了用户体验。后续可在消息分页、批量操作、错误重试等方面进一步优化。
## 附录
### 交互式命令开发模板
- 命令注册
- 在命令入口中注册命令/正则监听器与回调
- 绑定环境变量(KV、Bot 信息等)
- 处理器骨架
- 解析动态参数(正则/上下文)
- 校验登录状态与凭证有效性
- 调用客户端获取/提交数据
- 构造消息与内联键盘(必要时)
- 错误处理与用户提示
- 回调处理
- 解析回调动作字符串
- 读取上下文与 KV
- 更新消息文本或编辑消息
- 模板参考
- 参考现有处理器的结构与错误处理模式
章节来源
- [src/command/index.ts](file://src/command/index.ts#L20-L110)
- [src/command/handlers/login.ts](file://src/command/handlers/login.ts#L12-L75)
- [src/command/handlers/bookEvent.ts](file://src/command/handlers/bookEvent.ts#L11-L226)
- [src/command/handlers/cancel.ts](file://src/command/handlers/cancel.ts#L11-L84)
### 用户体验优化建议
- 分页与滚动
- 当列表较长时,采用分页或“加载更多”按钮,减少单次消息长度
- 状态保持
- 使用对话插件与 KV 存储保持上下文,避免重复输入
- 反馈与通知
- 关键操作(登录、预约、取消)提供即时反馈与可追踪的 ID
- 可访问性
- 文案简洁明确,提供“取消/返回”等兜底选项
- 错误恢复
- 对网络异常与参数错误提供重试与引导,避免用户卡死