初始提交

This commit is contained in:
2026-06-21 10:00:13 +08:00
commit 7a5dc32672
1441 changed files with 266348 additions and 0 deletions
@@ -0,0 +1,70 @@
## 概览
- 新增两个对外页面:`/ticket-search`(车票查询/详情)与`/ticket-order`(线上预定)
- 后端增加“线上预定/凭证”API,售票机支持“NEW/ONLINE”两模式,线上凭证在当天有效
- 页面样式统一沿用现有控制台风格(`web/style.css`),Minecraft 端所有文案保持英文
## 后端改动(Node/Express
- 新增数据文件:`web/data/orders.json`(列表)、`web/data/order_index.json`(按码索引)
- 新增接口:
- `POST /api/public/orders`:创建线上预定,入参:`start``terminal``train_type``trips``ride_date`YYYY-MM-DD)。生成唯一5位字母数字凭证 `code`,返回 `{ ok:true, code, price }`。价格通过现有票价数据计算(普通/特急),并按当前促销折扣应用(与`/api/public/config`一致)。
- `GET /api/public/orders/:code`:查询凭证详情,返回 `{ code, start, terminal, train_type, trips, ride_date, price, created_ts, consumed:false }`
- `POST /api/public/orders/:code/consume`:兑票后标记消费(幂等),防重复使用;返回 `{ ok:true }`
- `GET /api/public/popular`:根据现有售票事件日志(`web/data/ticket_events.jsonl``type:'sale'`)统计近7天或全部的热门站点与热门路线,返回 `{ topStations: [{name, code, count}], topRoutes: [{from,to,count}] }`
- 路由与静态文件:
- 追加服务器路由以兼容直链:`GET /ticket-search/:id``GET /ticket-search` 均返回同一静态页面文件(`web/ticket-search.html`);页面端通过 `location.pathname` 识别 `:id` 并拉取数据。
- 同理为 `GET /ticket-order` 返回 `web/ticket-order.html`
- 复用/对齐:价格计算逻辑沿用控制台已有数据源与折扣(`server.js` 已持久化 `stations/lines/fares``promotion`)。
## 前端页面
- `web/ticket-search.html` + `web/ticket-search.js`
- 顶部搜索栏(支持模糊匹配,匹配票号、起点、终点、站点编号)。调用 `GET /api/public/tickets?q=...` 渲染列表,点击进入详情。
- 详情视图:支持直链 `ticket.fse-media.group/ticket-search/XXXX`,通过 `GET /api/public/tickets/:id` 展示“概览+事件时间线”。
- 辅助区块:热门站点与热门路线,调用 `GET /api/public/popular`,以卡片或列表展示。
- 样式统一使用 `web/style.css` 的卡片/列表/按钮体系。
- `web/ticket-order.html` + `web/ticket-order.js`
- 流程:选择起点/终点(下拉+模糊搜索)、车型(普通/特急)、乘次、乘车日期(日期选择器)。右侧实时显示价格(调用 `GET /api/public/fares/query` 并应用折扣)。
- 点击“生成凭证”后调用 `POST /api/public/orders`,展示返回的 5 位字母数字码及说明:“到游戏内售票机付款”。
- 提供“复制凭证码”、“查看我的凭证详情”按钮(跳到 `/ticket-search/:code`)。
## 售票机 Lua 改动
- 首页两按钮:`NEW`(线下购买)与 `ONLINE`(线上兑票)。位置/大小与现有 `Start` 等同(修改 `showHome`),其余流程保持英文。
- 新增页面:线上凭证输入与验证
- 屏幕键盘(AZ、09、Backspace、Clear、OK),输入 5 位码;UI使用既有 `addButton`/`waitButtons` 组件。
- 验证逻辑:
- `GET http://ticket.fse-media.group/api/public/orders/:code`(或由 `config.json``api_base` 指到生产域),若返回存在且 `ride_date == os.date('%Y-%m-%d')` 且未 `consumed`,则有效。
- 有效则将 `state.departure``state.terminal``state.trainType``state.trips``state.cost` 赋值并跳转到订单确认/支付页;支付逻辑与线下一致。
- 无效弹英文提示:`Invalid voucher`
- 兑票完成后调用 `POST /api/public/orders/:code/consume` 标记已使用。
- 变更点位置参考:
- 首页按钮处:在 `Lua/TicketMachine/startup.lua:805..822``showHome`,替换 `Start``NEW``ONLINE` 两个 `addButton`,分别进入现有线下流程与新逻辑。
- 新增函数如 `showOnlineVoucher()`:与 `showOrderAndAudio()` 类似结构,添加键盘与HTTP校验后复用订单页。
- HTTP 使用已存在封装:`fetchHTTP()``jsonDecode()``startup.lua:191..198`, `186..189`)。
## 域名与HTTP访问
- 站点部署到 `ticket.fse-media.group`,售票机需允许该域名的HTTP访问:
- Minecraft 1.13+:在 `serverconfig/computercraft-server.toml` 中移除或调整 `[[http.rules]] host = "$private" action = "deny"`(参见 Tweaked CC 文档)。
- 老版本或单机不同路径,参考提供的文档片段。
- 售票机 `config.json``API_ENDPOINT.txt` 指向生产 API 基础地址,`startup.lua``API_BASE` 也将改为生产地址。
## 文案与样式约定
- Web 前端:中文页面与控件;
- CC:T 端所有提示、按钮、错误信息统一英文(现有实现已如此,新增页面按该规范)。
- 整体风格沿用 `web/style.css` 控制台样式(深色/浅色模式兼容)。
## 交付物
- 新增/修改的文件:
- `web/ticket-search.html`, `web/ticket-search.js`
- `web/ticket-order.html`, `web/ticket-order.js`
- `web/server.js`(新增`orders`/`popular`接口与静态路由)
- `web/data/orders.json`, `web/data/order_index.json`
- `Lua/TicketMachine/startup.lua`(首页按钮与线上凭证流程)
## 验证
- 后端:本地启动后用 `GET /api/public/popular``POST /api/public/orders``GET /api/public/orders/:code` 联调;
- 前端:打开 `/ticket-order` 生成凭证 → 复制码直链查看 `/ticket-search/:code`
- 售票机:触发 `ONLINE` 流程,输入码验证跨天逻辑与支付流程,兑票后标记消费成功。
## 兼容/风险控制
- 所有新增逻辑均以新文件/新接口为主,避免破坏现有控制台;
- 前端/后端的模糊搜索初期采用子串匹配,后续可替换为更精细的打分;
- 若 HTTP 被禁,售票机将回退到线下流程,界面提示网络不可用。