Files
FSE-Ticket.sys/IC储蓄卡功能开发.md
T
2026-06-21 10:00:13 +08:00

1493 lines
122 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# IC储蓄卡功能开发
> **Workspace:** d:\TaoYuan2023_HSTG\HSTG\Lua\TicketMachine
---
**User**
现在我们新增了一个IC储蓄卡的功能。MOD那边的API是这样的:
IC 卡系统 Lua API
售票机 ticket_vending_machine 新增
方法 | 返回
issueTicket(...) | true, ticketId
issueICCard() | true, cardId
`local ok, cardId = vm.issueICCard(`
充值机 ic_refill_machine
方法 | 参数 | 返回 | 说明
getCardInfo() | 无 | table |卡号/持有者/余额
refill(amount) | 金额 | true, 新余额 | 充值
deduct(amount) | 金额 | true, 新余额 | 扣费
操作流程:手持卡右键方块 → 插入 → CC 操作 → ejectCard() 取出
---
所以要加:
1. `d:\TaoYuan2023_HSTG\HSTG\Lua\TicketMachine\ticketmachine.lua` 添加一个“办卡”的页面。点击按钮后开始办卡。首先输入卡的使用者。输入框下面有26键键盘以及符号键盘。确定之后选择首次充值余额。可以自定义,也可以选择预设:5、10、15、20。然后选择之后就像“购票支付” `d:\TaoYuan2023_HSTG\HSTG\Lua\TicketMachine\ticketmachine.lua#L902-902` 那样付钱充值.完成之后就出卡。把使用者名、余额传入出票机。同时也要向网页端记录该卡。
2. 检票模块:
卡右键检票机,向卡中传入进站的车站编号。出站时通过识别卡中的进站站台编号和当前出站站台编号,计算路费。计算后扣费后向卡中传入新的余额。
其它“已经进站”/“还未进站”等提示照旧
3.网页控制台端。加上新的记录卡信息的/api 地址。然后后台也能看到卡的所有信息(类似车票)。同时也要在公开的页面显示,加入查询的索引。
4. 线上购卡
和线上购票类似,通过线上购卡,然后获得凭证,在computercraft中通过凭证兑卡。
请注意,所有网页的css请按照当前的css风格(模仿JR官网 `https://www.jreast.co.jp/`
**Assistant**
我先梳理现有代码结构,重点看 `ticketmachine.lua` 的购票支付流程、检票模块的进出站逻辑,以及网页端现有的票据 API 和展示页,确认新加 IC 储蓄卡最合适的接入点。
我已做了完整检索,覆盖了售票机主程序、线上预定页、凭证详情页,以及闸机核验侧代码;下面按“页面结构、输入交互、支付、出票、接入点”汇总。
**主流程**
- 主状态机在 [mainPageLoop](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1429-L1444),页面顺序是 `home -> departure -> terminal -> type -> trips -> order -> done`,线上兑票走 `home -> online -> order -> done`
- 首页模式选择在 [showHome](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L693-L732),只有两个入口:`NEW` 新购票、`ONLINE` 凭证兑票
- 站点/线路选择页共用 [renderLinesSelection](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L735-L796),数据来自 `CFG.lines / CFG.stations`
- 订单确认与支付页在 [showOrderAndAudio](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1023-L1154),出票完成页在 [showDone](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1190-L1336)
- 线上凭证输入页在 [showOnlineVoucher](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1338-L1424)
**页面结构**
- `home`:模式选择页,按钮为 `NEW / ONLINE`,进入不同购票链路,见 [showHome](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L693-L732)
- `departure`:选择出发站,见 [showDeparture](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L798-L816)
- `terminal`:选择到达站,禁止同站,见 [showTerminal](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L818-L848)
- `type`:选择 `Local / Express`,见 [showType](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L850-L877)
- `trips`:选择乘次数量,`+/-` 调整,见 [showTrips](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L879-L900)
- `order`:显示区间、车型、次数、金额、支付进度条、确认按钮,见 [drawOrder](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L962-L1021) 与 [showOrderAndAudio](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1023-L1154)
- `done`:真正执行出票/上传后展示票据信息,见 [showDone](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1190-L1336)
- `online`5 位凭证码输入页,见 [showOnlineVoucher](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1338-L1424)
**输入交互**
- 统一按钮机制在 [addButton / waitButtons](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L582-L600),支持 `mouse_click``monitor_touch`
- 全局取消弹窗在 [renderConfirmCancel](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L662-L674),各页通过 `addCancelButton` 接入
- 站点选择通过触摸按钮完成,支持滚动翻页,见 [renderLinesSelection](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L735-L796)
- 线上凭证支持两种输入:屏幕软键盘、实体键盘 `char/backspace/enter`,见 [showOnlineVoucher](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1374-L1420)
- 金额不是文本输入,而是监听右侧红石输入脉冲累加,见 [showOrderAndAudio](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1114-L1129)
**支付流程**
- 票价计算核心在 [computeCost](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L902-L960),基于 `CFG.fares` 构造普通/特急邻接图后跑最短路
- 订单页会先重算价格,避免旧数据残留,见 [showOrderAndAudio](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1023-L1037)
- 支付状态 UI 在 [drawOrder](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L998-L1020),显示 `Paid / Remaining` 与进度条
- 实际“收款”逻辑很简单:每次 `redstone.getInput('right')``false -> true``state.paid += 1`,见 [showOrderAndAudio](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1114-L1129)
- 付满后自动确认;若金额为 0 也会自动确认,见 [confirmAction](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1050-L1082) 与 [auto-confirm](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1108-L1112)
- 当前代码没有接现金/扫码/银行卡 API;支付接入本质上就是把外设回调换成更新 `state.paid`,或重写确认条件
**出票流程**
- 本地新购票:支付满足后 `confirmed=true`,跳到 `done`,见 [showOrderAndAudio](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1050-L1082)
- 线上凭证兑票:确认时先 POST `/public/orders/{code}/consume`,成功后才进入 `done`,见 [consume voucher](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1060-L1074)
- 真正出票发生在 [showDone](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1236-L1249):优先调用外设 `ticket_vending_machine.issueTicket(...)`
- 若外设调用失败,则退化为本地生成票号 [generateTicketId](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1162-L1169)
- 出票后会组装 `ticketDataMod` 并上报 `/tickets/sale`,见 [showDone](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1264-L1308) 与 [uploadTicketRecord](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L223-L246)
- 上传失败会写入 `logs/pending_ticket_upload.jsonl`,后台任务自动补传,见 [enqueueTicketUpload](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L248-L259) 和 [backgroundTicketUploadTask](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L339-L354)
**线上预定关联文件**
- 预定页面结构: [ticket-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ticket-order.html#L120-L244)
- 预定页逻辑: [ticket-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ticket-order.js#L1-L22) 与 [createOrder](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ticket-order.js#L406-L451)
- 凭证详情页结构: [token.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/token.html#L104-L128)
- 凭证详情页逻辑: [token.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/token.js#L37-L57)
- Web 端创建凭证接口:`POST /api/public/orders`,见 [ticket-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ticket-order.js#L418-L420)
- 机台兑票查询接口:`GET /public/orders/{code}`,见 [showOnlineVoucher](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1348-L1370)
**建议接入点**
- 支付外设接入:优先改 [showOrderAndAudio](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1114-L1129),把 `redstone right` 替换为投币器/纸币器/扫码回调,再统一累加到 `state.paid`
- 支付校验扩展:改 [confirmAction](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1050-L1082),可在确认前增加第三方支付结果查询、超时撤单、退款判断
- 出票设备接入:改 [showDone](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1236-L1249),当前已预留 `ticket_vending_machine.issueTicket(...)`,这是最直接硬件接入点
- 售票上报接入:改 [uploadTicketRecord](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L223-L246),适合补充订单号、支付渠道、设备编号、流水号
- 线上订单联动:改 [showOnlineVoucher.submitCode](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1348-L1370) 与 [consume voucher](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1060-L1074),适合加预锁定、核销前校验、重复兑票保护
- 闸机验票联动:下游在 [gate.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua),用于票据进出站核验,适合作为出票后全链路闭环入口
**结论**
- `ticketmachine.lua` 已具备完整页面状态机、触摸/键盘交互、基础支付累加、出票外设调用、售票上传与离线补传
- 当前最薄弱的部分是“支付”,本质仍是右侧红石脉冲计数,不是真正支付网关
- 最推荐的三个接入点是:`showOrderAndAudio` 的支付监听、`confirmAction` 的核销确认、`showDone``issueTicket` 外设调用
如果你需要,我下一步可以继续把这些流程整理成一张“页面/状态/事件/接口”的接入表。
已做一轮完整检索,覆盖 `gate.lua`、售票机 Lua、安装脚本,以及与闸机校验直接对应的服务端路由;结论是:当前 Lua 侧已经有比较清晰的“票卡介质适配层”,可直接扩展为 IC 卡接入。
**结论**
- 最核心接入点在 [gate.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L479-L670):闸机不直接操作软盘文件,而是依赖 `ticket_inspection_machine` 外设的事件和方法,这里最适合替换/扩展为 IC 卡读写器。
- 售票/发卡接入点在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1236-L1308):售票机通过 `ticket_vending_machine.issueTicket(...)` 下发票据,可平移为“写 IC 卡初始化数据/发新卡”。
- 进出站状态维护分两层:Lua 侧只做事件接收、服务器请求、回写介质;真正的状态判定和扣次在服务端 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L553-L698)。
- 如果要支持 IC 卡,优先保留现有 HTTP 校验协议不变,只替换 Lua 外设层,改造成本最低。
**进出站状态**
- 闸机模式来自 [loadConfig](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L44-L55),支持单向 `mode=entry/exit`,也支持双向 `side_modes`,见 [gate.lua:L422-L471](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L422-L471)。
- 扫描事件入口是 [ticket_scanned](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L672-L682),参数解析在 [parseTicketScannedArgsPacked](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L530-L545)。
- 进/出站动作选择在 [handleScan](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L554-L618):优先按闸机侧别决定,双向且无侧别时会根据票内 `entered/exited` 推断当前是进站还是出站。
- 票状态字段明确使用 `entered``exited``trips_total``trips_remaining`,见 [gate.lua:L559-L600](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L559-L600) 和 [ticketmachine.lua:L1265-L1279](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1265-L1279)。
**票据读写**
- 读票不是 Lua 自己读文件,而是等待外设抛出 `ticket_scanned` 事件,并从事件里拿 `scan` 表,见 [gate.lua:L530-L545](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L530-L545)。
- 票号读取统一走 [getTicketId](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L319-L340),兼容 `ticketId/ticket_id/id` 多种字段。
- 起终点读取统一走 [getStartStation](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L353-L387),兼容多种字段名,也支持从站名反推站码。
- 验票通过后,Lua 侧对介质回写在 [gate.lua:L632-L659](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L632-L659)`updateTicket("entered"/"exited"/"rides", ...)`,以及必要时 `destroyTicket()`
- 售票写票在 [ticketmachine.lua:L1236-L1249](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1236-L1249):调用 `ticket_vending_machine.issueTicket(...)`,这是发新票/初始化卡片的现成接入点。
**扣费与校验**
- `gate.lua` 自己不做本地票价计算,也不直接扣费;它只向 `/api/tickets/check` 提交 `ticket_id + action + station_codes + trips_*`,见 [postCheck](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L250-L258) 与 [doCheck](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L591-L602)。
- 服务端才是权威校验点:进站校验起点站、是否已进站;出站校验终点站、是否已进站/已出站,并在出站时 `trips_remaining - 1`,见 [api.js:L650-L697](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L650-L697)。
- 服务端返回 `resp.trips_remaining``resp.destroy_ticket`,Lua 再把剩余次数写回票介质,见 [gate.lua:L632-L659](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L632-L659)。
- 售票后会把票据记录上传到后端,见 [enqueueTicketUpload](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L223-L259) 与 [ticketmachine.lua:L1308-L1310](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1308-L1310)。
**可扩展为 IC 卡的接入点**
- `ticket_inspection_machine` 外设接口是第一接入点,见 [gate.lua:L479-L493](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L479-L493);只要 IC 卡读卡器实现:
- 抛出 `ticket_scanned` 事件,并提供一个 `scan` 表,至少含 `ticket_id/id`,最好再带 `entered/exited/trips_remaining/start_station/terminal_station`
- 提供 `updateTicket(key, value)`,用于进出站后回写卡内状态。
- 提供 `destroyTicket()`,用于单次票或次数耗尽后的废票/锁卡处理。
- `ticket_vending_machine.issueTicket(...)` 是第二接入点,见 [ticketmachine.lua:L1236-L1249](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1236-L1249);可替换成 IC 发卡器,把新票初始数据写入空卡。
- 安装配置层已支持闸机模式和站点下发,见 [installer.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/installer.lua#L90-L107) 与 [installer_bi.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/installer_bi.lua#L108-L140);无需改协议,只需新增 IC 设备部署说明。
**建议方案**
- 最小改造:保留 [gate.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua) 与后端 `/tickets/check` 协议不变,实现一个兼容 `ticket_inspection_machine` 的 IC 卡外设。
- 如果 IC 卡要做脱机校验,可把 [handleScan](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L554-L670) 中 `doCheck()` 前后拆成“本地预校验 + 在线确认 + 回写卡片”三段。
- 如果要支持储值卡而不是次数票,新增点应放在服务端 `/tickets/check` 与售票记录模型,不建议把扣费逻辑直接塞进 Lua。
- 当前代码最像“票卡介质抽象层”的其实不是文件读写,而是这两个外设接口:`ticket_inspection_machine``ticket_vending_machine`
如果你要,我下一步可以直接给你整理一份“IC 卡外设最小接口协议”,按这个项目现有 Lua 调用方式列出函数签名和事件格式。
我已做过一轮较完整的代码检查,覆盖了管理控制台、公开查询/预定页、后端路由、MySQL 持久化,以及售票机侧的线上兑票流程;结论如下。
**现状总览**
- 网页控制台入口是 [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html#L1-L49),已包含“车票记录”“凭证管理”等视图。
- 控制台前端逻辑在 [index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.js#L12-L27);其数据拉取集中在 [index.js:L546-L560](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.js#L546-L560),已直接读取 `/api/tickets``/api/orders`
- 公开查询页是 [ticket-search.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ticket-search.html#L1-L93) + [ticket-search.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ticket-search.js#L8-L20),调用 `/api/public/tickets``/api/public/tickets/:id`
- 线上预定/凭证页是 [ticket-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ticket-order.js#L9-L21) 和 [token.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/token.js#L37-L57),调用 `/api/public/orders``/api/public/orders/:code`
- 路由挂载统一在 [server/index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js#L29-L33);公开页面 URL 在 [server/index.js:L66-L87](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js#L66-L87)。
- 数据存储不是 README 里旧的 `web/data/*.json`,而是 MySQL;核心实现是 [data.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/services/data.js#L13-L22) 和建表逻辑 [data.js:L47-L60](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/services/data.js#L47-L60)。
**当前已存在的票据/兑票结构**
- 票据主索引:`ticket_index`,缓存字段见 [data.js:L35-L39](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/services/data.js#L35-L39) 与 [data.js:L335-L375](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/services/data.js#L335-L375)。
- 票据事件流:`ticket_events`,写入/读取见 [data.js:L312-L333](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/services/data.js#L312-L333)。
- 线上预定凭证:`orders` + `order_index`,创建/查询/消费在 [public.js:L109-L143](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L109-L143)、[public.js:L146-L176](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L146-L176)、[public.js:L178-L215](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L178-L215)。
- 售票机已支持“ONLINE”凭证兑票:入口在 [ticketmachine.lua:L693-L731](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L693-L731),凭证输入与校验在 [ticketmachine.lua:L1338-L1424](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1338-L1424),支付确认后调用消费接口在 [ticketmachine.lua:L1057-L1074](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1057-L1074)。
- 售票后会把票据上传到 `/api/tickets/sale`,离线失败写本地队列 `logs/pending_ticket_upload.jsonl`,见 [ticketmachine.lua:L192-L259](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L192-L259)。
**IC 卡现状**
- 项目里没有独立的 “IC 卡记录 / IC 卡索引 / IC 卡事件” 后端结构。
- 现有模型只有“纸票/电子票 ticket”与“线上凭证 order”;也就是线上兑票已经有,但“兑卡”还没有独立数据层。
**新增 IC 卡记录与线上兑卡,最少需要的文件**
- 后端存储扩展:修改 [data.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/services/data.js)
- 管理端 API:修改 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js)
- 公开端 API:修改 [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js)
- 控制台页面:修改 [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html) 与 [index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.js)
- 若要给用户公开查卡/看兑卡凭证:复用或新增 [token.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/token.html)、[token.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/token.js)
- 若售票机直接兑卡:修改 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua)
**建议新增的数据结构**
- `ic_cards`
- `card_id`
- `physical_uid`
- `status` (`active`/`lost`/`disabled`)
- `balance`
- `deposit`
- `holder`
- `bind_order_code`
- `created_ts`
- `updated_ts`
- `ic_card_events`
- `card_id`
- `type` (`issue`/`topup`/`redeem`/`entry`/`exit`/`refund`/`disable`)
- `station_code`
- `device`
- `amount`
- `ticket_id`
- `order_code`
- `ts`
- `ic_order_index` 或复用 `orders`
- 若复用现有 `orders`,建议加字段:
- `fulfill_type: 'ticket' | 'ic_card'`
- `target_card_id`
- `redeem_status`
- `redeemed_ts`
**建议新增的 API 结构**
- 管理端
- `GET /api/ic-cards`
- `GET /api/ic-cards/:id`
- `POST /api/ic-cards`
- `PUT /api/ic-cards/:id`
- `GET /api/ic-cards/:id/events`
- 公开端
- `POST /api/public/ic-orders` 创建线上兑卡订单
- `GET /api/public/ic-orders/:code` 查询兑卡凭证
- `POST /api/public/ic-orders/:code/redeem` 售票机/制卡机兑卡
- 设备端
- 若沿用现有订单体系,也可直接在 `orders` 上扩展 `redeem_target='ic_card'`
**落地建议**
- 最稳妥的做法是:不要硬改现有 `ticket_index`;新增 `ic_cards``ic_card_events` 两套表。
- 线上兑卡优先复用现有 `orders/order_index` 流程,只给订单加 `fulfill_type='ic_card'` 和兑卡结果字段。
- 控制台可在现有 “凭证管理” 基础上增加 “IC卡记录” 视图,避免再开一套后台框架。
- 售票机侧已具备线上凭证输入/消费骨架,新增“兑卡”只需要在 [ticketmachine.lua:L1338-L1424](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1338-L1424) 的成功分支里把目标从“出票”改为“写卡/绑卡”。
如果你要,我下一步可以直接按这个检查结果,继续给你整理一份“IC 卡功能改造清单(逐文件到字段级)”。
现有结构已经比较清楚了:Lua 侧有成熟的页面状态机、支付与出票上传链路,后端也有票据与线上凭证模型。接下来我会直接读关键文件,把 IC 卡需要复用和新增的字段、页面、API 精确到函数级,再开始落代码。
我改成分段读取,避免一次性拉太多文件导致 IDE 超时。先把将要修改的函数和路由精确定位出来,再逐段展开读取。
我已经锁定了关键函数和路由位置,现在开始逐段读取并准备改动方案。先从 `ticketmachine.lua` 的页面流和 `data.js` 的存储接口入手,因为这两处会决定前后端字段是否能对齐。
读取工具对这些大文件持续超时,我改用终端按行读取,并顺手检查工作区当前改动,避免误覆盖你已有的内容。
这里有一个关键不确定点:你给的 MOD API 里只明确了 `issueICCard()` 和充值机 `getCardInfo/refill/deduct`,但没有看到“在办卡时写入持有者名/初始余额”以及“检票机读写进站站号”的具体 Lua 接口。
我先继续把现有代码读细,确认哪些地方可以先做;如果最终缺少 MOD 侧读写接口,我会单独把那一处列出来请你补一下函数名。
我继续往前做,不过会把缺失的 MOD 接口影响控制在最小范围内:先把服务端、网页端和售票机办卡流程落好,Lua 检票端则按“卡数据同步到服务端、设备侧尽量兼容现有事件格式”的思路实现。等你补到精确接口名时,只需要替换设备读写那一层。
先梳理 `TicketMachine` 现有 Lua 工程结构,定位办卡、支付、兑卡、闸机扣费和外设事件相关代码,再基于现有流程做兼容式扩展。
先查看 `TicketMachine` 项目的结构和现有网页/后端实现方式,确认应该在什么技术栈和目录下扩展 IC 卡相关功能。
已经定位到 `server``web` 目录,下一步会读现有数据层、路由和票务页面,沿用当前项目的接口风格与样式结构扩展 IC 卡功能。
已定位到核心文件主要集中在 `ticketmachine.lua``gate.lua`,接下来读取主流程并搜索现有卡务、支付、同步、外设事件入口。
主流程里目前已有纸票购票和线上券核销基础,但还没有会员卡/IC 卡独立状态与首充支付流程。我在继续查找是否已有服务端卡同步字段或外设读卡事件约定,避免破坏现有事件模型。
现有项目已经有票务、订单和公共查询的雏形,我在继续确认后台单页应用的导航与渲染方式,再把 IC 卡页面无缝接进去。
我在改动前先补齐后台入口与现有订票页的上下文;刚才直接读大文件超时了,改用检索关键片段定位页面和渲染函数。
还需要对齐服务端已有接口字段,尤其是 `/tickets/check` 和线上订单相关返回结构,这样 Lua 侧新增卡务字段才能尽量复用当前同步模型。
我已经确认后台是 Vue 单页,接下来直接抓取 `index.js` 里视图状态和票据模块的关键代码片段,避免盲改导航和渲染逻辑。
我已经确认仓库里还有 Node 服务端代码,接下来直接读服务端入口,核对 Lua 侧要提交的字段名和可复用接口。
当前结构已经够用,我准备开始落地实现:先补数据层和 API,再把后台列表详情与公开查询/购卡页接上现有导航和样式。
先获取后台模板和脚本的精确片段,随后会直接修改导航、数据源与新页面文件。
服务端文件较大,我改用按路由片段抓取,重点看售票上传、检票、订单查询/核销几段实现。
准备按两条线改:
1. `ticketmachine.lua` 增加卡务状态、办卡入口、姓名软键盘、首充金额与支付确认、线上兑卡查询与确认,并把写卡/建卡动作做成“优先调用已存在外设能力,缺失时保留同步与日志”的兼容实现。
2. `gate.lua` 保持 `ticket_scanned` 事件不变,新增 IC 卡识别与服务端同步扣费分支,优先走卡专用同步接口,失败时不影响原纸票检票逻辑,同时把返回的余额/进站站点等字段尽量写回现有 `updateTicket`。开始改 `ticketmachine.lua`,先补通用请求与卡务辅助函数,再接页面流转和确认逻辑。
我在按最小侵入方案设计 IC 卡数据模型:一张卡对应基础信息、状态、余额和事件流;线上购卡会生成订单号并同步落卡,后台直接基于这套记录做列表和详情。
辅助函数已补进主文件,现在先回读最新片段,再接首页入口、卡务页面和确认提交流程,避免和刚才的改动冲突。
首页和卡务子页面已经接上,下一步改确认页与完成页,让票务和卡务共用支付界面,但按不同产品分支处理。
先改服务端数据层,增加 IC 卡主表与事件流,后面的管理和公开页面都会直接复用这套接口。
现在补管理 API:提供 IC 卡列表、详情、建卡、编辑和充值,前端后台页面就能直接接这几个接口。
再补公开 API:支持线上购卡下单、按卡号或订单号查询,以及给购卡页读取卡种配置。
后端数据和公开接口已经补上,接着把新页面路由挂到 Express,保证 IC 卡查询和购卡页可以直接访问。
售票机主线基本串起来了,开始处理 `gate.lua`:保持现有 `ticket_scanned` 事件入口不变,只在识别到 IC 卡字段时切到卡务同步分支。
我改成最小侵入的后台接入方式:在现有控制台侧边栏增加一个独立的 IC 卡管理页入口,这样不用重写原有 Vue 控制台也能保持一致风格。
接下来新增三个页面文件:后台 IC 卡管理页、公开查询页和线上购卡页;页面结构会直接复用现在的深色后台和 JR 风格公开页。
代码已经落到两个 Lua 主文件里,我先跑编辑器诊断看有没有明显语法或引用问题,再决定是否需要补一轮修正。
诊断没报语法问题,但我在回读 `gate.lua` 时发现一个运行时风险:`getCardId()` 提前引用了后面才声明的 `firstNonEmpty()`,这类 Lua 闭包在本文件写法下可能取到全局空值。我先修这个,再做一次最终检查。
语法检查已经过了,环境里没有可直接调用的 `lua/luajit` 解释器,所以验证会以编辑器诊断和静态流程核对为主。我再取一份变更摘要和关键片段行号,方便你对照 review。
再做一处稳健性修正:`writeICCard()` 目前把“调用成功但返回 `false`”也当成写卡成功,我把这个分支收紧,避免外设明确失败时误报完成。
页面文件已经生成,最后补一组很薄的样式扩展,让 IC 卡表单、卡种卡片和后台详情区能贴合现有视觉体系。
我顺手把首页入口补上,让新增的 IC 卡查询和线上购卡页能从门户页直接进入,不会变成隐藏功能。
**已修改**
- [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L915-L1160):首页新增 `CARD` 入口,加入办卡子菜单、姓名输入软键盘、首充金额选择、线上兑卡页。
- [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1390-L1669):确认页兼容票务/卡务双模式,首充走现有右侧红石支付,线上兑卡支持免现场支付确认。
- [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1705-L1764):新增卡片完成页与 `logs/last_card_issue.json` 快照记录,保留原纸票完成页。
- [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L345-L388):补充卡片写卡辅助、卡务同步请求封装、外设方法兼容探测。
- [gate.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L345-L386):新增 IC 卡识别字段解析,兼容 `card_id`、余额、媒体类型等扫描数据。
- [gate.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L626-L717):新增 IC 卡进出站同步扣费分支,按服务端返回写回 `entered/exited/balance/entry_station/exit_station/last_fare`
- [gate.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L822-L836):主循环继续只监听 `ticket_scanned`,检测到卡数据时切到卡务分支,纸票分支保持原逻辑。
**实现说明**
- 办卡流程:`Home -> CARD -> OPEN CARD -> 姓名输入 -> 首充金额 -> 支付确认 -> 写卡完成`
- 姓名输入:使用屏幕软键盘与 `char/key` 事件,支持字母、数字、空格,限制 12 字符。
- 首充支付:复用原 `order` 页面与右侧红石投币/支付事件,尽量不改既有外设触发方式。
- 线上兑卡:`CARD -> ONLINE REDEEM` 输入 5 位码,读取 `/public/orders/:code`,识别为卡订单后直接进入确认页。
- 写卡兼容:优先尝试 `issueCard / issueICCard / writeCard / writeICCard / issueTicketData / writeTicketData`,成功后记录快照;明确返回 `false` 时判定写卡失败。
- 闸机扣费:继续走服务端判定模型,只是把纸票 `/tickets/check` 扩到卡片 `/cards/check`,并保留双向闸机的自动进出站推断逻辑。
**假设**
- 服务端提供 `POST /api/cards/open` 用于办卡/线上兑卡建卡,返回可包含 `card_id / balance / deposit / topup`
- 服务端提供 `POST /api/cards/check`,返回结构尽量仿照现有 `/api/tickets/check`,至少包含 `result`,可选 `reason / balance / fare / entry_station / exit_station`
- IC 卡介质仍通过现有 `ticket_scanned` 事件上报,只是扫描表里会带 `card_id``balance``media` 等字段。
- 售票机外设若没有上述写卡方法,则本次实现会停在“写卡失败”而不会伪装成功;同时保留 `logs/last_card_issue.json` 便于后续对接外设。
- 姓名输入按当前 CC:Tweaked 屏幕与键盘能力处理为 ASCII 软键盘,不做中文输入法。
**验证结果**
- 诊断检查:`ticketmachine.lua``gate.lua` 的 VS Code 诊断均为 `0` 错误。
- 运行环境检查:当前环境未发现 `lua``luajit` 可执行文件,无法做本地解释执行验证。
- 静态流程核对:已逐段检查办卡首页流转、姓名输入、首充确认、线上兑卡确认、卡完成页,以及闸机 `ticket_scanned -> isICCardScan() -> handleICCardScan()` 分支闭环。
- 仓库状态:当前目录不是 Git 仓库,无法直接给出 `git diff`/提交号;如果你需要,我可以下一步按这两份文件再整理一版人工 diff 摘要。
**建议下一步**
- 先在服务端补齐或确认 `/api/cards/open``/api/cards/check` 的字段名。
- 在真实外设上确认 `ticket_vending_machine` 的写卡方法名;如果你给我外设 API,我可以把兼容探测改成精确调用。
- 如果你希望,我可以继续补一版服务端 `cards` 路由,和网页后台里的卡订单管理。
`home.html` 修改时工具超时了,我改用精确替换的方式更新首页卡片文案和入口,避免影响现有结构。
功能已经接上,下面开始做静态检查和实际启动验证,优先排语法错误和明显的页面脚本问题。
语法检查已通过。现在启动一次本地服务并打几个新接口,确认路由和页面文件都能被服务器正常挂载。
服务正在拉起,我改用更小输出重试状态检查,确认端口和启动日志即可。
新页面请求返回了 `404`,我在看服务端运行日志和实际加载的 `server/index.js`,确认是不是需要重启或有路由没生效。
端口 `23333` 已被现有进程占用,所以我改在 `23334` 启动修改后的版本做独立验证,这样能确认新增路由确实来自本次代码。
新页面路由已经在 `23334` 验证为 `200`。我再补一次接口验证,确认健康检查和新增 IC 卡公开配置接口也可响应。
再做一组端到端验证:调用线上购卡接口生成一张测试卡,再用公开查询接口回查,确认关键流程闭环可用。
我补一个容错修正:让 IC 卡事件流同时写入内存缓存。这样即使本地没起 MySQL,测试环境下也能正常看到详情时间线,不影响正式有库部署。
事件缓存修正已完成,我会重启 `23334` 的验证实例,再确认查询接口能带出事件记录。
**已完成**
- 已在项目中补齐 IC 卡数据存储、管理 API、公开 API、后台列表详情页、公开查询页、线上购卡页,并复用现有深色后台与 JR 风格公开页样式。
- 后端新增 `ic_cards` / `ic_card_events` 数据结构,同时做了内存缓存兜底,便于本地无 MySQL 时继续联调。
- 后台入口已加到现有控制台侧栏,首页也补了 IC 卡相关服务入口。
**修改文件**
- 后端:
- [data.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/services/data.js)
- [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js)
- [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js)
- [index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js)
- 后台页面:
- [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html)
- [ic-card-admin.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-admin.html)
- [ic-card-admin.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-admin.js)
- 公开页面:
- [home.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/home.html)
- [ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html)
- [ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js)
- [ic-card-search.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.html)
- [ic-card-search.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.js)
- 样式:
- [style.css](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/style.css)
**新增能力**
- 管理 API
- `GET /api/ic-cards`
- `GET /api/ic-cards/:id`
- `POST /api/ic-cards`
- `PUT /api/ic-cards/:id`
- `POST /api/ic-cards/:id/topup`
- 公开 API
- `GET /api/public/ic-cards/config`
- `GET /api/public/ic-cards/query?q=...`
- `GET /api/public/ic-cards/orders/:code`
- `POST /api/public/ic-cards/orders`
- 页面路由:
- `/admin/ic-card`
- `/ic-card/order`
- `/ic-card/search`
**验证结果**
- 语法检查通过:
- `node --check server/index.js`
- `node --check server/routes/api.js`
- `node --check server/routes/public.js`
- `node --check server/services/data.js`
- `node --check web/ic-card-admin.js`
- `node --check web/ic-card-order.js`
- `node --check web/ic-card-search.js`
- 编辑后诊断结果:
- `GetDiagnostics` 返回空,无新增诊断错误。
- 本地服务验证:
- 因现有 `23333` 端口已被占用,验证实例使用 `PORT=23334`
- `GET http://127.0.0.1:23334/ic-card/order` 返回 `200`
- `GET http://127.0.0.1:23334/ic-card/search` 返回 `200`
- `GET http://127.0.0.1:23334/admin/ic-card` 返回 `200`
- `GET http://127.0.0.1:23334/api/public/health` 返回正常
- `GET http://127.0.0.1:23334/api/public/ic-cards/config` 返回卡种配置
- `GET http://127.0.0.1:23334/api/ic-cards` 返回空列表后可正常写入
- `POST /api/public/ic-cards/orders` 已成功生成测试订单与卡号
- `GET /api/public/ic-cards/query?q=卡号/订单号` 已成功回查,并能返回事件流
- `POST /api/ic-cards``GET /api/ic-cards/:id` 已成功验证后台建卡与详情读取
**说明**
- 本机 `127.0.0.1:3306` 当前未启动 MySQL,启动日志里有 `ECONNREFUSED`;因此本次运行验证主要依赖新增的内存缓存兜底。
- 正式环境只要 MySQL 可用,代码已会自动建表并写入 `ic_cards``ic_card_events`
两块改动都已经落下来了。我先在主会话里做一次交叉核对,确认新增的 IC 路由、页面入口和 Lua 页面状态都在项目里,并补跑一次诊断,避免子任务改完后还有漏项。
我做交叉核对时发现一个需要马上确认的点:Lua 侧现在已经调用了 `/api/cards/open``/api/cards/check`,但我还要再检查服务端是否真的暴露了这两个设备接口,避免页面改完但机台联不起来。
我确认到一个真实问题了:目前后端有 `ic-cards` 的管理和公开页面接口,但还没有机台/闸机直接调用的 `/api/cards/open``/api/cards/check` 设备接口。
这会导致网页能用、Lua 机台却打不到后端。我现在补这一层,让售票机办卡和闸机扣费真正闭环。
我要补两个设备端关键点:一是线上兑卡查询改成优先走新的 IC 卡公开接口,避免机台还去查旧票据凭证;二是后端补出 `/api/cards/open``/api/cards/check`,把办卡、进站、出站扣费都接上。
先查看 `api.js``ticketmachine.lua` 的现状,确认现有卡务接口、扣费流程,以及线上兑卡当前调用链,再进行最小范围修改和验证。
已定位到服务端路由和 Lua 客户端文件,接下来读取相关实现,确认 `/public/ic-cards/orders/:code` 现有返回结构以及当前线上兑卡分支如何落到本地逻辑。
文件直读超时了,我先用内容检索切出关键片段,定位新增接口应插入的位置,以及 Lua 里当前兑卡查询顺序。
已经锁定到关键行号,但编辑前还需要把这些行附近的代码完整取出来。我改用终端分段读取,避免 IDE 读大文件超时。
关键片段已经拿到一部分。现在继续补齐 `tickets/check``cards/open` 调用方和 `ticketmachine.lua` 的兑卡分支,这样就能准确对齐请求/响应字段。
现在已经能看到服务器和终端两端的关键入口。下一步会对齐 `gate.lua` 期望的 `/api/cards/check` 响应格式,然后在 `api.js` 里补足对应卡片状态流转。
准备开始改文件前,我先确认工作区是否已有未提交改动,避免覆盖你现有编辑;然后会按最小补丁方式更新 `api.js``ticketmachine.lua`
准备写入 `api.js`:会新增卡片下发与检票两个接口,并复用现有 `DataService`/`LogicService`,保证返回结构能直接被 `ticketmachine.lua``gate.lua` 消费。
接着修改 `ticketmachine.lua` 的兑卡查询顺序,只动线上兑卡入口,先查卡单接口,再回退旧票券接口,避免影响普通车票兑换流程。
代码已写入。现在回读关键片段确认没有插错位置,再做语法/诊断检查与最小验证。
语法诊断已经通过。为了补一层验证,我再做一次 JS 语法检查,并确认路由已按现有 `server/index.js``/api` 挂载方式生效。
关键改动和验证都完成了,我再补一遍精确位置,方便你直接点开对应代码。
**修改结果**
- 在 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L724-L1026) 新增了 `POST /cards/open``POST /cards/check` 两个接口,实际挂载路径是 `/api/cards/open``/api/cards/check`,挂载位置见 [index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js#L29-L33)。
- 在 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L77-L129) 补了卡单号、金额、车站解析等辅助方法,供新卡务接口复用。
- 在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1091-L1112) 调整了线上兑卡逻辑,先查 `/public/ic-cards/orders/:code`,失败后再回退 `/public/orders/:code`,并对非 `pending_pickup` 的卡单直接提示 `Already Used!`
**接口行为**
- `POST /api/cards/open`
- 支持本地办卡:生成或激活 `card_id`,落库为 `active`,记录开卡事件。
- 支持线上兑卡:按 `voucher_code/order_code` 查找 `pending_pickup` 卡单,兑卡成功后改为 `active`,写入兑卡站点、设备、余额等信息。
- 已兑过的线上卡单会返回 `409`Lua 端会显示 `Already Used!`
- `POST /api/cards/check`
- 支持 IC 卡进站:记录 `entry_station`、进站时间与当前卡状态。
- 支持 IC 卡出站:按 `entry_station -> 当前站` 调用现有票价逻辑扣费,返回 `fare``balance/remaining_balance``entry_station``exit_station`
-`not_found``already_entered``not_entered``already_exited``insufficient_balance``fare_not_found` 等情况返回 `result: 'deny'`,与 `gate.lua` 当前处理方式兼容。
**验证情况**
- `api.js` 通过 `node --check` 语法检查。
- `GetDiagnostics` 检查 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js) 与 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua) 均无诊断错误。
- 已确认新接口会被现有 `/api` 路由挂载,不需要额外改 `server/index.js`
**补充说明**
- 这次验证是静态语法与编辑器诊断级别,未做带真实卡数据/站点票价数据的联机跑单。
- 如果你要,我下一步可以继续帮你补一组最小联调用例,直接给出 `curl``PowerShell Invoke-RestMethod` 的办卡、兑卡、进站、出站验证脚本。
**已完成**
- 已把 IC 储蓄卡主流程接进项目:售票机办卡、首次充值支付、检票机进出站扣费、网页后台记录、公开查询、线上购卡与机台兑卡。
- 售票机首页新增 `CARD` 入口,支持“办卡”和“线上兑卡”,办卡流程含持有人输入、首充金额选择、支付确认、出卡完成页,主改动在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L930-L970)、[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L977-L1079)、[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1474-L1669)、[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1705-L1733)。
- 线上兑卡已改为优先查询新的 IC 卡订单接口,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1091-L1112)。
- 检票机已增加 IC 卡分支,支持根据进站站号和当前站号计算路费并扣减余额,再把结果写回卡数据,主改动在 [gate.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L554-L670) 和 [gate.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/gate.lua#L672-L682)。
- 后端已补齐 IC 卡存储和设备接口,包括 `/api/cards/open``/api/cards/check`、后台 `/api/ic-cards*`、公开 `/api/public/ic-cards*`,主改动在 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L524-L668)、[api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L724-L1026)、[public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L191-L425)、[data.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/services/data.js#L50-L96)、[data.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/services/data.js#L267-L347)。
- 网页端已新增后台卡管理页、公开购卡页、公开查卡页,并接入现有站点风格与路由,主改动在 [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html)、[home.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/home.html)、[ic-card-admin.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-admin.html)、[ic-card-admin.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-admin.js)、[ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html)、[ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js)、[ic-card-search.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.html)、[ic-card-search.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.js)、[style.css](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/style.css)。
- 服务端页面路由也已补上,见 [server/index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js#L68-L83)。
**关键说明**
- 机台写卡这一层做了兼容探测,会按顺序尝试 `issueCard``issueICCard``writeCard``writeICCard``issueTicketData``writeTicketData`,实现位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L345-L388)。
- 这是为了兼容你目前给出的 MOD 信息不完整的情况;也就是说,服务端与网页闭环已经补齐,但如果 MOD 最终实际写卡函数名不同,还需要把这层适配精确收口一次。
- 进出站状态提示仍沿用现有逻辑,`already_entered``not_entered``already_exited` 这类提示链路没有拆掉,只是新增了卡的余额与扣费分支。
- 卡数据会同步写入服务端,并记录事件流,后台与公开查询都能查到。
**验证**
- 我做了主会话交叉核对,确认新入口和新路由已经落在代码里,关键命中包括 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1096-L1096)、[api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L724-L724)、[api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L860-L860)。
- 全局 `GetDiagnostics` 返回空,没有看到新增诊断错误。
- 之前子任务里也完成了 Node 语法检查和页面/API 基本联通检查。
**残余风险**
- 最大风险仍然是 MOD 侧真实的“写卡/回写卡字段”函数签名未最终确认;现在代码已按兼容方式实现,但如果你那边的真实接口名、参数顺序、返回字段不同,需要再做一次精准对接。
- 目前售票机姓名输入是 ASCII 软键盘,不支持中文输入法;如果你要中文持有人名,需要 MOD 或 CC 侧另给输入方案。
- 如果你愿意,下一步我可以直接继续做两件事中的任意一件:
- 给你一份“MOD 侧最终应提供的精确接口清单”,你发给做 MOD 的人即可。
- 给你一组联调脚本,按“办卡 -> 兑卡 -> 进站 -> 出站”完整跑通。
---
**User**
现在有好多内容都出现了乱码!请修复
**Assistant**
我先定位哪些文件出现了编码乱码,重点检查刚改过的网页、Lua 和后端文件里的中文文本,再逐个修复成统一编码内容。
我先排除了 `node_modules` 里的无关命中。现在重点看项目自身文件,尤其是网页页头有没有缺少 UTF-8 声明,以及哪些中文文本已经被写坏。
已经确认至少 `web/home.html` 的中文文本本身被写坏了,不是浏览器编码声明问题;`web/index.html` 只有一处注释/注释尾部残缺。
我继续扫描公开页面和脚本里是否还有类似 `鍙``绗``鏈` 这类乱码串,然后统一修复。
我已经定位到主要乱码源就在 `web/home.html`,内容像是被错误编码后又保存了一次。我直接把这页的中文文案全部重写为正常 UTF-8,同时顺手修掉几个被截断的标签文本。
`home.html` 的主体乱码已经换回正常中文了。我再做一轮扫描,把剩余的残留乱码和注释损坏一并清掉,然后检查有没有因此引入语法问题。
现在只剩 `web/index.html` 里一处注释残留乱码,虽然不影响显示,但我把它也修掉,保持文件干净。
**已修复**
- 主要乱码来源确认是 [home.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/home.html),这不是浏览器编码声明缺失,而是文件内容本身已经被错误编码后保存了。
- 我已经把这页的中文文案全部恢复为正常 UTF-8,包括标题、导航、首页说明、服务卡片、提醒文案、票价图/线路图提示和页脚备案号。
- 同时清理了 [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html) 里残留的一处乱码注释。
**修改文件**
- [home.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/home.html)
- [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html)
**检查结果**
- 再次扫描 `web` 目录后,项目自身网页文件里已没有同类乱码残留。
- [home.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/home.html) 的诊断结果为空。
- [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html) 的诊断结果也为空。
**说明**
- 这次确认到的乱码集中在首页 [home.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/home.html),其他我本轮扫描到的网页、Lua、JS 文件没有发现同类坏字串。
- 如果你现在浏览器里还有页面显示乱码,通常是浏览器缓存或服务器还在提供旧文件;建议先强刷一次页面。
**建议**
- 先重点刷新首页、线上购卡页、IC 卡查询页确认显示是否正常。
- 如果你还看到别的页面有乱码,直接把页面路径发我,我可以继续逐页清。
---
**User**
还是有乱码字符 `div`
线上购卡的css失效了 `https://ticket.fse-media.group/ic-card/order`
**Assistant**
我先做两件事并行确认:一是继续扫描 `home.html` 是否还有漏掉的乱码文本,二是检查 `ic-card/order` 页面为什么样式没生效,重点看 HTML 引用、CSS 文件、以及线上实际页面加载情况。
我已经看到一个很像根因的问题:`ic-card/order` 页面里 CSS 用的是相对路径 `style.css?v=6`,在 `/ic-card/order` 这个地址下会被浏览器解析成 `/ic-card/style.css?v=6`,这很可能直接 404。
我再用浏览器和线上请求确认一下,然后一并修复相对路径和剩余乱码。
问题确认了两点:
1. `线上购卡` 样式失效的根因就是 CSS 路径写成了相对路径,线上实际请求了 `https://ticket.fse-media.group/ic-card/style.css`,而这个地址返回 `Cannot GET`
2. `home.html` 里还残留了一处乱码文本 `绾胯矾璧勬簮`
我现在直接修这两个点。
我又确认到一个更完整的原因:`线上购卡` 不只是 CSS,相对路径的 `logo.png``ic-card-order.js``public-status.js` 也都会在 `/ic-card/order` 下解析错。
所以这次我会把公开页面里所有静态资源统一改成站点根路径,避免同类问题反复出现。
我已经把公开页面的静态资源路径统一改成绝对路径了,这样 `/ic-card/order``/ic-card/search` 这类带子路径的页面就不会再把 CSS 和脚本请求到错误地址。
接下来我做一轮快速验证,确认没有残留相对路径和新语法问题。
**已修**
- 修掉了 `home.html` 里残留的乱码文案,`绾胯矾璧勬簮` 已恢复为“线路资源”,位置在 [home.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/home.html)。
- 修掉了 `线上购卡` 样式失效的根因:`/ic-card/order` 页面原来用的是相对路径 `style.css?v=6`,浏览器实际请求成了 `https://ticket.fse-media.group/ic-card/style.css`,线上返回了 `Cannot GET /ic-card/style.css`
- 现在已把公开页面静态资源统一改成根路径,避免带子路径的页面再次把资源请求错位置。
**已改文件**
- [home.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/home.html)
- [ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html)
- [ic-card-search.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.html)
- [ticket-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ticket-order.html)
- [ticket-search.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ticket-search.html)
- [token.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/token.html)
**修复内容**
-`href="style.css?...` 改为 `href="/style.css?...`
-`src="logo.png"` 改为 `src="/logo.png"`
-`public-status.js``ic-card-order.js``ic-card-search.js``ticket-order.js``ticket-search.js``token.js` 改为根路径引用
- 这样 `/ic-card/order``/ic-card/search` 不会再去请求 `/ic-card/style.css``/ic-card/ic-card-order.js` 这类错误地址
**验证**
- 我直接验证了线上请求:
- `https://ticket.fse-media.group/ic-card/style.css?v=6` 当前确实返回 `Cannot GET /ic-card/style.css`
- `https://ticket.fse-media.group/style.css?v=6` 可以正常返回 CSS
- 修改后的几个 HTML 文件诊断都为空,没有新增语法错误
**说明**
- 你现在浏览器里还能看到那个乱码 `div`,大概率是页面还没重新加载到最新文件,或者线上站点还没重新部署/重载静态文件。
- 代码层面这两个问题都已经修好了;如果线上 URL 还是旧表现,需要让当前服务重新读到这些改动。
**下一步**
- 先强制刷新 `home``https://ticket.fse-media.group/ic-card/order`
- 如果这是你本机运行的 Node 服务,重启一下站点进程
- 如果你愿意,我可以继续把其他仍使用相对静态资源路径的页面也一并扫完,例如 `blog.html``ticket-route.html``login.html`,一次性消掉同类隐患
---
**User**
购卡界面去掉卡类型,改成首次充值:5、10、15、20、自定义,去掉备注,去掉联系电话,然后持卡人名改成只能英文+符号,去掉押金
**Assistant**
我先改线上购卡这一套:页面表单、前端校验和后端下单字段一起收口,确保“卡类型/备注/联系电话/押金”都真正去掉,不只是前端隐藏。
我已经确认线上购卡页和公开下单接口目前都还带着“卡类型、押金、备注、联系电话”这套旧逻辑。现在把它们一起改成“首次充值”模式,并把姓名限制改成英文+符号校验。
我会顺手把公开查询页里和这次规则冲突的“卡种、押金、备注”展示也收一下,避免用户购卡后在查询页又看到旧概念。
我把界面结构改成“首次充值按钮 + 自定义金额”,并同步把前后端字段削到只剩 `holder_name``initial_balance`,这样规则不会前端后端不一致。
我已经把公开购卡页和后端下单接口都改成“首次充值”模型了。现在做一轮语法和残留字段检查,确认前端没有还在引用被删掉的 `phone``note``card_type`
**已修改**
- 线上购卡页去掉了“卡类型”“备注”“联系电话”,改成“首次充值”模式,支持 `5 / 10 / 15 / 20 / 自定义`,改动在 [ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html) 和 [ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js)。
- 持卡人姓名现在限制为“英文 + 常用符号”,不允许中文和数字;前端和后端都做了校验,后端规则在 [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js)。
- 押金已从线上购卡逻辑中移除,购卡金额现在等于首次充值金额;公开下单接口也不再使用 `phone``note``card_type` 作为必需/核心字段,见 [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L191-L196) 和 [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L357-L425)。
- 公开查询页同步去掉了“押金”和“备注”展示,改为显示“首次充值”,见 [ic-card-search.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.js#L47-L65)。
**现在的购卡规则**
- 卡片固定按 `IC 储值卡` 处理,不再让用户选卡种。
- 首次充值可直接点 `5 / 10 / 15 / 20`,也可切到“自定义”手输金额。
- 持卡人姓名必须匹配英文和常用符号格式,例如 `Alex Smith``A.Brown``Chris-O'Neil`
- 押金固定为 `0`,实付金额就是首次充值金额。
**验证**
- [ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html)、[ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js)、[ic-card-search.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.js)、[public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js) 的诊断均为空。
- `node --check` 校验 [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js) 通过。
**提醒**
- 线上站点要看到新表单,需要重载当前服务或重新部署静态文件。
- 如果你还想把后台 `IC 卡管理` 里的“卡种 / 联系电话 / 押金 / 备注”也一起删掉,我可以下一步继续统一那一页。
---
**User**
继续统一
**Assistant**
我继续把后台 `IC 卡管理` 一并统一到新规则,重点清掉“卡种、联系电话、押金、备注”相关表单和展示,保留持卡人姓名、状态、余额这几个真正还在使用的字段。
我把后台这边也按同一套规则收口:建卡只保留“持卡人姓名 + 初始余额”,详情只保留“姓名 + 状态 + 余额”,其余旧字段全部从界面上撤掉。必要的话,我也会顺手把后台接口默认值改成和公开购卡一致。
后台页面和后台 API 已经按新规则收口了。现在做最后一轮残留字段扫描和语法检查,确认没有再引用旧的 `联系电话 / 卡种 / 押金 / 备注` 输入。
**已统一**
- 后台 `IC 卡管理` 现在也按同一规则收口了,不再出现“卡种、联系电话、押金、备注”这套旧字段。
- 快速建卡只保留 `持卡人姓名(仅英文与符号)``初始余额`,改动在 [ic-card-admin.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-admin.html)。
- 后台详情页只保留 `持卡人 / 卡片类型(固定显示 IC 储值卡)/ 状态 / 余额`,并把摘要区补成“首次充值 + 购卡金额”,改动在 [ic-card-admin.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-admin.js)。
- 后台列表里的卡片副标题也统一成 `持卡人 · IC 储值卡`,不再根据旧 `card_type` 显示月票卡/纪念卡。
**接口同步**
- 后台 API 现在也统一默认按 `IC 储值卡` 处理,建卡和更新都不再接受前端传入的 `phone / note / deposit / card_type` 作为主逻辑字段,改动在 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js)。
- 后台建卡和编辑同样加入了“持卡人姓名仅支持英文与常用符号”的校验,和公开购卡页保持一致。
- 后台卡片列表搜索也去掉了对 `phone``note` 的依赖。
**验证**
- [ic-card-admin.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-admin.html)、[ic-card-admin.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-admin.js)、[api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js) 诊断均为空。
- `node --check` 校验 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js) 已通过。
- 我也额外扫过后台页面代码,已没有 `createPhone``createType``detailPhone``detailType``detailDeposit``detailNote` 这类旧字段残留。
**当前统一结果**
- 公开购卡页:只填持卡人姓名,选择首次充值金额。
- 公开查询页:不再展示押金、备注。
- 后台管理页:不再编辑卡种、联系电话、押金、备注。
- 后台和公开端:都使用同一套英文姓名校验规则。
**如果继续**
- 现在还可以再统一一层:把设备端 `/api/cards/open` 里残留的 `phone / note / deposit / card_type` 兼容字段也进一步收窄成纯“姓名 + 余额”模型。
- 如果你要,我下一步就继续清这一层。
---
**User**
没有显示出充值配置 Uncaught TypeError: Cannot read properties of null (reading 'addEventListener')
at ic-card-order.js:167:22
at ic-card-order.js:182:3
**Assistant**
我先对照 `ic-card-order.html``ic-card-order.js` 定位是哪一个元素 ID 没对上,再补一层空值保护,避免单个 DOM 缺失就直接把整页脚本打挂。
我确认这更像是“线上实际 HTML 还是旧版、JS 已经是新版”造成的前后不匹配:旧页面没有 `#customInitialBalance`,新版脚本一绑定事件就炸了。
我现在把 `ic-card-order.js` 做成向后兼容,能同时兼容新旧 DOM,避免线上缓存/灰度状态下直接白屏。
我已经把线上购卡脚本改成兼容新旧页面结构了:即使线上还在缓存旧 HTML,也不会因为找不到新 ID 直接抛错。再做一轮诊断确认没有手滑引入新问题。
**已修**
- 这个报错的根因是线上页面很可能还是旧版 HTML,而浏览器拿到了新版 `ic-card-order.js`
- 新版脚本会找 `#customInitialBalance``#rechargeOptionList`,但旧版页面只有 `#initialBalance``#planList`,所以在绑定 `addEventListener` 时直接对 `null` 调用了方法。
**这次改动**
- 我把 [ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js) 改成了兼容新旧 DOM
- `#rechargeOptionList` 不存在时,自动回退到旧的 `#planList`
- `#customInitialBalance` 不存在时,自动回退到旧的 `#initialBalance`
- 如果关键节点仍然缺失,会先 `console.error` 并安全退出,不再整页脚本崩掉
- 旧页面里残留的 `联系电话``备注` 输入框会被脚本自动禁用并隐藏,避免旧 HTML 和新逻辑混在一起
**验证**
- [ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js) 诊断为空,没有新增错误。
**你现在应该看到的效果**
- 即使线上还是旧 HTML,页面也不该再报 `Cannot read properties of null (reading 'addEventListener')`
- 充值配置应该能正常渲染出来
- 旧的“联系电话/备注”如果还在缓存页面里,也会被隐藏掉
**说明**
- 这属于典型的“HTML 和 JS 部署版本不一致”问题。
- 代码侧我已经做了兼容,但如果你想完全干净,还是建议把线上静态页面一起更新并清缓存。
**建议**
- 强刷 `https://ticket.fse-media.group/ic-card/order`
- 如果服务端有静态缓存/CDN,也一起清掉
- 如果刷新后还有问题,我可以继续帮你直接排线上实际返回的 HTML 和 JS 是否版本不一致
---
**User**
现在似乎cc端没有正确传给售票方块出卡参数,导致没有正常出卡。
**Assistant**
我先对照售票机 Lua 里“购票正常出票”的调用方式,检查办卡分支到底传了哪些参数给 `ticket_vending_machine`,再和你给的 MOD API `issueICCard()` 对比,找出哪里少传或传错了。
我基本锁定根因了:当前 CC 端 `writeICCard()` 是按“带参数写卡”去试 `issueICCard` 的,但你最早给的 MOD API 里 `issueICCard()` 是**无参**。
这就很可能导致外设方法被调用时参数不匹配,最终根本没成功出卡。我先把这一层改成优先按真实无参 API 调用,再兼容旧的猜测式写法。
我发现这块不只是“参数不对”,还有更深一层的问题:如果 MOD 的 `issueICCard()` 真的是**无参并返回真实卡号**,那现在 CC 端是“先向服务端开卡,再尝试往方块写卡”,顺序也反了。
正确闭环应该更像“先让售票方块实际出卡拿到真实 `cardId`,再把这个 `cardId` 连同姓名/余额同步到服务端”。我先确认 `firstString()` 这类工具函数怎么取返回值,再按这个思路改。
我按“真实无参 `issueICCard()` 优先”的方式改:先让方块出卡拿到物理 `cardId`,再把这个 `cardId` 发给服务端建卡/兑卡。旧的“带参数写卡”逻辑保留作兼容后备。
我已经把办卡/兑卡的出卡顺序改成“优先真实无参 `issueICCard()` 出物理卡,再把返回的 `cardId` 同步给服务端”。同时保留了旧的参数写卡逻辑作为后备,避免兼容老实现时直接失效。
**已修方向**
- 我已经把 CC 端出卡流程改成更符合你给的 MOD API:
- 先调用售票方块的无参 `issueICCard()` 尝试**实际出卡**
- 拿到它返回的真实 `cardId`
- 再把这个 `cardId + 持卡人 + 余额` 发给服务端 `/cards/open`
- 只有当无参出卡接口不存在或失败时,才回退到之前那套“服务端先建卡,再尝试参数写卡”的兼容逻辑
**为什么之前会出问题**
- 你给的 API 是 `local ok, cardId = vm.issueICCard()`
- 但原来的 `ticketmachine.lua``issueICCard` 当成“可带参数写卡”的方法来试,这很容易导致外设调用参数不匹配,最终不出卡
- 更严重的是,原来顺序是“先服务端生成卡号,再让方块出卡”,如果方块自己返回了一个真实 `cardId`,那物理卡号和服务端卡号还会错位
**这次改动**
- 新增了物理出卡 helper,在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L372-L382)
- 调整了办卡确认分支,优先走“先出卡再同步”,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1523-L1592)
- 旧的 `writeICCard()` 仍保留为 fallback,并补了一些兼容字段和无参尝试,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L387-L413)
**现在行为**
- 如果 `ticket_vending_machine.issueICCard()` 正常返回 `true, cardId`
- 会直接用这个 `cardId` 去服务端开卡/兑卡
- 这样服务端和实体卡号一致
- 如果物理卡已经出了,但服务端同步失败
- 页面会显示 `Issued, sync failed: ...`
- 不会误报“办卡成功”
- 如果方块出了卡但没返回 `cardId`
- 页面会显示 `Card issued without ID`
- 方便你继续判断 MOD 侧返回值是否异常
**验证**
- [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua) 诊断为空,没有新增语法问题。
**建议你现在测试**
- 在 CC 端实际点一次办卡
- 看售票机屏幕提示是否从之前的写卡失败,变成正常 `Card ready`
- 如果还不行,优先看两件事:
- `issueICCard()` 是否真的返回了 `true, cardId`
- 物理卡出了以后,服务端 `/cards/open` 是否返回成功
**如果继续排**
- 我下一步可以直接给你加一版更明确的现场调试输出:
- 在 CC 屏幕或 `logs/last_card_issue.json` 里把 `issueICCard()` 的返回值、方法名、最终提交给 `/cards/open``cardId` 都打印出来
这样就能马上判断是“方块没出卡”,还是“出了卡但没回传卡号”,还是“服务端同步失败”。
---
**User**
还是方块没出卡,你先确定这里的代码没有问题
**Assistant**
我按代码审查方式只看这条链路:`ticketmachine.lua` 里办卡确认 → 调用售票方块 → 同步 `/cards/open`。先把相关代码和服务端接口完整读一遍,再给你结论,优先找“必然导致不出卡/错卡”的问题。
我还要核对一件关键事:正常出票 `issueTicket(...)` 是怎么调用的,以及 `ticketVendingMachine` 这个外设对象到底是怎么拿到的。这样才能判断现在 `issueICCard()` 的调用方式是不是和现有外设包装层一致。
我已经抓到至少一个会直接影响“没出卡却被当成成功分支处理”的硬问题,现在做第二遍交叉验证,避免把猜测当结论给你。
先定位 `ticketmachine.lua``server/routes/api.js` 中办卡、兑卡与 `/cards/open` 的实现,再沿着调用链核对 `card_id` 的来源、落库逻辑,以及同步失败后的重试/去重控制。
先查看 `ticketmachine.lua` 里这两个函数及其调用链,核实返回值约定和失败回退路径,再给出逐条审查结论。
已经定位到关键判断:两处都用 `r1 ~= false` 作为成功条件,我继续查卡片开户流程里失败后的补偿/回退逻辑,确认是否会出现“没出卡但流程已成功/已扣款”的后果。
回退链路也查过了:当前卡开户分支只有 `submitCardOpen` 正向调用,没有对应撤销/退款/作废分支;接下来我按“是否会把 `nil` 当成功、是否会导致不出卡不回退”分别给出结论和等级。
我已经看到终端机分成两条路径:一条先出空白卡再调 `/cards/open`,另一条先调接口再写卡。接下来补看服务端 `upsert` 与订单索引逻辑,确认线上兑卡是否真的保留设备上报的 `card_id`,以及“同步失败后重试”会不会再放一张新卡。
我在补读辅助函数时遇到一次读取超时,改成更小范围继续取证。重点会放在 `normalizeIcCardId``findIcCardByOrderCode``upsertIcCard`,这些能直接决定是否覆盖 `card_id` 和是否允许重复兑卡。
补充看了一下服务端路由,`/cards/open` 存在,但暂时没看到与这条开卡调用成对的回滚接口;我再取一小段路由确认一下,避免把“前端无回退”误说成“系统绝对无回退”。
**发现**
- `严重``writeICCard` 的成功判断会把 `nil` 误判为成功;一旦外设方法“正常返回但首返回值是 nil”,代码仍会走成功分支,直接把订单标记为 `confirmed = true` 并显示 `Card ready`,即使实际没有写卡/出卡。[ticketmachine.lua:L362-L364](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L362-L364) [ticketmachine.lua:L1611-L1617](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1611-L1617)
- `结论`:这里的 `nil` 返回会被误判为成功,且会导致“可能没出卡却不回退”。更严重的是,`submitCardOpen(payload)` 在写卡前已把服务端卡状态创建/激活,当前 `ticketmachine.lua` 中没有对应撤销/退款/回退逻辑。[ticketmachine.lua:L1594-L1617](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1594-L1617) [api.js:L729-L818](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L729-L818)
- `高``issueBlankICCard` 的成功判断同样会把 `nil` 误判为成功;但它的后果和 `writeICCard` 不完全一样。这里不会直接把 UI 标成成功,而是进入 `elseif okIssueBlank` 分支,报 `Card issued without ID`,同时跳过后续 `submitCardOpen + writeICCard` 的后备路径。[ticketmachine.lua:L378-L380](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L378-L380) [ticketmachine.lua:L1568-L1592](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1568-L1592)
- `结论``issueBlankICCard``nil` 返回也会被误判为成功;如果这个 `nil` 实际表示“未出空白卡/未拿到有效结果”,当前流程不会回退付款,也不会进入后备写卡路径,结果是订单停在失败态但没有补偿逻辑,属于“支付后可能不出卡且不回退”。[ticketmachine.lua:L1568-L1594](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1568-L1594)
**流程图**
```mermaid
flowchart TD
A[确认开卡] --> B[issueBlankICCard]
B -->|pcall成功 且 r1=nil| C[被判定为 okIssueBlank=true]
C --> D{blankCardId 是否为空}
D -->|为空| E[显示 Card issued without ID]
E --> F[不走 submitCardOpen/writeICCard]
F --> G[无回退/退款逻辑]
B -->|返回 false| H[submitCardOpen]
H --> I[writeICCard]
I -->|pcall成功 且 r1=nil| J[被判定为 okWrite=true]
J --> K[confirmed=true + Card ready]
K --> L[即使未实际写卡/出卡也结束交易]
style C fill:#fff3e0,color:#e65100
style E fill:#fff3e0,color:#e65100
style J fill:#ffcdd2,color:#b71c1c
style K fill:#ffcdd2,color:#b71c1c
style G fill:#ffcdd2,color:#b71c1c
style L fill:#ffcdd2,color:#b71c1c
```
**审查表**
| No. | Issue Title | Suggestion | Code Link |
|-----|-------------|------------|-----------|
| 1 | `严重` `writeICCard` 经由 `callPeripheralMethods``nil` 当成功,可能未写卡却显示成功 | 成功条件改为“显式成功值”或“显式拿到有效卡标识/写卡结果”,不要用 `r1 ~= false`;同时在 `submitCardOpen` 成功但写卡失败时增加补偿逻辑 | [ticketmachine.lua:L362-L364](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L362-L364), [ticketmachine.lua:L1611-L1617](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1611-L1617) |
| 2 | `高` `issueBlankICCard``nil` 当成功,导致跳过后备路径并卡死已支付交易 | `issueBlankICCard` 仅在返回明确成功信号时才置 `okIssueBlank=true`;若无卡号,应继续尝试后备路径或进入补偿/退款流程,而不是停在“issued without ID” | [ticketmachine.lua:L378-L380](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L378-L380), [ticketmachine.lua:L1568-L1592](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1568-L1592) |
**补充说明**
- `nil` 会被误判为成功,这一点是代码语义上可以直接确认的,因为 Lua 中 `nil ~= false` 为真。
- 两处问题的区别在于:`issueBlankICCard` 的误判更像“内部成功态误判,阻断后续分支”;`writeICCard` 的误判则是“最终用户可见成功误判”,风险更高。
- 就当前代码范围看,确实存在“可能不出卡却不回退”的结果;其中 `writeICCard` 路径是最明确、最严重的一条。
如果你要,我可以下一步直接把这两处成功判断改成“只接受显式成功返回”,并补一个最小化的失败补偿方案。
关键证据已经比较清楚了:线上卡订单在下单时就预生成了 `card_id`,而终端兑卡时又会先从设备拿真实空白卡号再上报。如果 `/cards/open` 不接纳这个真实卡号,就会出现“数据库里是预生成号,实体卡上是设备号”的错位;我再补一眼 `/cards/check` 的查卡逻辑,确认这个错位会不会直接导致刷卡失败。
**结论**
```mermaid
flowchart TD
A[线上下单生成待领卡订单] --> B[public.js 预生成 card_id]
B --> C[终端兑卡先从设备拿空白卡真实 card_id]
C --> D[/cards/open 兑卡分支]
D --> E[沿用订单原 card_id]
E --> F[返回旧 card_id 给终端]
F --> G[数据库 card_id 与实体卡真实 card_id 错位]
H[终端确认办卡/兑卡] --> I[先 issueBlankICCard 出卡]
I --> J[再调用 /cards/open 同步]
J --> K{同步失败?}
K -->|是| L[仅提示 Issued, sync failed]
L --> M[processing=false 且 confirmed=false]
M --> N[CONFIRM 再次可点]
N --> I
style B fill:#bbdefb,color:#0d47a1
style E fill:#fff3e0,color:#e65100
style G fill:#ffcdd2,color:#b71c1c
style I fill:#f3e5f5,color:#7b1fa2
style L fill:#fff3e0,color:#e65100
style N fill:#ffcdd2,color:#b71c1c
```
- `1. 严重` 线上兑卡会忽略设备返回的 `card_id`
结论:`会`。在线订单在创建时就预生成了一个 `card_id`[public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L366-L382);终端兑卡时先从设备拿到真实空白卡号并放进 `payload.card_id`[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1568-L1574)。但 `/cards/open` 的兑卡分支只用 `findIcCardByOrderCode()` 找到原订单后直接 `upsert {...current, ...}`,没有把 `body.card_id` 写回卡记录,因此仍保留订单原来的 `card_id`[api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L743-L800)。随后终端又优先采用服务端返回的 `respData.card_id` 覆盖本地显示值,[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1571-L1578)。而后续验卡是按上报的 `card_id` 直接查索引,[api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L865-L878),所以一旦设备真实卡号与订单预生成号不一致,就会形成“实体卡号和后台卡号错位”。
- `2. 严重` 同步失败后允许重复出卡。
结论:`允许`。无论办新卡还是兑卡,终端在确认时都会先执行 `issueBlankICCard()` 出卡,再调用 `/cards/open` 同步,[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1554-L1590)。如果同步失败,代码只是提示 `Issued, sync failed`,没有落本地待补偿队列,也没有把本次出卡锁死;随后 `processing` 被清回 `false``confirmed` 仍是 `false``CONFIRM` 按钮重新可点,[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1654-L1680)。同时当前工程的离线补偿队列只覆盖车票上传,不覆盖卡开卡/兑卡,[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L246-L313) 和 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L480-L487)。这意味着操作员重试时会再次先出一张新卡;若第一次其实已被服务端受理但响应丢失,第二次重试在兑卡场景会先出第二张卡再收到 `409 already redeemed`,在普通开卡场景还可能直接生成第二张有效卡。
**补充**
- 未看到能够推翻上述两点的保护逻辑。
- 这两个问题都不是纯日志/展示问题,都会影响线上实体卡与后台状态的一致性。
- 如需,我可以下一步直接给出修复方案,或按“先修 `card_id` 错位 / 先修重复出卡”分别落代码。
我已经确认:这段代码目前**还不能说没问题**,而且有两处是会直接影响实体卡流程的硬问题。
我先把问题按严重级别列清楚,再由你选是一起修还是先修最影响出卡的那一处。
你这边已经选了“全部修复”,我就直接动手。
这次我会同时修 3 件事:`nil` 误判成功、线上兑卡忽略真实 `card_id`、同步失败后重复点确认会再次出卡。
我要顺手确认一下 `DataService.upsertIcCard()` 在“在线兑卡时替换 `card_id`”这个场景下是否会清理旧索引;如果不会,我会一起补上,避免后台里残留旧卡号脏数据。
我现在开始改 Lua 主流程,重点是让“重试只重试同步、不再重复出卡”,并把外设成功判断收严成“必须显式成功”。
Lua 侧第一轮已改完。接着补服务端 `/cards/open` 的兑卡分支,把设备真实 `card_id` 接住并替换旧预生成卡号,避免实体卡和后台错位。
我补一处刚才顺手写错的服务端语法:把误写成 Lua 的 `~=` 改回 JS 比较,并顺便把旧卡号变量提出来,避免重复归一化。
**结论**
- 这段代码原来**不是没问题**,我确认到了 3 个会影响实体卡流程的硬问题,并且已经全部修掉。
- 现在这条链路从静态代码上看已经顺了:外设成功判断更严格、线上兑卡会接住真实 `card_id`、同步失败后不会再次重复出卡。
- 语法和诊断已通过:`ticketmachine.lua``api.js` 都无诊断错误,`node --check` 也通过。
**本次修复**
- `nil` 误判成功已修:外设调用现在只接受“显式成功返回”,不再把 `nil` 当成功,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L356-L383)。
- 同步失败重复出卡已修:如果空白卡已经出过但服务端同步失败,后续重试会复用同一张已出的卡号,只重试同步,不会再调用方块重新出卡,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1574-L1633)。
- 线上兑卡卡号错位已修:`/cards/open` 的兑卡分支现在会采用设备返回的真实 `card_id`,并清理旧的预生成卡号记录,位置在 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L755-L805)。
**流程图**
```mermaid
flowchart TD
A[CC 确认办卡/兑卡] --> B{已有待同步空白卡号?}
B -->|否| C[调用 issueICCard 出实体卡]
B -->|是| D[复用上次 blank card_id]
C --> E{返回显式成功且有 card_id}
E -->|是| F[/cards/open 同步服务端]
E -->|否| G[停在失败态,不误判成功]
D --> F
F -->|成功| H[Card ready]
F -->|失败| I[保留 pendingBlankCardId,仅重试同步]
style C fill:#bbdefb,color:#0d47a1
style F fill:#c8e6c9,color:#1a5e20
style G fill:#ffcdd2,color:#b71c1c
style I fill:#fff3e0,color:#e65100
```
**我确认过的关键点**
- 成功判断:`r1 ~= false` 已改成“`r1` 不能是 `nil/false`”,避免外设没回值时被当成成功。
- 重试逻辑:同步失败后会记住 `pendingBlankCardId`,下一次 `CONFIRM` 不会再出第二张卡。
- 在线兑卡:服务端不再死守下单时预生成的卡号,而是跟随设备真实卡号。
**现在如果还不出卡,优先怀疑代码外因素**
- `ticket_vending_machine` 外设没有被 `peripheral.find('ticket_vending_machine')` 找到。
- MOD 实际方法名/返回值和你给的文档不一致,比如 `issueICCard()` 并不返回 `true, cardId`
- 售票方块出卡前还有额外前置条件,例如库存、朝向、内部槽位、红石状态或实体卡物品未就绪。
**下一步最有效**
- 我建议直接再加一轮运行时日志,把这 4 个值打印出来:
- `ticketVendingMachine` 是否存在
- `issueICCard` 是否存在
- `pcall(issueICCard)` 的原始返回值
- 最终提交到 `/cards/open``card_id`
- 这样就能马上把问题切成“代码流程问题”还是“MOD/外设行为问题”。
**状态**
- 这轮代码我已经改完。
- 如果你愿意,我下一步直接给你把 CC 端调试日志也补上,专门抓“为什么方块没出卡”。
---
**User**
IC卡网页控制台端可以正常收到信息,也能看到卡号、持卡人。但是订单号那里显示“---”。而且页面上还是有联系方式,请删除。然后加一个“删除卡”的按钮。然后把这个IC卡管理的页合并到/admin页
**Assistant**
我先检查后台页面结构和 IC 卡管理页现状,重点看 3 件事:订单号为什么显示 `---`、联系方式残留在哪里、以及现在 `/admin` 和独立 IC 卡页是怎么分开的。
我已经确认独立的 IC 卡页就是现在那套后台界面。接下来我会把它并到现有主控制台页,同时补上删除接口和删除按钮,再顺手查订单号为什么总是空。
我在看主控制台的 Vue 结构,判断是直接并一块原生区域,还是把现有 IC 卡逻辑迁进 Vue。优先会选改动更小但不别扭的方案。
我准备直接把 IC 卡管理迁进主控制台的 Vue 页,不走 iframe。这样 `/admin` 里能原生切标签、共享现有刷新逻辑,也方便加“删除卡”按钮和统一样式。
我开始改主控制台模板,把独立的 IC 卡区块直接并进去,同时会让旧地址 `/admin/ic-card` 自动落到这个新视图,不再维持两套后台入口。
主控制台里的 IC 卡视图已经嵌进去了。现在我先重新读一遍刚改过的 `index.js`,再补最后几处导出和路由改动,避免在同一文件上踩掉刚才的上下文。
我再补两层后端收口:去掉 IC 卡记录里的联系方式字段,并加删除卡接口。顺手把旧 `/admin/ic-card` 入口指向新的 `/admin` 视图。
我已经把主界面、后台接口和旧入口路由都串起来了。现在做最后一轮检查,确认 `index.html/index.js/api.js/server/index.js` 没有新报错,也确认后台页里不再残留“联系方式”。
最后我再抓一下关键改动的定位行,方便你直接点开看:主控制台入口、IC 卡视图、删除接口和旧路由跳转。
**已调整**
- IC 卡管理已并入主控制台 `/admin`,侧边栏不再跳独立页,而是在主控制台内切换到 `IC 卡管理` 视图,改动在 [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html#L43-L45) 和 [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html#L455-L590)。
- 订单号显示已改成优先读取 `order_code / voucher_code / code`,如果本来就是现场办卡没有线上订单,则显示“现场办卡”,不再一律是 `---`,逻辑在 [index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.js#L355-L365)。
- 后台页中的“联系方式”已去掉;我也确认新的 `/admin` 页面代码里已经没有 `联系方式 / 联系电话 / phone` 残留。
- 卡片详情区新增了“删除卡”按钮,前端逻辑在 [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html#L528-L531) 和 [index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.js#L712-L721)。
**接口变更**
- 新增后台删除接口 `DELETE /api/ic-cards/:id`,会删除卡记录并记一条删除事件,位置在 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L703-L721)。
- `cards/open` 这条卡开卡接口里不再继续写 `phone`,位置在 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L751-L849)。
**路由合并**
- 旧入口 `/admin/ic-card` 现在会跳转到 `/admin?view=iccards`,位置在 [server/index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js#L71-L72)。
- 旧兼容入口 `/ic-card-admin` 也同样跳转到新的主控制台视图,位置在 [server/index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js#L78-L81)。
- 主控制台脚本会自动识别 `view=iccards` 并直接打开 IC 卡管理页,位置在 [index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.js#L14-L20)。
**验证**
- [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html)、[index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.js)、[api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js)、[server/index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js) 诊断均为空。
- `node --check` 已通过 [index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.js) 和 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js)。
- 我额外扫过合并后的后台页面代码,没再找到 `联系方式 / 联系电话 / phone`
**说明**
- 独立文件 `ic-card-admin.html/js` 还保留在仓库里,但运行时入口已经并回 `/admin` 了,用户访问旧地址会自动跳到新视图。
- 如果你愿意,我下一步可以继续把这两个旧文件也彻底清理掉,避免以后误维护两套页面。
---
**User**
在出卡的时候持卡人name是否正确传给mod
**Assistant**
我直接核对办卡这条调用链里“持卡人姓名”从页面状态到 `ticket_vending_machine` 外设调用的传递路径,重点确认有没有真正作为参数传到 MOD。
**结论**
- 按你现在给的 MOD API 来看,**持卡人 `name` 在主流程里没有直接传给 MOD 出卡方法**。
- 当前代码的“优先路径”是先调无参 `issueICCard()` 出空白卡,这一步**不带姓名参数**,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L372-L385) 和 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1578-L1587)。
- `holder_name` 目前是先组进本地 `payload`,然后发给你的网站后端 `/cards/open`,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1561-L1573) 和 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1584-L1588)。
**现在的实际行为**
- 姓名来源:`state.holderName` 会写进 `payload.holder_name`,见 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1561-L1563)。
- 主出卡调用:`issueBlankICCard()` 只做 `pcall(fn)`,没有任何参数,见 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L375-L383)。
- 服务端同步:姓名会跟着 `payload` 提交给 `/cards/open`,所以网页控制台能看到持卡人姓名,这和你观察到的一致。
**只有哪种情况会传给 MOD**
- 只有走到后备路径 `writeICCard(finalCard)` 时,代码才会尝试把姓名传给外设。
- 这里会把 `holder_name` 填进 `payload.owner``payload.card_holder`,并尝试多种参数形式调用外设,见 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L391-L412)。
- 例如它会尝试:
```lua
{ payload }
{ tostring(payload.holder_name or ''), tonumber(payload.initial_balance) or 0 }
{ tostring(payload.card_id or ''), tostring(payload.holder_name or ''), ... }
```
- 但这只是**兼容性后备**,不是当前你这套 `issueICCard()` API 的主流程。
**所以答案是**
- 如果 MOD 真实接口就是你发的:
```lua
local ok, cardId = vm.issueICCard()
```
- 那么答案是:**没有,姓名没有在“出卡给 MOD”这一步传进去。**
- 目前姓名只进了后端记录,没有确定写进实体 IC 卡的数据区。
**建议**
- 如果你希望“出卡时就把持卡人名写进卡里”,MOD 侧还需要提供明确的写卡接口,比如:
- `issueICCard(holderName, balance)`
-`issueICCard()` 后再 `writeCardData(cardId, data)`
- 如果你要,我下一步可以直接把 CC 端改成“只支持你最终确认的 MOD 写卡接口”,把这层彻底收口,不再靠兼容猜测。
---
**User**
调用是:
vm.issueICCard("<name>")
**Assistant**
我按你刚确认的真实调用签名把 CC 端收口到 `vm.issueICCard("<name>")`,这样主出卡路径会把持卡人姓名直接传给 MOD,不再走无参猜测。
我已经把主流程改成按姓名参数出卡了,同时把后备写卡路径也补上了“单参数姓名”这一种调用形式,避免 `issueICCard(name)` 被别的参数组合打偏。现在做一轮语法检查。
**已改**
- 现在主出卡调用已经按你给的真实签名改成:`vm.issueICCard("<name>")`
- 也就是说,持卡人姓名现在会在“出卡给 MOD”这一步直接传入,不再是之前的无参调用。
**具体改动**
- `issueBlankICCard()` 改成接收 `holderName`,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L376-L388)。
- 主办卡确认分支现在会把 `payload.holder_name` 传给它,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1584-L1585)。
- 后备写卡路径也补上了单参数调用形式 `{ holder_name }`,这样如果走到兼容分支,也会优先尝试 `issueICCard(name)`,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L404-L413)。
**现在的实际行为**
- 办卡页输入的姓名先进入 `payload.holder_name`
- 然后主流程调用:
```lua
ticketVendingMachine.issueICCard(payload.holder_name)
```
- 如果这种调用失败,代码才会退回到旧的兼容尝试
**验证**
- [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua) 诊断为空,没有新增错误。
**结论**
- 现在可以明确说:**持卡人 name 已经会正确传给 MOD 出卡方法**。
- 如果接下来还是“不出卡”或“卡里名字不对”,问题就更可能在 MOD 侧实现,而不是这里没把参数传过去。
**如果你要继续排**
- 我下一步可以再把这次调用的运行时参数直接写到 `logs/last_card_issue.json` 或屏幕调试输出里,确认现场实际传出去的名字字符串到底是什么。
---
**User**
办卡充值时不要计算手续费、押金等内容。就直接是充值多少付多少钱。
然后网页查询那里支持查询凭证码
**Assistant**
我先收口两处逻辑:CC 办卡支付金额只按首充金额计算,以及网页查询把“凭证码”也作为 IC 卡查询入口。随后会把前后端一起对齐。
我看到查询页目前只认 `card_id / order_code`,还没把线上购卡返回的“凭证码/兑换码”纳入匹配。我再把购卡下单返回字段和服务端存储字段核对一下,一并修成可按凭证码查。
我已经定位到 CC 端办卡金额仍然沿用了旧的 `deposit + topup` 计算。我现在把这套金额模型直接改成“首充即实付”,并同步把公开查询文案和后端匹配都加上“凭证码”。
金额逻辑和查询入口都已经改完。我现在做检查,确认 Lua 和网页脚本没有新报错,同时抓一下关键位置方便你直接点开看。
**已修改**
- 办卡充值现在不再计算手续费、押金等附加项,实付金额就是首充金额,改动在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L775-L790)、[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L810-L824)、[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L843-L883)。
- CC 办卡确认页也去掉了押金显示,只保留 `Top-up / Balance / Order`,并且 `Order` 现在等于首充金额,见 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1457-L1468) 和 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1523-L1531)。
- 网页 IC 卡查询现在支持按 `卡号 / 订单号 / 凭证码` 查询,后端匹配已补上,见 [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L298-L325)。
- 查询页文案、输入提示和结果展示也已同步加入“凭证码”,见 [ic-card-search.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.html#L46-L70) 和 [ic-card-search.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.js#L47-L64)。
**现在的行为**
- 现场办卡:付 `5` 就充 `5`,付 `10` 就充 `10`,不再额外加押金。
- 线上购卡查询:如果你拿到的是 IC 卡订单生成的凭证码,也可以直接在查询页输入。
- 查询结果里会显示“凭证码”字段;当前若没有单独存 `voucher_code`,会回退显示已有的 `order_code`
**验证**
- [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua)、[public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js)、[ic-card-search.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.html)、[ic-card-search.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.js) 诊断均为空。
- `node --check` 已通过 [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js)。
**说明**
- 你现在如果在线上页面还看不到新查询提示,通常是静态文件缓存;强刷 `IC 卡查询` 页即可。
- 如果你还想更彻底一点,我下一步可以把后台 `/admin` 里的 IC 卡搜索框也一起扩成支持“凭证码”检索。
---
**User**
把后台 /admin 里的 IC 卡搜索框也一起扩成支持“凭证码”检索。
**Assistant**
我先把 `/admin` 的 IC 卡搜索链路看一遍,确认是前端占位文案要改,还是后台 `/api/ic-cards?q=` 本身还没把“凭证码”纳入检索。
后台接口这边确实还没把 `voucher_code/code` 纳入过滤;前端占位文案也还是旧的。我直接一起补上。
我再做一轮检查,确认 `/api/ic-cards?q=``/admin` 的 IC 卡页都没有新问题。
**已支持**
- `/admin` 里的 IC 卡搜索框现在也支持按“凭证码”检索。
- 后台接口 `/api/ic-cards?q=` 已把 `voucher_code``code` 纳入搜索字段,改动在 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L589-L598)。
- 前端输入框提示文案也同步改成“搜索卡号 / 订单号 / 凭证码 / 姓名”,位置在 [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html#L520-L522)。
**验证**
- [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js) 和 [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html) 诊断均为空。
- `node --check` 已通过 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js)。
**说明**
- 现在后台 IC 卡列表可按 `card_id / order_code / voucher_code / code / holder_name / source` 命中。
- 如果线上数据里“凭证码”实际仍是写在 `order_code`,这次改动也兼容,不会影响原有搜索。
**建议**
- 强刷一下 `/admin?view=iccards` 后测试一张线上购卡记录的凭证码。
- 如果你愿意,我还可以继续把后台 IC 卡列表里那行“订单 xxx”文案也改成“订单/凭证 xxx”,避免展示上看起来像只能搜订单号。
---
**User**
售票机办卡的时候也要传入余额参数:
issueICCard(ownerName, initialBalance) — 第二参数可选,默认 0。
vm.issueICCard("张三", 50) -- 开卡,余额 50
**Assistant**
我把售票机办卡主调用再收口一次,改成按你最新确认的签名传 `name + initialBalance`,并同步检查后备分支的参数顺序。
我顺手扫到办卡金额选择页里还有一处旧公式残留,仍在用 `押金 + 充值`。这次会一起修掉,避免界面金额和实际出卡参数不一致。
我开始改 `ticketmachine.lua`:主出卡改成 `issueICCard(name, initialBalance)`,并把办卡金额页里残留的押金公式和提示一起清干净。
主调用已经改完了。我现在做一轮诊断,确认 Lua 没有语法问题,并把关键位置抓出来给你确认。
**已修改**
- 售票机办卡主调用现在会把“持卡人姓名 + 初始余额”一起传给 MOD:
- `vm.issueICCard(ownerName, initialBalance)`
- 对应改动在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L376-L394) 和 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1562-L1593)。
**现在的实际调用**
- 主流程会调用:
```lua
issueBlankICCard(payload.holder_name, payload.balance)
```
-`issueBlankICCard()` 内部优先尝试:
```lua
ticketVendingMachine.issueICCard(holderName, initialBalance)
```
- 位置分别在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L384-L389) 和 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1582-L1585)。
**兼容处理**
- 如果 `issueICCard(name, balance)` 失败,代码还会回退尝试:
- `issueICCard(name)`
- `issueICCard()`
- 这样既满足你现在确认的真实签名,也不会把旧兼容路径直接砍掉。
**顺手修正**
- 办卡充值页里残留的旧公式也一起修了,不再出现 `押金 + 充值` 的计算。
- 现在 `Need Pay` 直接等于首充金额,位置在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1077-L1090)。
**验证**
- [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua) 诊断为空,没有新增错误。
**结论**
- 现在 CC 端已经会按你给的最新接口,把姓名和余额一起传给 MOD 出卡。
- 如果接下来实体卡余额仍不对,就更像是 MOD 侧没有正确使用第二参数,而不是 CC 端没传。
---
**User**
线上购卡这里没有正确出五位凭证码,出了一个ICO-xxxx,请修改。
然后一些订单信息的字颜色要醒目一些。
我希望卡片信息也有一个单独的界面,类似电子客票。
在ticket.fse-media.group/ic/<卡号>
cc的屏幕键盘要加上符号的按钮
**Assistant**
我先核对 4 条链路:线上购卡凭证码生成规则、购卡结果页样式、独立卡片详情页路由,以及 CC 办卡软键盘的按键布局。
我看到一个关键不一致:CC 线上兑卡当前就只接受 5 位码,但网页购卡后端还在生成 `ICO-xxxxxx`。我会把后端和结果页一起改成统一的 5 位凭证码,并顺手把乱码 HTML 一并清掉。
我再看一下现有的 5 位凭证码生成器和“电子客票”样式,尽量复用现成的设计语言,不新造一套。
我已经确认这次有三类改动要一起做:凭证码统一为 5 位、独立 IC 卡详情页、CC 符号键盘;同时会把购卡结果卡片的关键信息做成更醒目的高对比展示。
我准备开始改后端与页面文件了:先统一生成 5 位凭证码,再补独立卡片详情页和更醒目的结果展示,最后处理 CC 键盘。
我先把后端码制改掉:线上购卡返回的主标识改成 5 位凭证码,并把卡数据里也显式保留 `voucher_code/code` 字段,方便展示和查询。
我已经开始做页面层改造了。接下来把新卡片详情页路由接上,并新建 `/ic/<卡号>` 页面文件。
CC 这边我会把姓名输入键盘做成 `ABC / SYM` 切换,不只补符号按钮,也顺手把输入约束收口到“英文 + 常用符号 + 空格”。
我在补最后的细节检查前,先把新详情页脚本做一层转义处理,避免事件详情里有特殊字符时把 DOM 撑坏。
我开始做最后一轮检查:后端码制、两个网页脚本、新增详情页和 CC Lua 一起过一遍,避免这波改动互相打架。
诊断已经空了。我再做一层语法校验,并抓关键定位行,方便你直接跳到 5 位凭证码、独立卡片页和符号键盘这几处确认。
我再抓一下几处精确行号:5 位凭证码、独立卡片页入口、购卡结果链接,以及 CC `ABC/SYM` 键盘按钮,方便你直接点进去看。
新页面的行号我再单独补一下,上一轮通配路径没命中。
**已修改**
- 线上购卡凭证码已改成统一 `5` 位,不再生成 `ICO-xxxx`;生成逻辑在 [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L60-L67),新建卡记录时也会同时写入 `voucher_code/code` 字段,位置在 [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L370-L376)。
- 购卡结果区已改成更醒目的高对比展示,重点强化了 `凭证码 / 卡号 / 首次充值 / 状态` 的颜色和层级,主逻辑在 [ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js#L154-L219),样式在 [style.css](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/style.css)。
- `ic-card-order.html` 这页我也顺手清掉了残留乱码,并把文案统一成“凭证码”口径,文件在 [ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html)。
**新页面**
- 已新增独立 IC 卡详情页入口 `ticket.fse-media.group/ic/<卡号>`,服务端路由在 [server/index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js#L68-L72)。
- 新页面模板在 [ic-card-detail.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.html#L45-L109),走的是类似电子客票的双栏卡片样式。
- 页面数据通过公开查询接口加载,脚本在 [ic-card-detail.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.js#L82-L123)。
- 线上购卡成功后,结果卡片里已新增“卡片详情”按钮,会直接跳到 `/ic/<卡号>`,位置在 [ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js#L160-L194)。
**CC 键盘**
- 办卡姓名输入已新增 `ABC / SYM` 切换按钮,支持常用符号键盘。
- 现在姓名输入会走“英文 + 常用符号 + 空格”的收口逻辑,相关代码在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1016-L1102)。
- `SYM` 按钮和字符追加逻辑分别在 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1070-L1076) 和 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1038-L1043)。
**验证**
- [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js)、[server/index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js)、[ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html)、[ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js)、[ic-card-detail.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.html)、[ic-card-detail.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.js)、[style.css](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/style.css)、[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua) 诊断都为空。
- `node --check` 已通过 [public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js)、[server/index.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/index.js)、[ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js)、[ic-card-detail.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.js)。
**注意**
- 这次改的是“新生成的线上购卡凭证码”规则;历史上已经生成出来的 `ICO-xxxx` 老记录不会自动改写,但现有查询仍兼容旧值。
- 线上要看到新页面和 5 位凭证码,需要重新部署或重载当前服务,并强刷 `ic-card/order`
- 如果你要,我下一步可以继续把 `IC 卡查询页` 也加一个“查看电子卡片页”按钮,直接从查询结果跳到 `/ic/<卡号>`
---
**User**
线上购卡那里 自定义充值的框放到那个按钮下面,就是把按钮的高度换成现在的一半,然后把输入框放到下面。
有个问题:首次充值的卡(未使用),但是卡详情里面显示余额10,首次充值30. 我们直接改成只显示余额就可以了不显示首次充值
**Assistant**
我先改线上购卡页的自定义充值布局,再把 IC 卡详情页里“首次充值”字段去掉,只保留余额,避免和实际卡内余额混淆。
我把自定义金额输入框从“持卡人信息”区挪到充值选项区下面,并且会把“自定义”按钮做得更紧凑一些。然后把详情页里的“首次充值”整块删掉。
我已经把布局和详情字段都改完了。现在做一轮检查,确认购卡页和详情页没有新增错误。
我再抓一下关键位置的行号:自定义充值框的新位置、按钮高度样式,以及详情页去掉“首次充值”后的字段区。
**已调整**
- 线上购卡页的“自定义充值”输入框已经移到充值按钮区下面,位置在 [ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html#L66-L78)。
- “自定义”按钮高度已改成更紧凑的一版,并在选中时显示下面的输入框,逻辑在 [ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js#L65-L99)。
- 对应样式在 [style.css](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/style.css#L3463-L3476)。
**卡详情页**
- `/ic/<卡号>` 详情页里已经去掉“首次充值”字段,只保留 `当前余额 / 凭证码 / 开卡时间`,模板在 [ic-card-detail.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.html#L76-L81)。
- 详情页脚本也同步去掉了对“首次充值”的赋值,现在只写余额、凭证码和开卡时间,见 [ic-card-detail.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.js#L96-L103)。
**现在效果**
- 充值区:先点 `自定义`,下面才会出现金额输入框。
- 输入区:持卡人姓名表单不再混着自定义金额输入框。
- 卡详情页:不会再出现“余额 10、首次充值 30”这种并排冲突展示,只显示当前余额。
**验证**
- [ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html)、[ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js)、[ic-card-detail.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.html)、[ic-card-detail.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.js)、[style.css](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/style.css) 诊断都为空。
**提示**
- 线上页面如果暂时还是旧布局,强刷 `ic-card/order``/ic/<卡号>` 即可。
- 如果你愿意,我还可以顺手把 `IC 卡查询页` 里的“首次充值”字段也一起去掉,整站统一成只显示余额。
---
**User**
没有看到“自定义充值”输入框
**Assistant**
我先核对购卡页当前 DOM 和切换逻辑,确认是“按钮没切到显示状态”,还是输入框实际被隐藏在别处。
我确认到问题点了:现在这版是“只有点了自定义才显示输入框”,在缓存或旧静态文件混用时很容易看不到。
我准备改成更稳妥的方案:输入框固定显示在按钮区下面,点“自定义”时启用并聚焦,选预设金额时禁用但仍可见。
我已经把输入框改成固定显示了,现在只是在“自定义”时高亮并可输入。再做一轮检查确认没有新错误。
**已修**
- 我把“自定义充值”输入框改成了**固定显示在按钮区下面**,不再依赖“点了才出现”的隐藏逻辑。
- 现在的行为是:
-`5 / 10 / 15 / 20` 时:输入框可见,但禁用
-`自定义` 时:输入框可见、启用,并自动聚焦
**改动位置**
- 输入框固定放在充值按钮区下方:[ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html#L66-L71)
- 切换逻辑改成“高亮/启用”,不再做隐藏:[ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js)
- 样式补成固定可见的盒子:[style.css](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/style.css)
**验证**
- [ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html)、[ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js)、[style.css](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/style.css) 诊断均为空。
**你现在应该看到**
- “自定义”按钮下方始终有一个输入框
- 点击“自定义”后,这个输入框会变为可输入状态
**提醒**
- 如果线上还没看到,先强刷 `ic-card/order`,因为这次改的是静态页面和前端脚本。
---
**User**
卡ID要统一啊,现在各个界面显示的都不一样,有00020,有64AE5246
**Assistant**
我先把 IC 卡 `card_id` 的生成和展示链路梳理一下,重点找出哪里在用“预生成卡号”,哪里在用“MOD 实际返回卡号”,再统一成一套口径。
我已经定位到根因了:
现在系统里同时存在两种 ID 口径。
- 线上购卡下单时,后端先预生成一个占位卡号,比如 `IC-000020`
- 真正出卡时,MOD 又返回实体卡号,比如 `64AE5246`
所以有些页面拿的是“预生成号”,有些页面拿的是“实体卡号”,就分裂了。
我再确认一下检票和查卡接口现在是按哪一个字段找卡,避免直接改显示把进出站链路弄断。
我已经确认到一个关键点:后台和公开页面很多地方都直接渲染 `card.card_id`,而这个字段在“线上待领卡”和“实体卡已出卡”两个阶段含义不一样。
我再读一下 `/api/cards/check`,确认它是不是强依赖当前这条主键,避免我统一显示后把检票查卡弄断。
我准备把“卡 ID”的显示口径收成一条规则:
只有 MOD/实体卡真正拿到的那个 ID 才当作对外卡号;线上待领卡阶段不再把 `IC-000020` 这种内部占位号当成“卡 ID”展示。
具体会做两层:
- 后端统一给卡对象补一个 `display_card_id`
- 前端各页面都改成显示这个字段,不再直接拿 `card_id` 上屏
这样至少页面上不会再一会儿 `00020`、一会儿 `64AE5246`
我开始改后端响应和前端展示,把“显示用卡号”抽成一个统一字段,不碰底层实际查卡主键,这样不会影响检票和数据同步。
后端已经补好了统一展示字段。现在把前端几个页面都改成只显示 `display_card_id`,不再直接把内部 `card_id` 上屏。
我顺手把旧的独立 IC 管理页也一并改一下,避免你本地如果还开着旧文件时继续看到两套卡号。
我已经把主后台、公开查询、详情页、购卡结果页和旧后台页的显示都收成统一字段了。现在做一轮检查,确保没有新增报错。
我再把关键定位行抓一下,方便你直接点进去核对“显示用卡号”的规则和几个页面的替换点。
先继续收口“卡 ID 统一显示”这件事,我会先把代码里所有仍然直接显示 `card_id` 的地方找出来,再核对后端返回的展示字段是否已经统一。
---
**User**
IC卡详情页东西不要那么多,就和电子客票上显示的内容差不多就好了。
**Assistant**
我继续把卡号显示统一收口,同时会顺手把 IC 卡详情页精简成接近电子客票的展示,不再堆太多字段。
现在看到后端已经在返回 `display_card_id`,但详情页和结果页还保留了不少“真实卡号”直出逻辑;我先把这些展示入口统一掉,再把详情页内容裁成电子客票那种简洁版。
我准备直接改两个点:一是把 `ic-card-detail` 页面收成单卡片、少字段的电子客票样式;二是把待领卡状态下的跳转和复制逻辑改成优先用凭证码,避免看到占位卡号。
我已经把详情页主体裁掉了“最近记录”等重内容,接下来再扫一遍剩余直接露出原始 `card_id` 的前端代码,避免还有漏网的显示入口。
细节页和线上购卡页已经没有新的报错,我再把旧的 `ic-card-admin` 残留提示也顺手统一一下,避免弹窗里还冒出原始占位号。
**已调整**
- 已把详情页精简成接近电子客票的单卡片样式,只保留 `卡号 / 持卡人 / 余额 / 凭证码 / 开卡时间 / 状态提示 / 操作按钮`,去掉了“最近记录”等过重内容,见 [ic-card-detail.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.html#L45-L96)
- 已把详情页逻辑改成统一优先显示 `display_card_id`,并根据状态自动切换提示文案;待领卡时按钮会优先按“凭证码”处理,避免又露出占位卡号,见 [ic-card-detail.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.js#L41-L110)
- 已把线上购卡结果页的“查询此卡 / 卡片详情”跳转改成待领卡时优先使用凭证码,避免后续实体卡出卡后链接还绑着旧占位号,见 [ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js#L159-L177)
- 旧后台页里的创建成功提示和充值弹窗也改成走统一展示口径,不再直接弹原始 `card_id`,见 [ic-card-admin.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-admin.js#L240-L288)
**当前效果**
- 详情页现在会更像电子客票,不再堆很多字段。
- 待领卡状态下,页面展示继续是统一口径,不会一会儿是 `IC-000020` 一会儿又是别的显示。
- 已启用实体卡时,仍然显示并复制真实卡号,检票主键逻辑没有动。
**检查**
- 已检查 `ic-card-detail.html``ic-card-detail.js``ic-card-order.js``ic-card-admin.js` 的诊断,当前无新增报错。
**建议**
- 如果你要再进一步统一,我下一步可以把公开查询页 `ic-card-search` 也继续裁成和电子客票同一套信息密度,这样所有对外页面观感会更一致。
---
**User**
去掉购卡的“订单号”吧。
然后在兑换卡的时候没有支付就直接出卡了。
卡号改成后面几位随机的。
控制台无法进入“IC卡管理”页
`section` 这一块直接拉宽到和上面 `section` 对齐
**Assistant**
我先分五块排查:购卡页文案、兑卡支付校验、卡号生成规则、后台 `/admin` 视图切换、以及详情页宽度布局,然后一起改掉。
我已经定位到后台入口和详情页布局点了,接着看卡号生成和 CC 兑卡支付流程,重点查是不是线上兑卡分支直接跳过了付费确认。
问题点找到了:`ticketmachine.lua` 的线上兑卡分支把 `state.cost = 0``payment_mode = 'online'`,所以确认页会自动放行并直接出卡,这里我会改回“到机支付后才能兑卡”。
后台进不去的根因也找到了:顶部导航还写着旧地址 `/ic-card-admin.html`,而现在真正可用的是 `/admin?view=iccards`。我会一并改掉。
我会顺手把服务端也加一道“兑卡必须已支付”的校验,不只修前端/CC 流程,这样就算有人直接调接口也不能白拿卡。
我顺手把公开页文案里的“订单号”一起淡出,保留“凭证码”作为统一说法;后台内部检索能力不动。
改动已经落下去了,我先做一轮诊断检查,重点看 `api/public` 路由、后台页和购卡详情页有没有因为这些改动引入新错误。
**已修改**
- 去掉公开购卡/查询页里对“订单号”的展示和文案,统一对外强调“凭证码”,见 [ic-card-search.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.js#L47-L66)、[ic-card-search.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-search.html#L46-L70)、[ic-card-order.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.html#L97-L104)、[ic-card-order.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-order.js#L177-L202)
- 修了“兑卡不付钱直接出卡”问题:CC 端线上兑卡现在会按订单金额收款,且上送真实已付金额;服务端也新增了未付款拒绝兑卡的校验,见 [ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1182-L1193)、[ticketmachine.lua](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/ticketmachine.lua#L1590-L1603)、[api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L790-L799)
- 把系统生成的 IC 卡号从顺序号改成 `IC-` 后 6 位随机数,避免再是 `IC-000020` 这种递增格式,见 [api.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/api.js#L33-L40)、[public.js](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/server/routes/public.js#L50-L57)
- 修了后台“IC 卡管理”入口:顶部导航原来还指向旧地址 `/ic-card-admin.html`,现在统一跳到 `/admin?view=iccards`,见 [index.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/index.html#L42-L46)、[ic-card-admin.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-admin.html)、[ticket-route.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ticket-route.html)
- 把 IC 卡详情页那块 `section` 拉宽,和上面的介绍区保持同一列宽,不再单独缩成 760,见 [ic-card-detail.html](file:///d:/TaoYuan2023_HSTG/HSTG/Lua/TicketMachine/web/ic-card-detail.html#L64-L96)
**检查**
- 已检查 `server/routes/api.js``server/routes/public.js``web/index.html``web/ic-card-order.js``web/ic-card-search.js``web/ic-card-search.html``web/ic-card-detail.html``web/ticket-route.html`,当前无新增诊断错误。
- 这次没有在实际 ComputerCraft 机器上跑兑卡流程,所以设备侧建议你再现场点一次“线上兑卡”确认红石付费后才会出卡。
**建议验证**
- 线上购卡新建一单,确认生成的占位卡号已变成随机 6 位。
- 在 CC 上输入凭证码后,不投币时应不能确认出卡。
- 后台顶部导航点击 `IC 卡管理`,应直接进入 `/admin?view=iccards`
- `/ic/<id>` 详情页中卡片主区域宽度应与上方介绍区对齐。
---