Files
XQKqueue/findings.md
2026-08-01 21:44:59 +08:00

659 lines
98 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.

# 景区排队叫号系统:调研发现与决策台账
## Phase 42 运营统计模块标题区呼吸空间优化2026-07-16
- 用户通过截图明确指出“每日趋势、项目对比、状态分布、高峰时段”几个模块的标题和副标题贴近边框,整体缺少呼吸空间。
- 截图证据显示问题集中在卡片标题区的上下内边距和标题区到首个数据区的间隔,不是数据内容本身或模块顺序问题。
- 本轮采用统一规则:桌面卡片增加 24px 上下内边距与 32px 水平内边距;标题区副标题使用更舒展的行高,标题区下方增加 24px 留白;移动端收敛为 20px 内边距并保留 20px 标题区间隔。
- 不改变趋势、项目比较、状态列表、高峰列表的 DOM 数据结构和下钻交互,只调整 CSS 节奏与标题区/内容区边界。
## Phase 41 运营统计页视觉层级与排版精修2026-07-16
- 本轮按 `design-taste-frontend` 的“保留式重设计”处理:不改变历史数据页路由、导航、数据契约、权限、导出和项目下钻,只调整视觉层级、排版和空值表达。
- 设计读法为可信、轻量、低干扰的后台复盘工具;参数设为 `DESIGN_VARIANCE=4``MOTION_INTENSITY=2``VISUAL_DENSITY=5`,不引入营销页式动效、渐变或新图片。
- `ui-ux-pro-max` 设计系统仍推荐数据密集型看板但要求统一字体层级、8px 间距节奏、足够对比度、无横向溢出,以及少于 4 个时间点不用折线图。
- 当前页面筛选区复用了记录页的 6 列网格,统计页隐藏字段后仍留下不均衡空白;五个 KPI 各自成卡,导致第一层指标像五个同级模块;趋势、项目和节奏卡片的边界同质,主次不够明显。
- 精修方案统计页筛选网格收敛为日期、项目、操作KPI 合并成单一指标轨道;趋势与项目保持主内容宽卡,状态与运营节奏作为次级双栏;移动端统一单列并保持 8px 触控间距。
- 页面 visible copy 需要避免使用破折号作为缺省值,统一为“暂无/未提供/日期至日期”等可读文案;小时分布文字改用已定义的深色文本 token修复变量未定义导致的继承不确定性。
## Phase 40 运营统计看板布局与 UI/UX 收敛2026-07-16
- 用户明确要求删除运营统计看板中的“需要关注”模块;本轮只移除前端展示与相关引导文案,不改变项目下钻、历史查询和实时运营概览职责。
- `ui-ux-pro-max` 设计系统推荐数据密集型经营看板:以有限层级的网格承载多个 KPI、趋势和排序比较配色沿用现有管理端 token不新增依赖或视觉体系。
- UI/UX 检索要求响应式页面避免横向溢出、保持连续标题层级、避免加载时布局跳动;图表检索建议时间序列使用折线图、离散项目使用排序比较,并保留可读数值。
- 当前实现的主要布局问题是趋势与“需要关注”并列导致主内容被压缩,项目对比与高峰时段再次并列造成卡片碎片化,窄屏项目行的三列声明又承载四组内容。
- 收敛后的结构固定为:核心指标 → 全宽每日趋势 → 全宽项目对比 → 状态分布与高峰/小时节奏;少于 4 个营业日时趋势区域改为日卡片摘要,避免单点折线误导。
## Phase 39 运营统计经营复盘看板优化2026-07-16
- 用户已确认运营统计模块按“经营复盘看板”优化,不做实时值班监控;实时排队继续由现有“运营概览”负责。
- 当前 `/api/admin/history/summary` 只返回四类汇总指标、状态分布字段和按小时聚合;缺少按营业日趋势、项目维度对比、峰值时段排名、异常项目/日期摘要。
- 当前 `HistoryPage` 的“运营统计”只有 4 张汇总卡片、状态分布和按小时长条列表,信息密度偏低,无法快速回答“哪天/哪个项目变差、差在哪里”。
- 既有日期范围最多 31 天、项目筛选和 Asia/Shanghai 小时聚合可以复用;新增接口字段应继续服从项目权限与同一日期筛选口径。
- 小时统计实现已校正为分开按 `joined_at` 统计取号量、按 `called_at` 统计叫号量;两者可能落在不同本地小时,集成夹具已覆盖这一情况。
- 推荐看板结构:顶部筛选与数据新鲜度;第一层核心 KPI第二层每日趋势取号量、完成率、平均等待第三层项目排行/对比;第四层峰值时段和需要关注的异常摘要;支持点击项目或日期回到排队记录筛选。
- 继续使用现有原生 CSS 和管理端 token不新增图表依赖趋势图用轻量 SVG/HTML 图形,避免引入包和造成项目风格分裂。
## Phase 37 后台历史数据管理功能规划2026-07-16
- 现有管理端导航为运营概览、项目管理、账号管理和大屏中心,历史数据适合新增单一“历史数据”入口,内部采用排队记录、叫号记录、运营统计三个视图。
- 现有 `queue_sessions``project_id + business_date` 定位营业日,`queue_tickets` 已保存号码、同行人数、状态和取号/叫号/到场/完成/过号时间,`call_batches``call_batch_tickets` 可还原叫号批次;首期不需要新建独立历史事实表。
- 现有管理 API 仅允许 `ADMIN` 角色进入,管理员默认跨项目;历史接口仍需把项目授权作为服务端过滤条件,不能信任客户端项目参数。
- 当前数据库维护任务会在终态数据到期后清除手机号、姓氏和称谓,并保留号码及统计所需字段;历史页面应把这类记录显示为“已匿名化”,不能再通过手机号检索。
- 既有产品/设计文档要求原始排队业务事件 90 天后不可逆匿名化,但现有代码主要实现的是终态个人字段 30 天清理和审计 1 年过期删除,二者存在待统一的策略差异。
- 推荐首期做只读历史查询、叫号批次追溯、统计聚合和 CSV 受控导出;不允许直接修改历史状态/号码/同行人数,不首期引入数据仓库、冷归档或复杂审批流。
- 详细方案已写入 `docs/history-data-management-plan.md`,当前唯一必须确认的高影响决策是 90 天后原始业务事件究竟保留匿名明细还是只保留统计。
- 用户已确认90 天后保留匿名业务明细和长期统计,删除手机号、姓氏等个人关联信息,且不可恢复;该口径纳入后续清理任务、查询权限、导出字段和验收标准。
## Phase 36 员工端取号同行人数输入修复2026-07-16
- 用户反馈员工端取号页的“同行人数”输入框存在默认值 `1` 被固定、无法顺畅改成其他人数的问题。
- 本轮只修复输入交互与相应回归测试,不改变项目配置的人数上下限、取号 API 契约或服务端校验。
- 根因已定位在受控输入的 `onChange``Number(event.target.value) || minPartySize` 会把清空产生的空字符串立即转换并回填为最小人数 `1`,导致用户无法按“删除旧值 → 输入新值”的正常方式编辑。
- 修复需要让前端表单草稿的 `party_size` 临时接受空字符串;只有提交时才收窄为整数并校验项目上下限,发给 API 的字段仍保持 `number`
- 表单草稿现使用 `number | ""`,项目切换时仍会把空值或越界值恢复到新项目最小人数;成功取号后同样恢复到项目最小人数,既修复编辑体验又保留原重置行为。
- 定向 8 项员工页测试与 TypeScript 双配置检查通过;新增断言覆盖默认 `1` 被清空后保持为空、再输入 `3` 并正常取号的完整路径。
- 前端全量 14 个测试文件、52 项测试及 Vite 生产构建通过;真实员工取号页已打开,首个快照处于正常的会话权限确认加载态,待页面完成渲染后继续输入验证。
- 真实页面首次交互中,`fill("")` 后读取输入值仍为 `1`;这与新回归测试结果矛盾,当前更可能是运行中的开发服务没有加载最新模块,或页面数据初始化存在测试未覆盖的二次回填,必须继续定位后再验收。
- `:5173` 的 Vite 转换源码已明确包含新的空字符串分支,排除旧进程/旧模块;失败后的 DOM 显示输入仍聚焦且值为 `1`,下一步改用真实键盘的全选删除路径,判断是自动化 `fill("")` 行为差异还是 React 状态仍被重置。
- 真实键盘路径验证通过:对默认 `1` 执行全选 + Backspace 后 DOM 值稳定为 `""`,继续键入 `3` 后值为 `"3"`;用户实际编辑路径已修复,未提交真实取号数据。
- 首次 `fill("")` 结果是数字输入框与浏览器自动化直接填充方法的差异,不代表 React 状态仍被回填;以实际键盘操作和组件回归测试作为交互验收依据。
- 最终 DOM 显示同行人数为 `3`,项目提示仍为 110 人;浏览器控制台无 error/warn修复后的取号页已保留供直接查看。
## Phase 35 员工端队列增量展开2026-07-16
- 前端 Vite 已监听 `:5173`Go API 已监听 `:8080``/healthz` 返回 `status: ok`;用户要求的“启动项目”当前已满足,无需重复启动占用端口。
- 当前队列默认切片 10 项,但点击“查看更多”会把接口已返回的全部等待号码一次性渲染;真实队列可达 200 项,会让页面高度瞬间大幅增长。
- 最新口径按页面空间优化处理:继续复用现有队列快照,不修改 API每次点击只把可见上限增加 10属于按需渲染而非新增服务端分页。
- 保留“收起”可让用户随时回到 10 项;切换项目或员工场景时也应重置为 10 项,避免把上一上下文的展开量带入新页面。
- 增量控制不改变 FIFO 顺序、叫号 revision、轮询刷新、队列总指标或列表行布局。
- 真实员工队列浏览器实测为 10 → 20 → 30 → 10 项;对应页面高度为 1606 → 2372 → 3079 → 1606px证明每次只追加一页且列表继续随页面自然延展。
- 第一次追加后“查看更多”和“收起”同时存在,第二次仍可继续追加;收起后只保留“查看更多”,不存在一次性渲染全部队列的回退。
- 浏览器控制台无 error/warn员工端定向 8 项、前端全量 14 个文件 52 项测试、TypeScript 检查和 Vite 生产构建全部通过。
## Phase 34 员工端批量按钮与指标分隔2026-07-15
- 最新反馈只调整员工端叫号页,不能影响正在进行的 Phase 33 管理端项目表单结构化工作,也不改叫号 API、模式参数、数量上限或禁用条件。
- 当前“按号码叫号”和“按人数叫号”按钮均使用深绿色 `button--primary`;本轮将复用现有浅色按钮体系,避免新增独立颜色 token。
- 可见按钮文案按用户指定改为“批量叫号”和“批量叫人”;模式容器与输入框仍保留精确业务语义,确保屏幕阅读器能区分号码数量与目标人数。
- 移动端指标为两列布局。全局三列规则会对第 4 项应用 `nth-child(3n+1)` 并清除左边框,现有移动端规则只清除奇数项边框、没有重新给偶数项加回边框,因此“下一个号”和“下个号人数”之间缺线。
- 修复应限定在 `max-width: 720px`:偶数项恢复左边框、奇数项继续无左边框;桌面三列首项规则保持不变。
- 390×844 真实页面中两个批量按钮均计算为白色背景、绿色边框与绿色文字;旧按钮文案计数为 0快速叫号仍是白字主操作。
- “下个号人数”卡片左边框计算宽度为 1px、颜色为 `rgb(213, 222, 216)`,与“下一个号”卡片边界零间隙衔接;页面 `scrollWidth=clientWidth=390`
- 普通 390×844 视口截图显示叫号卡宽 366px、页面壳宽 390px两个浅色按钮和指标中线均正常失真的 `fullPage` 截图属于接管旧标签后的截图合成问题,不是页面布局问题。
- 720px 边界仍为两列,第四项左边框为 1px721px 恢复三列,第四项作为新行首项左边框为 0证明修复未破坏桌面边框逻辑。
- 原始参考图、当前叫号模块、修复前指标和修复后指标已放入同一次视觉对照;最新文字需求全部体现,未发现 P0-P3 遗留问题,`design-qa.md` 最终状态为 passed。
## Phase 33 项目表单结构化2026-07-15
- 用户要求的字段已存在于共享 `ProjectForm`,新建和维护也已复用同一套草稿与提交逻辑;本轮无需修改 API 或数据模型。
- 现状把 13 个字段平铺在一个 `.settings-grid` 中,基础属性、叫号约束和展示规则没有语义层级,不利于快速扫读和维护。
- 信息架构按用户口径固定为三组:基础信息(名称、编码、格式、状态);叫号规则(支持方式、单号最少/最多人数、按号码默认/单次上限、按人数默认/单次上限);其他规则(已体验起始数、每人预计间隔、官方提示)。
- “单次山限”按上下文解读为“单次上限”;页面保留现有“按号码/按人数”精确业务文案,避免“批量叫号/批量叫人”在员工端产生歧义。
- 这是保留式后台重构,沿用现有品牌绿、圆角、原生表单控件与 CSS 变量,不新增组件库或装饰动效。
- 产品手册中的历史“项目维护”截图显示为旧版极窄布局,与当前已统一的宽屏管理端代码不一致;它仅用于确认历史问题,本轮视觉验收必须以当前运行页面为准。
- 1440×1000 真实页面中,表单宽 1376px三个分区均采用“左侧分组说明 + 右侧字段”结构,页面 `scrollWidth` 等于视口宽度,无水平溢出。
- 首次桌面实测发现,成对字段中带辅助说明的“单次上限”会因 Grid 默认拉伸,将旁边默认值输入框下移约 14px已为分组内字段增加顶部对齐约束。
- 修正后桌面实测的单号人数、批量叫号、批量叫人三组成对输入框 Y 坐标分别完全一致,基线错位已消除。
- 390×844 实测中,表单宽 358px三个主分区均收敛为单列叫号规则每行收敛为“标题说明在上、两个成对字段在下”每列 139px页面无水平溢出。
- 真实项目列表已加载 3 个“维护”入口;首个维护路由为 `/admin/projects/16f75858-8a19-4f79-bd39-eeda4a86f1ad`,可用于复验共享表单在已有数据回填场景下的结构与响应式表现。
- 真实维护页已正确回填项目名称、编码、格式、状态及全部叫号/其他规则字段DOM 中保留三处分区和四个叫号规则分组,保存入口正常出现。
- 维护页在 390×844 下 `scrollWidth=clientWidth=390`1440×1000 下三处分区均为约 `285px + 1017px` 两栏,三组成对数字输入框的 Y 坐标分别完全一致,页面 `scrollWidth=clientWidth=1440`
- 新建页与真实维护页的浏览器控制台均无 error/warn临时响应式视口已恢复验收标签页已关闭。
- 最终前端全量验证通过14 个测试文件、52 项测试全部成功,应用与 Node TypeScript 检查通过Vite 生产构建成功。
- 本轮目标文件和三份项目台账的 `git diff --check` 通过;工作树中仍保留用户已有的其他未提交改动,本轮未清理、回退或暂存。
## Phase 32 员工端叫号指标与队列展示2026-07-15
- 参考图只用于确认员工端统一叫号卡的结构与品牌语言;本轮继续沿用仓库现有 Logo、绿色主色、圆角和响应式体系不新增视觉资产。
- 用户明确要求移除的是叫号模块内部横线:标题下方分隔线和窄屏两种叫号模式之间的横线都应删除;宽屏模式之间现有竖向分隔不属于本次删除范围。
- 按号码叫号按钮当前使用次要描边样式,按人数叫号使用绿色主按钮;统一颜色应让两者都采用同一个绿色主按钮样式,输入框与禁用逻辑保持不变。
- 指标目标为六项:最新叫到、本次叫号人数、下一个号、下个号人数、剩余未叫号、剩余未叫人数;不再展示最末号数和最末号预计时长。
- 下个号人数可直接取等待队列首项 `party_size`;剩余未叫号和剩余未叫人数分别使用已有 `waiting_ticket_count``waiting_people_count`,不需要修改 API。
- 队列默认仅渲染前 10 项;超过 10 项时显示可访问的“查看更多/收起”按钮。展开只改变前端可见切片,不改变队列顺序或轮询数据。
- “不要容器、页面自适应延展”按去除队列 `ol` 的固定高度、内部滚动、边框和圆角处理;展开后由页面本身滚动,叫号吸顶与底部导航行为保持现状。
- 队列每行改为三个等宽轨道:号数左对齐、人数居中、已等待分钟右对齐,保证移动端和宽屏都具有均匀对称的扫描节奏。
- 仓库无 `.project-docs`,无需触发额外项目文档维护流程;当前工作树仍包含大量既有改动,本轮只增量修改员工页、员工页测试、样式和既有台账。
- 390×844 真实页面测量:两个叫号按钮背景均为 `rgb(11, 107, 58)`;标题下边框和第二模式横向边框均为 0旧末号指标数量为 0。
- 390px 队列首屏恰好 10 项,三列计算宽度均为 98.664px,内容中心点约为 66/195/323px左右间距对称整页 `scrollWidth=clientWidth=390`
- 队列列表计算样式为 `max-height:none``overflow-y:visible`、0 边框/0 圆角,收起时 `clientHeight=scrollHeight=701px`,不存在内部滚动容器。
- 真实“查看更多”展开后渲染接口返回的 200 项,页面高度由 1684px 增至 15104px列表自身 `clientHeight=scrollHeight=14122px`;收起后恢复 10 项和 1684px 页面高度。
- 移动端滚动到 `scrollY=840.5` 时页头底边和叫号吸顶层顶边同为 83px重叠为 0控制台无 error/warn。
- 1280px 桌面与 720px 平板均无横向溢出、默认 10 项、列表无内部滚动且三列等宽桌面保留模式间竖向分隔720px 以下不出现任何模式分隔横线。
- 参考图、390px 聚焦裁图与完整页面已在同一次对照输入中复核;按最新文字需求产生的按钮色和分隔线差异为有意变更,未发现 P0-P3 视觉问题,根级 `design-qa.md` 最终状态为 passed。
## Phase 31 员工端叫号模块与通知2026-07-15
- 本轮只调整员工端现有业务工作台,保留当前品牌、路由、叫号 API 与高密度操作语言。
- 目标文件 `StaffPage.tsx``StaffPage.test.tsx``styles.css` 已有未提交改动,必须基于当前工作树增量修改,不能回退其他在途功能。
- 当前代码已有叫号反馈状态、按号码/人数模式和 `staff-call-notice` 样式线索,需读取当前实现与工作树差异后判断哪些需求已部分落地。
- 验收口径:通知可访问地手动关闭、每条新通知从创建起 5 秒自动移除;两种叫号入口保留业务能力但共享一个主标题和一个吸顶容器。
- `notice` 当前是单条可空状态,叫号前会清空,成功或失败后写入;尚无超时 effect、关闭回调或关闭按钮。
- 通知当前渲染在叫号模块之前,并通过 `.staff-call-notice` 包裹;这适合保留为瞬时状态消息,但应避免它挤占或替代固定叫号模块的位置。
- `staff-call-actions` 内已有 `staff-call-controls`,其下按能力分别渲染两个 `staff-call-mode`,每个模式都带重复小标题;合并需求可在不改变 API 参数和输入框可访问名称的前提下重组 DOM。
- 现有员工页测试覆盖叫号成功、设备失败、人数上限和主操作,需新增假定时器测试,并调整对统一标题与删除模式标题的断言。
- 当前样式明确写着“叫号操作在文档流中”,`staff-call-actions` 没有 sticky/fixed只有通知 `.staff-call-notice` 使用 `position: sticky`,与“整个叫号模块始终置顶”相反。
- 适合的结构是新增一个统一吸顶包装层,把叫号通知和 `staff-call-actions` 作为同一层级整体置顶;通知消失后叫号卡自然回到顶部,不需要监听滚动或计算高度。
- 大标题应由 `staff-call-actions` 内唯一的 `h2` 提供,并通过 `aria-labelledby` 命名整个操作区;两个 `staff-call-mode` 可保留为业务布局容器,但删除其可见小标题和内层卡片感。
- 现有按钮与输入的可访问名称已经区分“按号码”和“按人数”,删除小标题不会损失操作辨识度。
- 员工端页头本身 `position: sticky; z-index: 20`,最终覆盖层高度为桌面 68px、窄屏 64px叫号吸顶层应使用 `z-index: 19`,并在对应断点采用 `top: 68px/64px`,避免遮挡页头。
- `.staff-motion-scope``display: contents`,叫号布局父级没有阻断 sticky 的 overflow吸顶包装层可纯 CSS 实现,不需要滚动事件。
- 当前未提交差异包含本轮之前正在开发的同行人数、按人数叫号、游客取号和大屏调整;实现必须只触碰员工叫号相关片段,不能清理或格式化整个样式文件。
- 基线全量测试中员工页相关用例通过,但已有在途游客取号/查号改动导致 `VisitorLookupPage.test.tsx` 两项断言失败;这些失败在本轮代码修改前已存在,与员工叫号需求无关。
- 浏览器验收前确认本地 Vite `:5173` 与 Go API `:8080` 均已运行API `/healthz` 返回 200可直接使用真实页面和数据验证。
- 真实员工账号登录后DOM 只呈现一个 `h2`“按号数/人数叫号”;按号码与按人数仍作为可访问的操作分组,按钮和默认数量均正常返回。
- 390x844 真实视口首轮测量显示统一叫号卡高 262px、吸顶包装层高 282px页面总高 1306px具备实际滚动空间布局未横向溢出。
- 首轮测量同时发现窄屏页头真实底边为 83px而 CSS sticky 偏移仍是 64px滚动后会有 19px 落到页头下方,需以真实页头高度修正而不是只依赖 `min-height` 声明。
- 页头高度差异来自后置品牌 Logo 规则:窄屏 Logo 框实际为 104x66px加上下各 8px padding 与边框后页头为 83px`min-height: 64px` 不代表最终盒高。
- 1280px 桌面视口同样存在偏移Logo 框 112x64px、页头真实高 85px而 sticky top 为 68px。最终偏移应按断点设置为桌面 85px、`<=720px` 83px。
- 修正后 390x844 滚动至页面底部(`scrollY=462`)时,页头底边与 sticky 顶边均为 83px重叠量为 0统一叫号卡仍完整可见下面队列内容正常从其后滚动。
- 移动端视觉截图确认:唯一大标题、快速叫号、按号码数量和按人数三项操作组成一个白色大卡;两个旧小标题和两张内层小卡已消失,底部导航未被覆盖。
- 真实叫号后通知正确显示“叫号已生效00015”“1 个号码,共 5 人”和可访问按钮“删除叫号通知”;跨步骤复查时通知已自动消失,证明真实页面的 5 秒清理链路已运行。
- 手动路径复验新通知“叫号已生效00016”出现后删除按钮从 1 个变为 0 个,通知立即移除。
- 自动路径精确复验通知“叫号已生效00017”在约 4.65 秒时仍存在,超过 5 秒后按钮计数变为 0符合从通知创建起 5 秒自动消失的口径。
- 1280x800 桌面滚动至最大 `scrollY=410.5` 后,页头底边和 sticky 顶边分别为 85px重叠量为 0页面无水平溢出统一叫号卡宽 1176px 并保持完整可操作。
- 桌面截图确认按号数和按人数操作共享同一卡片与标题,右侧人数操作通过一条轻量分隔线区分,不再形成第二张小卡。
- 断点边界复测发现 720px 页头为 87pxLogo 已进入窄屏尺寸但仍使用桌面 10px padding721px 页头为 85px需保留三档偏移默认 85px、621-720px 为 87px、<=620px 为 83px。
- 三档修正后 620/621/720/721px 四个边界的 header bottom 与 sticky top 分别精确相等83/87/87/85px四个视口重叠量均为 0。
- 浏览器验收结束前控制台 error/warn 均为空,临时响应式视口已恢复。
- 最终前端全量测试为 14 个文件、51 项全部通过;修改前曾失败的两项在最终工作树中也已恢复通过,无遗留测试失败。
- 目标文件与三份项目台账的 `git diff --check` 通过;仓库仍包含用户原有的大量未提交跨端/后端改动,本轮未清理、回退或暂存这些内容。
- 最终源码复核确认5 秒 effect 有 clearTimeout 清理;“删除”按钮为显式 `type=button` 且有可访问名称;叫号 API 参数、幂等键、禁用条件和两种按钮文案均未改变。
- 新增可见文案仅为“按号数/人数叫号”和“删除”,语义明确、无重复小标题;布局未引入滚动监听、第三方依赖或额外动画。
## Phase 28 创建项目与项目维护表单统一2026-07-15
- 创建页 `ProjectProfileForm` 当前只展示项目名称、项目编码和票号格式;项目维护页 `ProjectSettingsForm` 还展示项目状态、每次叫号数量、单号预计间隔和游客官方提示,两个页面的可见字段与布局不一致。
- 创建页向 `POST /api/admin/projects` 隐式发送 `timezone: "Asia/Shanghai"`;后端 `validateAdminProjectRequest``time.LoadLocation` 校验时区。
- 服务端运行镜像基于 Alpine未安装 `tzdata`,且 Go API 未导入 `time/tzdata`;在精简运行环境中可能无法加载 `Asia/Shanghai`,造成截图中的“项目时区无效”。
- 执行方案已获用户确认:创建页与维护页共用完整项目表单和默认值;时区继续使用维护页同样的默认值,不增加手填时区控件;服务端嵌入时区数据,并增加针对该回归的测试。
- 已将项目名称、编码、票号格式、状态、每次叫号数量、单号预计间隔和游客官方提示统一到 `ProjectForm`;创建提交沿用维护页的默认状态、数量、间隔和官方提示,并在创建基础记录后保存运行设置。
- Go API 的 `httpapi` 包已 blank-import `time/tzdata`,让 `Asia/Shanghai``CGO_ENABLED=0` 的 Alpine 运行镜像中也能被 `time.LoadLocation` 解析。
- 回归结果:前端 11 个测试文件共 38 项测试、TypeScript 检查、Vite 生产构建、Go 全量测试与 `go vet` 均通过;在 `ZONEINFO` 指向不存在路径时,默认时区回归测试仍通过。
## 员工端末号预计时长与闪屏2026-07-12
- `queueSnapshot` 当前把 `metrics.estimated_wait` 固定写成 `nil`,等待票的 `staffTicketView` 也未见按位置注入 ETA员工前端却只读取最后一张等待票的 `estimated_wait`,因此稳定落入“暂不可估算”。
- 后台、公屏和游客接口已经统一调用 `domain.CalculateETA`;员工快照应按 `waiting_count - 1` 作为末号前方人数,并传入项目级 `ETAIntervalSeconds` 与当前运行状态。
- 员工页场景入场动画依赖 `[scene, Boolean(queue)]`。初始渲染 `queue=false`,首个轮询响应后变为 `true`,整块页面会再次淡入/位移,视觉上表现为刷新闪屏;该动画应只随场景切换,不随轮询数据挂载重播。
- 修复后首次队列数据挂载只设置稳定终态;只有 `scene` 真正变化时才播放场景切换动画。五秒轮询仍保留,且沿用旧数据刷新,不卸载叫号主内容。
- `formatEstimatedWait` 现在优先识别服务端标准字段 `estimate_minutes`,单点预测展示为“约 N 分钟”避免同值上下界显示成“N-N 分钟”。
- 用户刷新后仍见“暂不可估算”的原因是开发 API 于 14:23 启动早于后端修复且不支持热更新Vite 前端已热更新,形成新前端配旧接口的状态,并非算法再次失效。
- 重启 API 后真实员工接口确认:云栖观光车项目/会话均为 `RUNNING`,配置每号 96 秒,等待 279 号,末号估算返回 `available=true, estimate_minutes=450`
- 继续排查周期性闪屏发现:`FreshnessBanner` 在每次五秒轮询开始时插入“更新中”段落,完成时删除,导致员工页主体随 DOM 高度变化上下跳动。健康的后台刷新不应占据布局;游客端已有顶部实时状态,管理端已有刷新按钮状态,删除该临时段落不损失必要反馈。
- 游客端另有两个直接消费 `resource.refreshing` 的可见状态:页头每三秒在“实时更新/更新中”之间切换,刷新按钮同步启用/禁用并改变样式。它们虽然不卸载主卡片,但会造成周期性色彩和透明度闪动;健康自动轮询应保持“实时更新”和按钮外观稳定,只在离线或陈旧时改变界面。
## 大屏全屏纵向布局2026-07-12
- 全屏信息顺序调整为:日期时间与项目名标题栏 -> 当前叫号 -> 自动轮播列表。
- 现有轮播分页和六秒切换逻辑可直接保留,只调整全屏结构与标题信息。
- “总计等待号数”与“最新取号码”同置于列表标题栏,删除底部重复等待统计。
## 大屏顶部信息优化2026-07-12
- 用户截图对应管理端 `ProjectScreenTile` 的单项目全屏状态,不是独立公示屏 `DisplayPage`
- 当前全屏顶部只有超大项目名和状态徽标,日期时间缺失,项目名称与主叫号数字竞争视觉注意力。
- 调整边界:日期时间仅在单项目全屏时显示在左上角;项目名称作为右侧上下文;项目状态从该大屏组件删除。
## 项目管理/规则配置拆分2026-07-11
- 当前 `/admin/projects` 只渲染 `ProjectSettingsForm`,内容是项目状态、叫号估算数、预计等待方式与参数,本质上是规则配置。
- 后端只有 `PUT /api/admin/projects/{id}/settings`,没有创建项目或维护项目基础信息的管理 API。
- `projects` 已包含可作为项目档案的 `name`/`code`/`timezone`/`ticket_prefix`,规则参数也已天然按项目行隔离,无需新建规则表。
- 最终交互边界:只保留“项目管理”导航;列表负责创建和进入维护,单个项目维护页同时包含基础信息与当前项目的规则配置。
- 时区不向管理员暴露,底层继续使用现有默认值保持数据兼容;票号不再手填前缀,界面仅提供 `00000` 格式选项。
- 项目名称/编码与运行状态/预计等待参数在管理交互中都是“项目维护字段”,不再使用基础信息和规则配置的视觉分区。
## 员工端 H5 GSAP 交互审计2026-07-11
- 员工端当前以 `/staff``/staff/tickets``/staff/me` 三个场景组织,核心动作是快速叫号、批量叫号、创建排队号码和切换项目。
- 当前已具备 busy、成功/警告/失败、轮询、离线/陈旧提示、幂等键等业务反馈GSAP 必须消费这些状态,不建立第二套状态。
- 最适合 GSAP 的位置是组合状态时间线:叫号结果与队列重排、取号指标更新、项目切换弹层、场景内容切换。按钮 hover/focus/press 继续使用 CSS。
- 批量叫号必须作为原子事件整体进入;禁止逐号 stagger、老虎机数字、弹跳、闪烁以及依赖动画回调执行业务。
- 轮询每 5 秒更新,不能每次都播放动画;只强调当前前台操作导致且 revision 前进的变化。页面恢复前台后直接展示权威快照,不补播旧动画。
- 所有动画应通过 `useGSAP` 限定作用域并清理,使用 `gsap.matchMedia()` 为 reduced motion 提供直接终态。
- 详细方案见 `docs/staff-h5-gsap-ux-plan.md`
- 实施采用单一 `motion/gsap.ts` 入口注册 `useGSAP` 与 Flip避免各组件重复注册插件。
- 场景动画依赖 `Boolean(queue)`,确保初始加载态结束、真实场景挂载后才播放;无授权项目时不再对空 selector 调用 GSAP。
- 测试环境固定匹配 reduced-motion 分支,使可访问性查询不会在动画中间态把内容判定为隐藏,同时保留业务和焦点行为测试。
## Phase 16 跨端对齐审计2026-07-11
- 员工端已以“单号快速叫号 + 1-100 手动数量叫号”为权威交互,后台仍暴露 `call_batch_size` 配置,会让运营人员误以为叫号数量由项目固定。
- 管理端仍有 `第 N 批` 兼容显示分支;新业务界面应始终展示实际号码/号段,内部 call batch 仅作事务和审计容器。
- 游客端存在硬编码“第 33 位 / 共 65 位”、`10:30` 和“每 30 秒”,与 API 真实 `people_ahead` 及 5 秒轮询逻辑冲突,必须改为真实投影。
- 大屏号段预测已从当前叫号尾号推导,可兼容每日五位数字号;用户语义应统一为“本次叫号/最近叫号”。
## 用户已确认的需求
- 员工端H5可取号、叫号。
- 游客端H5可查看排队情况和预估等待时间。
- 大屏端Web公示最新排队情况。
- 管理端Web管理预估规则、数据日志、账号等。
- 取号标识包含手机号、姓氏、性别。
- 支持批量叫号。
- 员工端与大屏可能外接硬件,必须预留接口。
- 先调研成熟案例并形成完整规划,确认后再实施。
- 一个系统需要支持多个景区游玩项目,排队、规则、员工权限、设备和数据均按项目区分。
- 系统应优先简单操作和轻量实现,避免复杂工作流、过度配置与笨重架构。
- 运营数据看板并入管理端开发,不单独建设一套看板系统。
- 面向用户的文案使用“预计等待时间/预计叫号时间”,不直接显示英文缩写 ETA。
- 员工端与管理端(含运营数据看板)均必须通过账号登录后访问;不提供匿名入口。
## 当前假设(尚未确认)
- 这是从零开始的绿地项目;仓库当前无业务代码或既有架构约束。
- 当前按“一个景区/运营主体下包含多个游玩项目”规划,不在 MVP 引入多租户或多景区集团层级。
- 游客 H5 的“查看”入口可能通过号码查询链接、二维码或手机号验证访问。
- 首期不直接承诺与特定品牌硬件绑定,而以设备适配层隔离。
## 未决决策
- 取号粒度:个人或同行团体。
- 游客能否自助取号、是否需要短信验证码、是否允许远程取号。
- 批量叫号的精确定义与操作上限。
- 过号、回呼、取消、迟到、优先队列、闭园和故障降级规则。
- 硬件类型、品牌、协议、部署网络及现场控制要求。
- 短信/公众号/小程序通知是否属于范围。
- 多景区/多运营主体、多租户、票务/闸机/CRM 集成是否属于后续范围MVP 只确认同一系统内的多项目。
- “看板并入管理端”当前解释为运营数据看板并入管理端,原需求中的游客公示大屏仍保留为只读页面;若用户所说“看板”即指公示大屏,需重新确认页面归属。
## Design Brief
- 模式:绿地产品,不是现有界面重设计。
- 设计目标:降低游客等待焦虑,提高员工高压操作正确率,让大屏在远距/强光下快速扫读,让管理端可审计且信息密度可控。
- 共同语言:可信、清晰、耐候、低焦虑;克制的景区品牌感建立在公共服务可读性之上。
- 四端差异:员工端高密度操作;游客端单任务引导;大屏远距信息;管理端数据/审计。
- 反方向AI 紫渐变、全面玻璃拟态、娱乐化霓虹、三等分通用卡片、无意义循环动画、用颜色作为唯一状态信号。
- Product Design 未发现已保存的用户设计上下文或品牌资产;本轮从当前需求与公开参考出发,品牌色/Logo 作为后续可替换层。
## Design Research Findings
- UI/UX 设计库的首轮综合检索返回了 `Accessible & Ethical` 风格和高对比深蓝/蓝色板,这与公共服务场景吻合;但同时误匹配了 App Store 落地页、Cinzel/Josefin Sans 等奢华地产表达,已明确排除。数据库推荐只能作为候选,不可替代场景判断。
- 针对性风格检索最符合的是 `Swiss Modernism 2.0 + Accessible & Ethical + Inclusive Design`:严格网格、数学间距、非装饰性层级、单一品牌强调色、高对比、清晰焦点与 reduced motion。
- 产品类型检索把本项目识别为 `Government/Public Service``Real-Time Monitoring/Analytics Dashboard` 的组合。推荐底座是 accessible minimalism实时监控只用于员工/管理端的信息组织,不采用 IoT 常见的全暗色玻璃拟态。
- 色彩候选中,公共服务深蓝方案和公共交通“蓝 + 橙”方案最相关。设计范式应把品牌主色与语义状态色分开:蓝色可承担品牌/交互,橙色只承担提醒或景区品牌点缀,红/绿/黄不可作为唯一状态编码。
- 简体中文字体检索明确支持 Noto Sans SC 单字体体系;首轮综合检索推荐的 Cinzel/Josefin Sans 缺少中文与公共服务适配性,排除。最终字体应优先系统中文字体栈或可自托管的 Noto Sans SC/思源黑体,数字可使用 tabular numerals。
- UX 检索强调44×44px 以上触控目标、3-4px 可见焦点、动画只作用于每屏 1-2 个关键元素、完整 loading/success/error 反馈、320/375/414/768/1024/1440 多断点验证。
- 图表检索建议等待趋势用折线图ETA 预测与实际用实线/虚线加预测带;项目比较用条形图;目标达成用 bullet chart时段拥挤用热力图但必须提供数值/表格替代。实时流图只在 ≥1Hz 且确有监控价值时使用,并提供暂停。
- GOV.UK 的官方设计原则与本项目高度一致:从用户需要开始、把复杂工作留给系统、为所有人设计、理解真实使用环境、建设完整服务而非孤立网页、保持一致但不强求四端完全相同。这支持“共享 token/语言,但按终端任务差异化”的设计范式。
- 中国侧可访问性底线可锚定现行 `GB/T 37668-2019`《信息技术 互联网内容无障碍可访问性技术要求与测试方法》。工信部适老化与无障碍改造通知进一步强调界面元素简化、信息扁平化、功能标识统一和操作流程一致;这些原则适用于游客 H5 的低认知负担设计,也适用于员工端在高压现场减少误操作。
- W3C《中文排版需求》最新工作草案2026-05-03提醒中文并非把西文字号规则机械替换即可设计需验证汉字字面、字重、行距、断行以及汉字与拉丁字母/数字/票号混排。项目因此统一采用清晰的中文无衬线字体并将号码、ETA、时间戳的等宽数字和中西文混排列入真机测试。
- 成熟公共服务/交通系统共同指向“公共服务导视式界面Public-service Wayfinding UI事务层使用 GOV.UK/NHS 的清晰、可恢复和低负担模式,状态与组件采用 USWDS 一类语义 token远距信息借鉴机场/公共交通导视。景区品牌只作为可替换的识别层不侵入号码、ETA、状态和关键操作区。
- 官方导视标准支持以下可落地约束:无衬线、开放字腔、稳定笔画;正文左对齐、不两端对齐、不压在复杂图片上;长行控制在约 6070 个西文字符等效范围。大屏字号不能只按 CSS px 验收,应按最远观看距离和屏幕实物字符高度做上午/正午/傍晚与斜视角测试。
- 动效原则收敛为“克制、快速、状态优先”:普通交互首选 CSSReact 条件面板才使用 MotionGSAP 只允许进入大屏多区域同步换批等真正需要可中断时间线的少量场景。批量叫号必须作为一个原子批次同时出现,禁止逐号 stagger、老虎机数字、弹跳、闪烁、跑马灯和恢复前台后补播旧动画。
- 建议动效 token按压 100ms、快速状态 150ms、标准面板 200ms、员工批次更新 300ms、大屏整体换批不超过 400ms低动效仅保留不超过 100150ms 的透明度/高亮,无动效为 0ms。业务提交、硬件命令、语音与动画并行响应同一事件任何业务逻辑不得依赖动画完成回调。
- Page Visibility 与浏览器节流意味着 ETA、过号、叫号宽限和硬件执行都不能依赖前端计时器。标签页恢复时应先拉取服务端权威快照和 revision直接显示最新状态不重放隐藏期间的动画、提示音或语音。
- 排队产品 UI 专项核验收敛出 7 个成熟模式Visitor Status Ticket、Operational Call Card、Batch Action Bar、Call Takeover、Live Ops Strip、Offline Trust Banner、Hardware Receipt Tray。前四项在 Qmatic/Waitwhile 公开资料中有直接界面或帮助文档证据;离线/硬件闭环可从 Wavetec/Qmatic 核验能力,但“多通道 ACK + 局部重试”并无成熟公开 UI仍需本项目自定义。
- 厂商公开证据边界Waitwhile 能证明批量 Serve/Alert/No Show 等操作,不能证明容量自动选组、原子事务、并发冲突和硬件 ACKQmatic 能证明单票叫号/转移/过号和多硬件,未证明多人原子批量叫号;因此不能从营销截图推断这些关键交互已经成熟。
- USWDS 使用语义颜色 token而非在组件里硬编码其官方可访问性指南强调颜色不能成为唯一含义。对本项目意味着品牌色、交互色、状态色和图表色必须分层状态还需文字、图标和形状。
- WCAG 2.2 官方标准确认:普通文本至少 4.5:1、大字 3:1支持 200% 文本缩放;焦点不可被遮挡;状态消息应能被辅助技术读取而不强制抢焦点;动画与闪烁需有暂停/停止/隐藏或 reduced motion 方案。
- TfL 的官方标准把一致的品牌、字体、颜色与安全/信心直接关联,并要求根据交通模式与环境选择正确标准。其导视强调清晰视线、图文结合、环境适配,而不是把一套 Web 卡片放大到屏幕。
- GOV.UK 错误消息规范要求错误具体、可修复、与字段标签语言一致,避免“发生错误”“必填”等泛化文案。这应作为员工取号表单和管理配置表单的文案标准。
## Research Findings
- 浏览器硬件 API 不能作为唯一的生产级硬件方案:截至 2026-07WebUSB、Web Serial、WebHID 仍是“Limited availability”且通常要求 HTTPS、安全上下文、用户授权/手势及特定浏览器支持。
- Web Serial 可连接物理串口以及通过 USB/Bluetooth 模拟串口的设备;首次授权需用户主动选择端口。它适合受控 Chromium 终端上的可选直连模式,不适合作为任意游客手机/任意浏览器的必备能力。
- 公网页面访问本地网络设备正在受到更严格的权限控制。Chrome 142 起推出 Local Network Access 权限提示;本地设备的 HTTP/HTTPS、CORS、证书及浏览器策略都会影响直连可靠性。
- 初步架构推论:硬件集成应有独立的“设备网关/本地代理”作为主路径以云端下发设备命令、本地驱动适配、回传执行回执WebUSB/Web Serial/WebHID 仅作为受控终端的可选适配器。所有设备命令都需幂等键、超时、重试、状态回执和手动降级。
- Waitwhile 的公开 API/帮助资料提供了一套可借鉴的领域拆分Location/Queue、Service、Resource窗口/通道/员工、Customer、Visit。Visit 的主状态包含 WAITING、SERVING、COMPLETE另有取消、到达、优先等标签/状态;事件以 visit.created/updated/removed、location-status.updated、message.created/updated 等 webhook 对外分发。
- Waitwhile 的 Visit 示例同时包含 `partySize`、票号、队列位置、原始/当前预估等待时长等字段,说明成熟产品通常把“访客资料”和“一次排队访问”分开,并显式支持同行人数。
- 成熟产品把游客个人状态页与公共大屏分开个人页可展示实时位置、ETA并允许到达/延迟/退出;公共屏可只显示票号/脱敏标识、正在服务及窗口/资源,且可播放声音。
- Waitwhile 的 API 允许一次创建或更新多个 Visit但其“批量消息”不等于“批量叫号”。这进一步说明本项目必须定义批量叫号的原子语义而不能把多选 UI 当作完整业务规则。
- 成熟系统记录账号、访客、队列访问、消息和配置变更等审计条目;并公开 409 并发冲突与 429 限流行为。对本项目的启示是叫号写操作需要乐观并发/串行化、幂等、重试边界和完整审计。
- 国内景区已有与本项目高度相似且可核验的成熟实操:
- 梵净山红云金顶采用扫码预约叫号,小程序展示预约号/当前叫号并在接近时提醒;现场广播和电子屏按连续号段(示例为 1736—1835批量播报引导游客在等待时游览其他点位。这直接证明“批量叫号”应支持按容量叫连续号段并把 H5、提醒、广播、大屏统一在同一批次事件下。
- 长江索道通过售票窗口、自助机、微信公众号、OTA 等多入口实名购票取号,按号段、分时段乘坐;游客可在线查看排队进程并离开现场等候。其经验表明取号来源要统一归一化,队列票应可关联外部票务凭证,但不应把票务系统直接耦合进核心状态机。
- 陶然亭公园游船把云上排队、叫号登船、游船启航控制、广播、收银、定位和统计结合。其经验表明叫号系统可能最终进入“运营控制”边界,硬件命令与安全关键的启航控制必须分级授权、独立审计,不能由普通大屏页面直接触发。
- 国内案例还显示两种常见容量模型:红云金顶/长江索道属于按号段或批次放行,游船属于资源/船次容量调度。因此 ETA 不能只有“每人平均服务分钟数”一种公式,至少需支持连续服务与批次/班次两类规则。
- 国际主题乐园的官方资料进一步验证了几个共性:
- Disney、Universal、Europa-Park、USJ 普遍将门票/账户/同行组作为核销与排队主体,一人可为全组操作;成熟系统不会把姓名等弱标识当数据库主键。
- 主流体验通常使用 boarding group、return window 或系统分配时段,并明确名额有限、可能停发/暂停,且不承诺静态精确分钟数。
- 过号策略差异很大Disney 表述为迟到可能不予接待Europa-Park 明确迟到失去位置并需重新排队;这证明宽限、重排和重叫必须是项目级可配置规则。
- Volcano Bay 的 TapuTapu 用射频腕带、reader、振动提醒并支持遗失挂起/解绑Disney/Universal 也使用 QR/NFC/实体票。这些案例支持“身份/核销凭证抽象 + 设备适配器”,而非绑定手机号或某一硬件协议。
- 多数官方游客材料不披露员工批量叫号 UI 和内部算法。可以确认 boarding group/号段/容量配额具备批量放行语义,但不能声称已核验某家具体的员工端按钮设计。
- 同行组应当成为一等业务对象:一个排队单需记录 `party_size` 及成员/外部票凭证(可选);按容量批量叫号默认不得无提示拆组,拆组或跳过大组必须授权并留痕。
- 通用厂商对照补充:
- Waitwhile 是公开资料中对批量操作证据最明确的产品,可多选 Visit/活动参与者执行 Alert、Serve 等操作,并公开 REST、Webhook、认证、限流和重试文档但官方明确核心产品没有正式离线模式。
- Qmatic 公开能力主要是 Call next、指定号码、Recall/Recycle/No-show优势是本地 Orchestra/Queue Agent 与打印、屏幕、语音硬件体系。其 Data Connect 是只读且非实时,不能被误用为叫号接口。
- Wavetec 公开案例展示本地 Controller、打印/语音/屏幕、双向 REST 与恢复后云同步,硬件/边缘模式成熟;但没有核验到一次叫多条独立票的公开证据。
- Qtrac、QLess 偏云端/浏览器和多渠道通知;公开材料不足以证明真正的批量多人叫号或断网自治。
- 行业结论是“批量叫号并非通用标配”。本项目的按人数/设备容量批量放行是核心差异,必须自建明确原子语义,而不是假定现成产品天然具备。
- Waitwhile 的 SUMMIT One Vanderbilt 案例按设施吞吐管理游客组:游客扫码/员工平板登记、填写同行人数,在场馆内活动,到时系统召集下一组。这是“同行组 + 设施容量 + 运营批次”的直接参考;页面所列效果与流量数字属于厂商案例自报。
- 合规核验结论:
- 手机号、姓氏、性别与游客关联后均属于个人信息;处理需目的明确、最小必要、事前告知并采用最短必要保存期限。
- 2025 年专项治理明确点名线下消费场景强制收集非必要手机号、生日、性别;仅写“用于取号标识”不足以自动证明三项均必要。
- 上述字段本身不在《个人信息保护法》第28条明确列举的敏感个人信息类别中但聚合风险可能改变保护等级不满14周岁未成年人的个人信息属于敏感个人信息。
- 大屏/广播若仍能对应具体游客,属于公开个人信息,应单独评估合法性/同意与保护影响;仅做手机号星号掩码并不自动等于匿名化。
- 网络运行/安全日志依法至少保留6个月普通排队身份映射没有全国统一天数应按最短必要个人信息保护影响评估和委托/提供处理记录至少保留3年。
- 合规产品建议:公开屏和广播默认只使用随机票号;提供不依赖手机号的现场二维码/纸质号替代;儿童随监护人同行组处理;手机号只在短信/OTP/找回确有需要时收集;性别改为可选称谓或取消。
- ETA 研究结论Little's Law `L=λW` 适合长期/稳定窗口的平均校验,不等于实时个人 ETA景区午高峰、停机和增减资源是非平稳场景直接用“人数÷到达率”会误导。
- ETA 应使用完成/放行吞吐而非游客到达率。批次项目基础公式可写为:`距下一批时间 + (ceil((前方有效人数 + 本组人数) / 预计实际批容量) - 1) × 预计批次间隔`;实际容量应来自近期真实入场而非名义容量。
- 游客展示应称“预测区间”而不是统计学上的置信区间建议四舍五入到5分钟显示高/中/低可信度、更新时间,并分别定义“预计叫到号”和“预计开始体验”两个可能的终点。
## 技术/产品决策
| Decision | Rationale |
|----------|-----------|
| 硬件采用抽象设备命令 + 本地设备网关,浏览器直连只作为可选方案 | 浏览器硬件 API 兼容性、授权和本地网络策略无法满足多硬件/多终端的稳定生产要求 |
| 大屏终端需支持保活、断线缓存和连接健康上报 | 大屏属于长时间运行终端;浏览器虽有 Screen Wake Lock但旧设备兼容和权限仍需降级策略 |
| 客户Visitor与一次排队单Queue Ticket/Visit分表 | 同一游客可多次排队排队状态、ETA 与审计属于一次访问而非永久身份资料 |
| 将批量叫号建模为独立 Call Batch而非循环调用单号接口 | 需要原子选择、部分失败规则、统一回执、撤销边界和硬件播报一致性 |
| 游客个人状态页与公共大屏使用不同数据投影 | 权限、隐私、交互和刷新粒度不同,不能复用同一返回模型 |
| 大屏/广播默认只使用随机票号 | 手机号/姓氏/性别的公开必要性不足,且现场组合信息可能重新识别游客 |
| ETA 使用完成吞吐、批次容量和区间预测,不用到达率直接相除 | Little's Law 的稳定平均前提不适合非平稳实时队列;批次设施还受周期和实际载客量影响 |
| 先锁定队列修订行/CAS再比较客户端修订号 | 避免两个并发叫号请求先同时通过版本校验,后到者等锁后仍沿用旧候选集 |
| 严格 FIFO 且不拆组时ETA 复用逐组装箱算法 | `总人数÷容量` 忽略批次容量碎片,只能作为允许拆组时的近似下界 |
| MVP 的 `CallBatch` 只保留 ACTIVE/PARTIALLY_RESOLVED/RESOLVED | 覆盖叫号、部分到场/过号和结束WITHDRAWN 撤回属于 P1避免首期复杂逆向状态 |
## Phase 10端结构重构发现
- 当前管理端只有 `/admin` 概览,后端已经提供项目参数更新接口;本轮可补齐项目管理表单,而不需要扩展服务端。
- 公示屏的公开令牌只保存哈希,管理概览不能重建现有 `/display/:token` 地址。因此大屏中心应以内置、受管理员保护的实时监控墙为主,物理公示屏继续沿用原有绑定 URL。
- 当前员工页把取号、批次核验、队首预览和叫号堆在一屏。重构为 `/staff``/staff/tickets``/staff/verify` 三个 H5 场景入口,可复用全部既有 API、幂等和项目授权逻辑。
- 设计采用公共服务导视式运营界面桌面端左侧任务导航与高密度表格H5 仅在当前场景呈现必要信息;不采用营销页面式视觉、装饰动效或新组件依赖。
| 硬件确认后再拆分下行 DeviceCommand 与上行 DeviceEvent | MVP 只保留统一接口和模拟成功/失败;扫码/按钮/完整 ACK 在具体硬件型号确认后实现 |
| taste 的建议只作用于品牌表达和反模板化检查 | 该 skill 明确不适合仪表盘、数据表与多步骤产品 UI后台基础应选择成熟可访问组件模式 |
| GSAP 不作为全局默认动画库 | 简单状态反馈用 CSS/框架原生轻量过渡;只有大屏确有可中断多区域时间线需求时才评估 GSAP并强制 reduced motion/清理 |
| 设计范式采用“公共服务导视型 Calm Utility” | 公共服务事务清晰度、交通导视和现场运营稳定性比旅游营销或科技大屏风格更适合四端场景 |
| 四端共享语义 token但采用不同密度/信息层级 | 游客需要单主状态,员工需要高压操作,大屏需要远距扫读,管理端需要高密度审计;一致不等于相同 |
| 临时使用高对比蓝 + 暖橙品牌层VI 到位后通过 alias 替换 | 当前没有既有品牌资产;语义状态、对比度、焦点和关键布局不能被品牌替换改变 |
| MVP 动效以 CSS/框架原生轻量过渡为主 | GSAP 只有大屏出现确切的可中断多区域时间线需求时才评估,且不能进入业务提交或设备控制链路 |
| 公共使用每日可读票号,私密查询使用高熵 token | 兼顾远距可读性与抗枚举;公开票号本身不能成为个人状态查询凭证 |
| WCAG 2.2 AA 与 GB/T 37668-2019 基线随 MVP 交付 | 无障碍不是后补功能P1 只承载多语言、AAA 或专项辅助设备增强 |
| MVP 采用轻量模块化单体,不引入微服务、工作流引擎、规则 DSL 或事件溯源 | 用户明确要求系统不笨重;队列正确性保留在清晰的数据库事务中,其余能力按真实需求逐步增加 |
| 运营数据看板作为管理端模块 | 共用账号、权限、项目筛选和数据接口,避免多建一个前端应用与部署单元 |
| 以 `project_id` 作为核心业务边界 | 一个系统支持多个项目,但共用同一数据库和代码;项目分别拥有队列、规则、号段、设备、人员权限与统计 |
| 用户界面不用 ETA 缩写 | 对游客和现场员工统一写“预计等待时间”或“预计叫号时间”,降低理解成本 |
| 员工端与管理端看板均采用账号登录 + 项目授权 | 员工和管理员身份、可见项目与操作范围需要可追溯;游客状态页和公示屏仍使用受控无账号访问 |
## 风险与边界
- 手机号、姓氏、性别均涉及个人信息处理,大屏必须脱敏,日志需最小化留存与受控访问。
- 等待时间是动态估计,不宜呈现为确定承诺;需要区间、更新时间与异常降级。
- 叫号是高并发实时操作,必须防止重复叫号、跳号和多员工竞争导致的不一致。
- 浏览器直连本地硬件能力有限且兼容性不一,硬件接口不能只定义成前端 JavaScript API。
## 轻量化复核2026-07-10 用户补充后)
- 原规划中的三类预计时间模型、完整规则版本审批、独立实时/设备工作进程等内容适合作为能力上限,但若整体进入 MVP 会违背“操作简单、系统不笨重”的新约束。
- MVP 应只实现首批项目实际需要的一种预计等待计算方式;同一项目只保存容量、批次间隔/平均处理时长、人工暂停等少量参数,高级回放、权重融合、复杂规则版本和机器学习后移。
- 管理端的运营数据看板与规则管理共用一个 Web 应用;游客公示大屏保留只读路由,不另建管理看板应用。
- 技术实现进一步收敛为一个后端应用、一个 PostgreSQL、同一代码库中的 H5/管理/公示页面Redis、独立消息中间件、微服务和通用工作流引擎均不是 MVP 前提。
- 多项目采用同库同表 `project_id` 隔离,不做每项目一套部署/数据库,也不先建设组织—租户—景区—项目的多级继承。账号通过项目授权表访问一个或多个项目。
- 多项目下必须独立的最小范围:队列状态、票号前缀/序列、容量/预计时间参数、员工权限、设备绑定、营业状态和报表筛选;跨项目总览只放在管理端。
- 文档一致性复核发现旧版高级内容仍散落在领域对象、指标、测试和默认架构中(预计规则版本/逐次快照、复杂误差指标、定时发布回放、事务 Outbox/独立网关默认值);这些需要同步降级为简单配置、关键节点记录、基础误差统计和数据库待发送表/可选设备网关。
- 二次复核还发现硬件章节、管理接口和设计验收仍默认完整设备网关/规则发布流程。轻量版应把网关标为“真实硬件需要时选配”,管理接口改为项目预计时间设置,设计验收改为当前值/上一版/审计,而不是版本 diff 与发布流程。
- 最终轻量 MVP 已冻结为:四种项目状态(未开放/运行/暂停/结束)、唯一 `CALL_NEXT`、严格 FIFO、不拆组、不跳组、装不下即欠载员工主界面没有手选、预叫、撤回或复杂规则。
- 硬件 MVP 只保留统一适配接口、模拟成功/失败和测试记录;注册配对、心跳、完整 ACK、扫码/按钮上行与本地网关均以具体硬件型号确认为前提。
- `project_id` 已形成闭环契约覆盖所有项目级记录、唯一键、查询更新、统计审计、SSE 频道、设备命令和接口授权;项目范围由服务端从账号、查询令牌或设备绑定确定。
- 独立复核确认上述轻量化、多项目、看板归属和中文预计时间术语均无剩余 P1 问题。
## Resources
- MDN WebUSB API: https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API
- MDN Web Serial API: https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API
- web.dev Accessing hardware devices on the web: https://web.dev/articles/devices-introduction
- Chrome Web Serial guide: https://developer.chrome.com/docs/capabilities/serial
- Chrome Local Network Access update: https://developer.chrome.com/blog/local-network-access
- MDN Screen Wake Lock API: https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API
- Waitwhile API - List visits: https://developers.waitwhile.com/reference/listvisits
- Waitwhile API - Webhooks: https://developers.waitwhile.com/reference/webhooks-2
- Waitwhile webhook examples: https://developers.waitwhile.com/docs/webhook-response-examples
- Waitwhile audit entries: https://developers.waitwhile.com/docs/tracking-changes-with-audit-entries
- Waitwhile customer status page: https://help.waitwhile.com/en/articles/9949637-the-customer-status-page-real-time-updates-for-your-customers
- Waitwhile public/serving display: https://help.waitwhile.com/en/articles/11370712-how-to-use-the-waitlist-display-to-direct-customers-to-a-counter
- 梵净山扫码预约、当前叫号、号段广播(贵州省人大转载贵州日报): https://www.gzrd.gov.cn/gzwh/202505/t20250530_87945751.html
- 长江索道智能分流、按号段分时乘坐(重庆市政府): https://www.cq.gov.cn/ywdt/bmts/201809/t20180921_8655058.html
- 长江索道在线查看排队进程重庆市政府2025: https://www.cq.gov.cn/zwgk/zfxxgkml/zdlyxxgk/ggwh/ly/zxdt/202503/t20250311_14394287.html
- 陶然亭公园云排队、叫号、广播与启航控制(北京市公园管理中心): https://gygl.beijing.gov.cn/xxgk/xxgk_gyxx/202203/t20220321_2635717.html
- Disney World Virtual Queue: https://disneyworld.disney.go.com/en_CA/guest-services/virtual-queue/
- Universal Studios Hollywood Virtual Line: https://www.universalstudioshollywood.com/web/en/us/plan-your-visit/virtual-line
- Universal Orlando Virtual Line: https://www.universalorlando.com/web/en/us/plan-your-visit/virtual-line
- Europa-Park VirtualLine: https://www.europapark.de/en/theme-park/info/plan-your-visit/virtualline-europa-park
- Universal Studios Japan 预约乘坐: https://www.usj.co.jp/web/zh/cn/enjoy/numbered-ticket/yoyakunori
- Universal Volcano Bay TapuTapu FAQ: https://www.universalorlando.com/web/en/us/plan-your-visit/taputapu-faq
- Waitwhile 批量操作: https://help.waitwhile.com/en/articles/8061037-navigating-the-visits-page
- Waitwhile SUMMIT One Vanderbilt: https://waitwhile.com/case-studies/summit-one-vanderbilt/
- Waitwhile 离线能力说明: https://help.waitwhile.com/en/articles/11603596-does-waitwhile-work-without-internet
- Qmatic Serve View: https://docs.qmatic.io/en/staff-user-guides/user-guide--serve-view.html
- Qmatic Queue Agent: https://docs.qmatic.io/en/service-and-branch-configuration/branch-configuration/about-branches.html
- Qmatic Data Connect 限制: https://data-connect.docs.qmatic.io/developerguide.html
- Wavetec Wasl 本地分支与云同步案例: https://www.wavetec.com/es/case-studies/wasl-properties-customer-experience-transformation/
- Qtrac Virtual Queuing: https://qtrac.com/virtual-queuing/
- QLess Products: https://www.qless.com/products/
- 《个人信息保护法》: https://www.cac.gov.cn/2021-08/20/c_1631050028355286.htm
- 2025 年个人信息保护专项行动: https://www.cac.gov.cn/2025-03/28/c_1744867353112759.htm
- 《网络数据安全管理条例》: https://app.www.gov.cn/govdata/gov/202409/30/520076/article.html
- GB/T 45574-2025 敏感个人信息处理安全要求: https://openstd.samr.gov.cn/bzgk/std/newGbInfo?hcno=F9F3A2EBF49E9B4D73AD8C8912986D5A
- Little's Law 原始论文: https://pubsonline.informs.org/doi/10.1287/opre.9.3.383
- Time-Varying Little's Law: https://www.cambridge.org/core/journals/probability-in-the-engineering-and-informational-sciences/article/abs/estimating-waiting-times-with-the-timevarying-littles-law/18BF94EF65D06A5E52B72D1F81F3BFE0
## Browser Findings
- MDN 将 WebUSB页面更新 2025-07-12和 Web Serial页面更新 2026-05-26标注为非 Baseline/有限可用,并说明仅安全上下文可用。
- Chrome 文档说明 Web Serial/WebUSB 的设备选择必须由用户手势触发,且单设备权限由用户显式授予。
- Chrome Local Network Access 文档(更新说明覆盖至 2025-09-29显示 Chrome 142 推出访问局域网设备的权限提示;这会影响公网页面直连本地打印机、控制器或网关。
- Waitwhile API 状态与 webhook 示例显示,成熟排队产品使用明确 Visit 状态、位置/ETA 字段和前后快照事件;其帮助中心将个人状态页面与 TV/Serving Display 拆分配置。
- 梵净山资料给出了完整现场链路:手机实时队列 → 接近提醒 → 广播/电子屏按号段叫号 → 闸机入场;这是当前最贴近用户需求的国内参考案例。
- 国际案例中同行组、门票凭证、return window、容量限额、迟到处理和多通道核销是反复出现的成熟模式应吸收其领域模型不照搬依赖原生 App 或自有腕带的交互前提。
- 五家通用厂商的公开资料证明游客状态页、ETA、大屏、短信、硬件代理和审计已成熟但真正的多人批量叫号与断网自治不能靠营销词推断均需明确合同/POC。
## 实施冻结决策2026-07-10
- 用户已在最新完整摘要后明确回复“确认,可以执行”,需求确认门槛已打开。
- MVP 采用中心服务唯一写入;完全断网时停止数字化取号/叫号并切换人工预案。
- 取号为一人一号;同一手机号允许在同一项目持有多个活动号码,员工确认重复提示后继续并留审计。
- 取号字段为手机号必填、姓氏和称谓选填,称谓默认“游客”,不采集法定性别;大屏只显示票号。
- 批量叫号为每项目固定 N、严格 FIFO 的连续号码;不足 N 时叫剩余号码,不手选、不跳号。
- 过号后原号码失效,若继续排队则由员工重新取新号进入队尾。
- 预计等待时间首期支持固定批次与连续放行两种简单模板,每项目二选一。
- 认证首期为内置账号密码、RBAC 和项目范围,预留 SSO/OIDC。
- 技术栈冻结为 React + TypeScript + Vite 前端Go + GORM + PostgreSQL 后端;核心叫号事务显式使用锁、幂等和约束。
- 硬件首期只交付统一接口、成功/失败模拟器和测试日志。
- 留存默认值:个人关联 30 天、原始业务事件 90 天后匿名化、安全日志至少 6 个月、后台审计 1 年、影响评估记录 3 年。
- 当前本机已发现 Node.js 22.22.3、pnpm 10.33.2、npm 10.9.8;未发现 Go、Docker 或 psql需要在实现阶段建立可复现运行环境。
## Phase 7 实施发现
- 已安装 Go 1.26.5 与 PostgreSQL 17.10;本地开发数据库使用角色/库 `queue`
- 初版迁移从数据库层落实项目级外键、项目/营业日票号唯一、公开 token 哈希唯一、手机号 HMAC 活动索引、审计留存时间、幂等键唯一和设备模拟结果约束。
- GORM 仅承担模型与常规查询;固定 N 叫号仍需在同一显式事务中锁定 `queue_sessions`、读取 FIFO 票号、创建批次、推进票状态、增加 revision 并写审计/幂等响应。
- 独立契约审查证明“可编译/可构建”不足以替代端到端响应核验:公示投影必须使用独立白名单 DTO管理项目行必须返回真实指标客户端同一提交意图必须复用幂等键。
- “过号后重新取号”需要一等业务动作而非仅靠普通取号表单:原票与新票应有唯一关联、服务端锁/revision/幂等保护和显式审计。
- 连接新鲜度必须按最近一次成功请求判断,不能用最后一次业务状态变化时间代替;空闲但健康的队列不会持续产生 `updated_at`
- 公示屏的公开 DTO 刻意不暴露内部主键,因此前端列表稳定键应由公开且会话内唯一的批次号/叫号时间组成,不能假定内部 DTO 字段存在。
- 最终纵向切片已通过真实 PostgreSQL、增强 API 烟测、Go 竞态测试、13 项前端测试、生产构建和四端浏览器验收;当前可作为真实硬件接入与现场试点的开发基线。
## Phase 8 变更边界2026-07-10
- 员工端与管理端需要在已登录且通过 `project_id` 授权的上下文中,显示票号、完整手机号、姓氏/称谓和状态之间的对应关系。
- 游客状态页由高熵私密 token 授权,只增加联系手机号尾四位用于自我核对,不返回完整手机号。
- 公示屏的公开白名单契约保持不变,任何序列化结果均不得出现 `phone` 字段。
- “真实测试”定义为:数据写入本机 PostgreSQL经过正在运行的 Go API 读写,并由 React 页面实际渲染和浏览器操作验证;测试手机号是明确的受控测试值,不使用组件 mock 或静态假响应冒充联调结果。
- 现有手机号和姓氏已经使用 AES-GCM 加密存储,附加认证数据分别是 `phone:{project_id}``last_name:{project_id}`;无需也不应新增数据库明文字段。
- 当前 `ticketView` 是不持有 cipher 的包级函数,且只返回 honorific内部 DTO 若要返回完整手机号/姓氏,需要改为经过 `Server` 解密的授权投影,解密失败必须让请求失败而不是静默返回错误对应关系。
- 管理概览路由已有 ADMIN 门槛;员工队列路由已有账号项目授权。新增完整手机号只能落在这两类现有鉴权路由,不能复用到公示 DTO。
- 当前真实 PostgreSQL 中已有多条 AES-GCM 密文记录:手机号密文 27 字节、nonce 12 字节、HMAC 64 字符,证明页面此前缺少对应关系是读模型/展示问题,不是数据未落库。
- 员工端需要同时覆盖“等待队列表”和“当前批次卡片”;只在等待表加手机号会导致叫到后立刻失去号码与联系方式对应关系。
- 管理端目前只有项目汇总,新增活动号码表应限制为 WAITING/CALLED/ARRIVED 等仍需现场处理的状态,避免运营首页默认展开历史个人信息。
- 后端已将员工票号投影改为经 `Server` cipher 解密的授权 DTO覆盖等待队列、当前批次、创建、叫号、状态迁移和重新取号响应任一密文认证失败会让请求失败不会产生错配的空手机号。
- 管理端 `active_tickets` 只选择 WAITING/CALLED/ARRIVED游客响应只增加 `phone_last4`;公示 DTO 仍是独立结构,未复用内部票号视图。
- 前端员工端同时覆盖队首预览、等待表和当前批次,管理端新增活动号码表;公屏 `BatchCard` 默认 `showContactDetails=false`,只有员工端显式开启。
- 真实浏览器/实库记录 A0009 验证通过:员工端将 A0009、受控完整手机号与“实测女士”对应游客私密页只显示尾号 8042管理端活动号码表显示同一完整对应关系公屏 DOM 不含完整测试手机号或“手机号”标签。
- 独立审查发现事务边界细节:状态迁移若在提交后才解密并组装响应,密文损坏会让数据库已变更但客户端收到 500。个人字段授权投影属于事务成功条件必须在 commit 前构造。
- 真实烟测不能只验证静态 waiting/admin 投影;创建、叫号/current batch、状态动作和重新取号都各自序列化票号必须逐路径验证手机号/姓氏连续性,并在结束时清理活动批次以支持重复执行。
- 最终桌面视觉复核中,员工端把手机号作为队首预览的次级信息且保留固定底部叫号动作;管理端活动号码表在首屏内清晰对应项目、票号、完整手机号、姓氏/称谓、状态和时间,没有挤压原项目总览。
- 四个新鲜标签页的浏览器控制台均无 error/warn。
- 390×844 真实员工页面包含 A0009 和完整测试手机号document scrollWidth 375 小于 innerWidth 390新增手机号列仍被表格自己的横向滚动容器约束没有造成整页横向溢出。
- `go run` 作为后台烟测进程时,父进程退出与编译后二进制释放数据库连接之间存在竞态;临时数据库清理应运行可直接控制 PID 的构建产物,并用 PostgreSQL `dropdb --force` 收口残余连接。
- 最终 `make smoke-real` 改为构建单一临时 API 二进制;连续两次运行均完成真实迁移/写入/全路径断言,且每次结束后临时数据库计数都回到 0。
## Phase 9 尺寸边界2026-07-10
- 员工端与游客端按手机 H5 处理,固定参考宽度为 390px实际设备视口小于 390px 时必须使用 100% 宽度,不能产生整页横向滚动。
- “固定尺寸”只固定设计宽度,不固定页面高度;员工表格和长内容仍在页面/局部容器内正常滚动。
- 管理端和公示屏分别面向桌面运营与远距大屏,不能被手机端 max-width 规则误伤。
- 当前员工与管理端共用无变体的 `AppShell`,因此不能直接给 `.app-shell` 限宽;需要增加仅 StaffPage 使用的 mobile variant避免管理端一起变成 390px。
- 现有员工单列布局主要由 viewport `@media (max-width: 767px)` 触发;固定 390px 容器在桌面 viewport 下仍会命中桌面双列规则,因此 mobile variant 还必须显式覆盖 header、main、staff-layout、project picker 和固定底栏布局。
- 实现采用 `AppShell variant="mobile"`,只由 StaffPage 启用;选择器以 `.app-shell--mobile ...` 提高作用域,因此后续通用 media query 不会把管理端限宽。
- 员工固定操作栏使用 `left: 50% + translateX(-50%) + width: min(100%, 390px)` 与手机画布同宽;游客页和登录卡同样收敛到 390px宽表格仍由 `.table-scroll` 局部滚动。
- 1280px 桌面窗口实测:员工 shell=390px、底部叫号栏=390px游客页=390px管理端和公屏均为 1265px证明手机规则未污染桌面路由。
- 桌面截图确认员工 H5 以居中手机画布呈现header、单列内容和固定叫号栏对齐同一宽度。
- 390×844 实际视口复验:员工 shell=390px、固定叫号栏=390px、document scrollWidth=390px游客页=390px、scrollWidth=390px并继续显示真实尾号 8042。
- 独立尺寸审查指出 `viewport-fit=cover` 下顶部还需 safe-area inset固定栏的主内容预留不能小于文本放大后的栏高登录页父级 16px padding 会让 414px 视口中的 390px 卡片缩水到 382px。
- 上述三项已修复:员工、游客与登录页覆盖四向安全区;员工主内容和固定栏共用 `180px + safe-bottom` 预留,项目/状态长文本单行省略;登录页用动态左右留白确保 414px 视口中的卡片为 390px。
- 四档真实浏览器回归通过:员工 shell/底栏在 320、375、390、414px 视口分别为 320、375、390、390px登录卡同样分别为 320、375、390、390px均无整页横向溢出。
- 游客页四档回归均无横向溢出且继续显示真实手机号尾号1280px 桌面复核中员工/游客保持 390px管理端/公屏保持约 1265px四端控制台无 error/warn。
- 为避免只在空列表上验收,通过真实员工页面向开发 PostgreSQL 创建 A0010员工端与管理端显示 `A0010 / 13800138042 / 尺寸实测女士`,游客私密页只显示 A0010 与尾号 8042。
- A0010 存在时的 390px 员工页 document scrollWidth=390px760px 宽的号码表被 322px 的局部 `.table-scroll` 正确约束,没有把整页撑宽。
## Phase 11 全平台功能文案极简化2026-07-11
- 用户要求所有平台删除非必要标题、说明、备注、副标题、设计思考和约束表达,只保留直接完成任务所需的按钮、字段、数据与状态。
- 采用公共服务产品界面的保守边界:不删除表单标签、表头、按钮名称、票号/手机号/人数/时间、成功/错误反馈、必要空态、隐私最小披露和辅助技术名称。
- 本轮只改前端内容层级与相应间距,不改变路由、业务接口、权限、字段顺序、状态机或隐私投影。
- 设计方向读取为:面向现场员工、管理员和游客的高密度公共服务产品界面,低变化、低动效、高信息密度;`DESIGN_VARIANCE=3``MOTION_INTENSITY=2``VISUAL_DENSITY=8`,沿用现有原生 CSS 设计系统。
- 初步字符串扫描显示冗余主要集中在 `page-heading` 的 eyebrow+H1+说明三层、panel 的 eyebrow+标题、项目上下文备注、Freshness 常态时间、EmptyState 描述和卡片总结句;按钮、表单标签、表头、票号、手机号和关键状态无需改名。
- 员工 H5 当前每个场景同时出现顶级场景标题、场景导航、面板标题,语义重复。应保留“叫号/取号/核验”导航与面板内直接操作删除“员工工作台”eyebrow、顶级 H1 说明和面板 eyebrow。
- 员工叫号页的“当前叫号/当前批次/队首预览/固定容量/底栏本次将叫”存在多次重复;保留批次本体、等待数、队首号码和唯一底部叫号按钮即可。
- 法定/隐私留存说明虽然属于必要合规信息,但不必常驻占据主流程;本轮保留字段用途的最小辅助技术描述与错误反馈,删除长留存备注的可见常驻行,不改变数据处理规则。
- 管理端冗余集中在侧栏三行介绍与隐私注释、各页“eyebrow + H1 + 说明”、运行规则说明和大屏中心底部注释;导航、汇总指标、表单字段、表头、票号与全屏按钮是硬功能,应保留。
- 游客端可删除品牌副标题、私密链接标签、重复状态徽标、通用 guidance 与“需要帮助”长说明;必须保留项目、文字状态、票号、尾号、预计等待、前方人数、叫号入口/时间、服务端消息和刷新按钮。
- 公示屏可删除“现场叫号”眉题、重复批次元信息、健康状态下的数据更新时间、设备文案和“以工作人员指引为准”;项目、运行状态、当前票号、最近叫号、等待量、预计等待及异常连接提示必须保留。
- 登录页只需品牌名、账号、密码、登录按钮和错误反馈;宣传副标题、内部账号 eyebrow、重复登录标题、权限说明与账号约束帮助文字均可删除。
- 删除可见标题时必须把 `aria-labelledby` 改成稳定 `aria-label` 或保留屏幕阅读器标题重点包括员工四个区块、BatchCard、Visitor help、Login、Display current 和 Admin 两张表。删除手机号留存提示时必须同步清理 `aria-describedby`,避免悬空引用。
- 测试应从页标题断言转向硬功能断言:按钮、表单控件、表头、票号、手机号、文字状态、操作结果、离线/错误/空态和隐私不泄露;另加反回归断言确保被点名的解释性文案不再出现。
- CSS 需要同步收口:员工底栏删去两行状态后,`--staff-primary-bar-reserve` 可由 180px 下调到约 100px删去页标题后以紧凑工具栏承载项目选择/刷新/全屏,不保留空的 `.page-heading` 间距。
- 侧栏只剩三项导航后应删除 intro/note 样式并缩窄栏宽与内间距;登录卡删除介绍区后降低纵向 gap游客帮助区改成单按钮操作区公示屏删除 footer 后同步调整 grid rows避免底部空行。
- 设计技能的营销布局规则不适用于本项目的高密度后台/数据表;本轮只采用复制审计、无障碍、对比度、按钮不换行、主题/颜色/圆角一致性和空/错/加载状态等通用预检项,不引入新设计系统依赖。
- 页面层精简已落地:员工三场景删除页级标题/说明和面板眉题,底栏只剩主按钮;管理三页删除介绍层与备注;游客删除重复状态/帮助说明;登录只剩品牌与控件;公示屏删除眉题、设备说明与重复元信息。
- 第一轮字符串复扫仍发现少量需总线收口的内容:游客 `privacy-label`、项目名仍使用 eyebrow 样式、公示屏健康 footer、UI 中的 `—/` 占位或范围符号,以及员工项目状态被单独包装成一张过重的 context 卡片。
- 管理端只剩导航后1023px 媒体规则仍会把单一 nav 放入双列侧栏;需要改为单列。单按钮/单选择器的 `.admin-page-heading` 需要右对齐并缩小底部间距,避免删除标题后留下大片空白。
- 首个真实浏览器页面确认登录卡只剩品牌、账号、密码和登录按钮,已删除内部账号、登录工作台、宣传说明与帮助备注;访问员工端时未登录会正确回到该精简登录页。
- 管理员登录实际落到 `/admin`;精简后 DOM 只保留三项导航、刷新按钮、四项汇总、两张业务表及真实 A0010/完整手机号/姓名状态对应,已无页级 eyebrow、H1 说明或侧栏注释。
- 管理概览截图确认左侧导航已缩为紧凑卡片,刷新按钮右对齐,汇总与表格连续排列;删除标题后没有空白容器、断裂边框或按钮漂浮问题。
- 员工叫号页真实 DOM 已压缩为项目选择/运行状态、叫号/取号/核验导航、等待数、下一批真实号码及唯一叫号按钮;用户点名的“员工工作台”“当前批次与下一批”“严格按队首自动选号”等说明均不存在。
- 390×844 实测宽度与固定栏正确shell=390px、底栏=390px/86px、document scrollWidth=390pxA0010 仍可见且旧说明为零。
- 视觉截图发现“暂无当前批次”仍继承通用 180px 空态高度,虽然文字已删但留下过量空白;需对叫号面板空态压缩到约 88px 后复验。
- 叫号空态已压缩并实测为 88px390px 页面仍无横向溢出。
- 员工取号页真实 DOM 只保留项目/状态、三任务导航、手机号/姓氏/称谓、创建按钮、等待队列/刷新和业务表;手机号用途、留存说明、可选备注与“代游客创建/实时列表”均已删除A0010 对应关系未丢失。
- 390px 取号页截图确认表单直接进入字段/按钮,等待队列紧接其后,无空标题块;宽表仍仅在局部容器内滚动。
- 核验页空状态只保留项目、任务导航、刷新和“暂无需要核验的批次”,未保留“当前批次/到场与完成核验/叫号后会显示”等说明。
- 游客 A0010 页只保留品牌、项目、文字状态、票号、尾号 8042、预计等待、前方号码和刷新按钮“个人状态页/私密链接/需要帮助/通用 guidance”均已删除完整手机号仍未泄露。
- 390px 游客截图确认内容在单张票卡内完成,刷新按钮紧随其后,无帮助说明卡、空白页脚或横向溢出。
- 项目管理页真实 DOM 只剩项目选择器、项目状态/批量数/宽限/预计方式/间隔/缓冲字段和保存按钮;页级标题、说明和“运行规则”说明均不存在。
- 管理端大屏中心只保留全屏按钮、项目名/状态、当前票号、等待量、预计等待和设备状态;已无“全项目实时监控”说明、公开投影备注或 tile 眉题。
- 旧公示屏 token 当前返回“尚未绑定项目”,需要从本地种子/配置定位当前可用只读地址后再验公示内容;错误态本身已精简为错误、原因和重连按钮。
- 使用项目幂等 seed 生成新公示 token 后,真实公示页正常返回;页面只保留项目/时钟/运行状态、当前叫号、最近叫号和队列概况,健康 footer、设备文案和现场说明均已删除。
- 公示屏桌面截图确认四个硬信息区占满画布且无底部空行;当前新营业日暂无叫号,正确显示“暂无待到场号码/暂无最近叫号/等待 0”。
- 最终静态扫描中用户点名的旧文案、纸号/广播预案、帮助说明和可见长破折号均为零;所有页面控制台 error/warn 为零。
- 最终前端基线为 11 个 Vitest 文件、26 项测试TypeScript、Vite 生产构建和 Go API 健康检查全部通过。
## Phase 12 移除核验流程2026-07-11
- 用户确认不需要核验逻辑,并批准推荐方案:员工端只保留叫号/取号;每次叫下一批时自动结束上一批,不再提供到场、完成、过号或重新取号操作。
- 不能只删除前端入口:当前 Go 事务会在活动批次存在时拒绝再次叫号;必须在同一显式事务内结束上一批与其未结束号码,再锁定 FIFO 下一批。
- 保留边界:固定 N、严格 FIFO、幂等键、`expected_revision`、项目授权、审计记录、设备模拟和公开隐私投影均不改变。
- 当前 `callNext` 在 revision 校验后统计项目级 `CALLED` 批次并返回 `ACTIVE_BATCH_EXISTS`;替代实现应在同一事务中锁定所有活动批次,将其仍为 `CALLED/ARRIVED` 的票标为 `COMPLETED`,写入 `completed_at`,再选取本营业日队首 WAITING 号码。
- 自动轮换只在新批次确实创建成功时提交;若 revision 冲突、队列为空、设备记录或响应投影失败,事务回滚,上一批不能被单独结束。
- revision 仍只增加 1 次,幂等重放仍在轮换之前返回保存响应;`CALL_NEXT` 审计应补充自动结束的批次/票数,便于追溯系统而非人工完成。
- 旧状态列和迁移需保留以兼容历史数据,但应移除 HTTP 路由与前端 API 入口,使到场/完成/过号/重新取号在产品运行面不可访问。
- 代码核查确认:核验能力由两个 Go 路由状态迁移、重新取号、React `/staff/verify` 页面及 `BatchCard` 行操作共同暴露;三处必须一起移除,避免残留入口。
- 当前员工端在存在 `current_batch` 时同时拦截函数和禁用按钮;改造后只按等待人数、项目状态和数据新鲜度决定能否叫下一批。
- 工具记录:首次追加本节时匹配了错误的标题上下文,补读文件尾部后按现有 Phase 12 段落重新定位。
# 2026-07-11 新增确认:无批次叫号与账号归属
- 后台必须提供账号管理,并能维护每个账号所属项目。
- 员工叫号包含两个入口:快速叫下一个号;批量叫号可手动输入本次数量。
- “批次”只可作为后端事务分组实现细节,不再作为用户可见业务概念或编号。
- 票号按项目、按营业日独立递增,展示固定五位纯数字,从 `00001` 开始,不含 A/B/C/D 等前缀。
# Phase 17 登录隔离发现2026-07-11
- 当前 React 只有 `/login``LoginPage.destinationFor` 按角色把 `ADMIN` 导向 `/admin`,其他导向 `/staff`
- 当前 Go API 只有 `/api/auth/login|me|logout`,全站共用 `SessionCookieName` 一枚 Cookie员工 H5 与管理 Web 无法在同一浏览器保持独立会话。
- 员工 API 当前只要登录即可访问管理员也会被当作员工使用需要将入口、Cookie 和后端角色校验三层同时隔离。
# 2026-07-11 维护账号 UI 审计
- 截图中“所属项目”直接使用浏览器原生 `fieldset/legend`,在宽屏容器中产生突兀的灰色边框、过多空白与松散纵向排列。
- 维护页当前是单项即时保存;本次仅调整视觉结构,不改变角色、状态和项目归属的 API 行为。
- 改造方向:使用无边框语义分组、紧凑的说明文案、自适应项目卡片网格和整卡可点击状态,与现有公共服务导视风格保持一致。
# 2026-07-11 页头 Logo 审计
- `xiaoqikong-logo.jpg` 是 640×640 方形完整品牌图,内含绿色山水图形、“小七孔文旅集团”与英文名,不是可直接作为横向页头图标的素材。
- 截图中的重复文字由“图片内嵌公司名 + `AppShell` 默认公司名”叠加造成;多段后置 CSS 覆盖还使原有裁切几何失效。
- 不修改原始品牌资产,通过固定视窗和绝对定位只展示图片上半部的绿色图形,避免各端继续显示内嵌文字。
# 2026-07-11 管理端列表与账号维护 UI 审计
- 项目列表当前使用 5 个弹性列,“操作”列占用宽度后内容仍左对齐,视觉上像表格只使用了左侧区域。
- 角色字段使用原生 `<select>`macOS 弹层无法与页面设计系统保持一致,且弹出后遮挡账号状态。
- 角色仅有“员工 / 管理员”两个互斥值,适合改为带 radio 语义的分段选择;项目权限列表适合使用 `auto-fit + minmax` 充分利用宽屏。
# 2026-07-11 后台维护草稿与管理员防锁死
- 数据库核查确认 `admin` 账号已被即时交互改为 `STAFF`,密码未变;管理端按角色严格拒绝员工账号,因此表现为“账号密码登录不上”。
- 已将 `admin` 恢复为 `ADMIN`,并用管理端登录端点实测返回 HTTP 200。
- 项目创建、项目基础信息与运行规则已经使用 form submit 和明确保存按钮;后台唯一的点击即提交维护项是账号维护。
- 账号维护现在本地组合角色、状态和项目权限草稿,仅在用户点击“保存修改”后调用一次更新 API。
- 服务端对最后一个启用管理员的降级或停用返回 `409 LAST_ACTIVE_ADMIN`,不再仅依赖前端防误触。
# 2026-07-28 关键接口日志审计
- 当前 `accessLog` 只记录 request_id、method、path、status 和 duration_ms不记录业务出入参。
- 统一中间件比逐 Handler 埋点更小、更不易漏接口;仅对 `/api/` 业务接口记录正文健康检查、SSE 事件流和 CSV 导出不捕获正文。
- 手机号、密码、Cookie、Authorization、状态 token 等不能原样写日志JSON 字段需递归脱敏,查询参数也需按字段名脱敏。
- 请求/响应正文必须设置大小上限,防止队列快照、历史查询等大响应放大日志和内存占用。
- 文档明确禁止普通应用日志记录完整手机号、姓名、密码、Cookie 与访客/公示 Token实现采用现有路由白名单、递归脱敏及 64 KiB 上限。
- 现有中间件顺序还会让 panic 绕过访问日志并丢失 request_id将 request_id 和 accessLog 放在 recoverPanic 外层后500 可被统一记录。
- SSE 与 CSV 下载不捕获响应正文Idempotency-Key 仅记录是否存在,不记录原值。
- 请求正文先按路由对应 DTO 严格校验;未知字段、类型错误或不支持的正文只记录省略原因,避免攻击者借无效请求向普通日志写入任意隐私内容。
- 查询参数按路由白名单投影;历史手机号查询只保留尾四位,其他自由查询只记录是否存在。
- 账号名的 `username``display_name``created_by``requested_by` 等别名统一脱敏UUID 形态用户名也不例外。
- ResponseWriter 仅在底层实际支持时暴露 `http.Flusher`;已提交响应后发生 panic 时不再追加错误 JSON。
# 2026-07-28 手机号查询返回重复排队号码
- 用户截图显示手机号查询共返回 3 张排队单,其中同一项目“鸳鸯湖下湖(玻璃钢船)”出现两条 `00001`
- 两条记录的 `revision` 分别为 `1``3`,服务端时间也略有差异;这说明重复项来自后端查询结果,不是 React 对同一数组元素重复渲染。
- 重复记录均为 `WAITING`,项目 ID 相同、号码相同,但当前公开 DTO 未返回 ticket ID 或 queue session ID优先核查同一项目多个活动场次被同时查询的情况。
- 已用真实 PostgreSQL 构造“同项目昨日/今日两个 `RUNNING` 场次,各有同手机号 `00001`”场景;`TestInternalPhoneLookupUsesLatestActiveSessionPerProject` 在修复前稳定返回两条revision 分别为 `3``1`
- `queue_tickets` 已有 `(project_id, queue_session_id, display_number)``(project_id, queue_session_id, ticket_number)` 唯一约束,因此这不是同一场次内的重复写入。
- `statusByPhone` 当前直接筛选所有状态为 `RUNNING/PAUSED` 的场次;员工队列和公屏快照则都按 `business_date DESC` 只选择最新活动场次,查询口径不一致是首要根因。
- 根因已确认:跨营业日创建新场次时,旧场次可能仍保留 `RUNNING/PAUSED`;手机号查询没有像员工队列和公屏一样选择最新场次,因此把旧、新场次中的同号同时返回。
- 修复在数据库查询层增加按项目关联的“最新活动场次”子查询,不采用结果数组去重;这样旧场次同号会被排除,当前场次中同手机号的 `00001``00002` 等合法不同号码仍全部返回。
- 本次不需要数据库迁移,也不修改历史数据;重新发布 API 后查询立即按新口径生效。
# 2026-07-31 管理端大屏中心免登录访问
- `/admin/display` 当前被 `AuthProvider portal="admin"``RequireAdmin` 包裹,未登录会跳转 `/admin/login`
- `AdminPage` 无条件轮询 `/api/admin/overview`;该接口包含 `active_tickets` 的完整手机号、姓氏等授权数据,不能直接取消后端鉴权。
- 大屏组件实际只消费项目 ID、名称、状态、当前公开票号、等待票/人数、累计取号/体验人数、预计等待等字段。
- 采用新公开接口返回字段白名单,并让公开路由使用独立页面壳;其他 `/admin/*` 页面和 `/api/admin/*` 接口保持原鉴权。
- 工作区已有 `DisplayPage.tsx` 与对应测试的未提交语音播报改动,本轮不覆盖、不整理这些用户改动。
- 线上 URL 在普通读取器中被安全校验拒绝,应用内浏览器两次只读打开均超时;没有据此推断线上当前页面状态,也未执行部署。
# 2026-07-31 单项目大屏项目编码路由
- 前端已有 `/display/:token` 通配路由,传入项目编码时无需新增 React 路由;当前阻断点是后端只接受 40128 位 Token 并按哈希查项目。
- 项目编码规则为 224 位大写字母、数字、下划线或连字符;可复用既有校验规则,并对 URL 输入统一转大写。
- 已有有效 Token 最短 40 位,不会与最长 24 位的项目编码冲突,因此可在同一个快照接口中安全区分两类标识。
- 后台新建项目不生成公示 Token但项目编码必有值改用项目编码后新建项目也能直接打开单项目只读大屏。
# 2026-07-31 单项目公示屏排版问题
- 线上 `/display/YYHHC` 在 1280×720 下稳定复现:当前叫号卡片范围为 `top=140, bottom≈692`,最近叫号栏为 `top=532, bottom=702`,实际纵向重叠约 160px页面总高度约 1203px。
- 生效样式中,外层网格被重定义为三行,但旧规则仍把 `.display-current` 放在第 3 行、`.display-secondary` 放在第 4 行,导致右侧“后续号段预计”落到主卡片下方。
- `.display-secondary .display-history` 又使用 `position: fixed` 固定在视口底部;当主卡片被旧 `min-height: 520px` 撑高时,固定底栏直接覆盖主卡片。
- 正确结构应重置当前卡片和右侧摘要到同一第 2 行,并在矮屏断点下压缩固定底栏高度、号码区最小高度和上下留白。
- 修复后 1280×720当前卡片与右侧摘要均为 `top=124, bottom=542`,最近叫号栏为 `top=558, bottom=702`,重叠量为 0页面宽高与视口一致。
- 修复后 1920×1080主内容与底栏重叠量为 0页面无横纵向溢出右侧号码区间和等待时间的测量间距为 18px不再互相覆盖。
- 390×844 下页头切换为两行居中布局,日期和时间均落在视口内;内容使用普通纵向滚动,无横向溢出。
# 2026-07-31 单项目大屏复用管理端全屏布局
- 用户截图为 2048×1152 的 16:9 景区电视大屏,结构依次是白色时间顶栏、当前叫号主卡、四项统计、后续号段卡。
- 截图与仓库 `AdminPage.tsx``ProjectScreenTile` 的全屏 DOM、文案和字段完全对应不需要另造一套页面结构。
- 线上 `/admin/display/token` 会跳转到员工页,未登录访问 `/admin/display` 当前仍显示管理端登录;线上行为不作为本地新布局的源码基准。
- 单项目快照已有项目名、当前/最近批次、等待票数、等待人数和已体验人数,但暂未声明 `latest_ticket_number``issued_ticket_count`;这两项是参考布局的明确指标。
- 最稳妥的复用方式是让项目大屏组件支持独立展示修饰类,并让该修饰类与 `:fullscreen` 共用相同 CSS避免复制大段样式后发生漂移。
- 本地代理真实 `YYHHC` 数据后2048×1152 下顶栏、主卡和后续号段卡依次为 `0146``163594``6111117`,页面滚动尺寸与视口完全一致。
- 1280×720 下四个统计卡各约 233px 宽,内容 `scrollWidth=231px`,没有裁切;整页宽高仍与视口一致。
- 390×844 下使用两列统计卡和较小的号段字号,号段与等待时间保留 20px 间距;页面 `scrollWidth=390``scrollHeight=844`,无横向或纵向溢出。
- 浏览器日志只有 Vite 连接与热更新调试信息,无 warning 或 error。
# 2026-08-01 Android 公示屏 APK
- 用户要将公开项目页面做成 Android APK明确只有“项目列表”和“具体项目展示”两类页面。
- 现有仓库已提供公开项目列表入口 `/admin/display` 和单项目入口 `/display/{项目编码或 Token}``YYHHC` 是现成项目编码示例。
- 初始方案是原生 WebView 薄壳线上页面保持单一事实来源APK 负责沉浸式显示、屏幕常亮、允许无需手势的媒体播放和受控页面导航。
- 仓库当前没有 Android 工程;需要先确认本机 Android SDK/JDK/Gradle 能力,再选择兼容的最小构建配置。
- 公开项目列表入口实际是 `/admin/display`;每个项目卡的“全屏展示”调用 DOM `requestFullscreen()`,并不跳转 URL。Android 壳必须实现 `WebChromeClient.onShowCustomView`,否则仍会出现“浏览器未允许全屏”。
- 单项目展示入口是 `/display/:token`,同时支持项目编码(如 `YYHHC`)和既有公示 Token可作为 HTTPS 深链直接进入 APK。
- 本机有 Amazon Corretto JDK 21、Android SDK platform 35/36/36.1、Build Tools 35.0.0/36.1.0/37.0.0;未把 Gradle、ADB、sdkmanager 加入 PATH仓库也没有 Gradle Wrapper。
- Android SDK 实际位于 `C:\Users\7brot\AppData\Local\Android\Sdk`,可由工程 `local.properties` 或构建环境变量显式引用。
- 普通网页读取器对 `queue.nianxx.cn` 返回不可重试的安全校验拒绝,未获得线上页面内容;不能把该失败解读为线上服务不可用。
- 应用内浏览器打开 `/admin/display` 时也在资源加载阶段超时;这与仓库 2026-07-31 的线上访问记录一致,当前尚无证据表明页面业务接口本身故障。
- 有界重试成功打开 `https://queue.nianxx.cn/display/YYHHC`,页面标题为“景区排队叫号系统”,项目名为“鸳鸯湖下湖自助手划船”,单项目展示结构与源码一致。
- 浏览器侧出现的是宿主 Statsig 初始化超时,目标页面本身已完成导航和 DOM 渲染;不将该外部统计错误计入产品故障。
- `/admin/display` 第二次只读导航仍超时,按有界重试原则停止;其路由、项目卡、全屏按钮和公开数据接口已由本地源码及 2026-07-31 的既有验收充分确认。
- Android 官方 AGP 9.2.0 兼容表要求 Gradle 9.4.1、最低 JDK 17、最低 Build Tools 36.0.0;本机 JDK 21 与 Build Tools 36.1.0 满足基线,因此采用 AGP 9.2.0 + Gradle 9.4.1。
- Android 官方文档明确WebView 若不覆盖 `onShowCustomView/onHideCustomView` 会向网页报告不支持全屏;`setMediaPlaybackRequiresUserGesture(false)` 可取消默认的媒体播放手势要求。这两项正好对应项目列表全屏和叫号播报需求。
- 本机 Gradle 缓存已包含完整的 Gradle 9.4.1 发行包,可直接生成 Wrapper无需另行下载启动器。
- Android 工程采用纯 Java 和系统 WebView不引入 AndroidX、UI 框架或运行时第三方依赖;唯一测试依赖是 JUnit 4.13.2。
- Android 单测、Lint 和 Debug APK 构建已同时通过APK 包名 `cn.nianxx.queue.display`、版本 `1.0.0`、minSdk 23、target/compileSdk 36仅声明网络权限。
- 生成的 Debug APK 为 902,508 字节,已通过 v1/v2 签名校验;当前电脑未连接 Android 真机或模拟器,因此无法在本轮执行设备级 WebView/音频/全屏交互验收。
- Lint 第二轮为 0 错误、4 个版本/配置警告;确认 `autoVerify=false` 曾误加到 Launcher Filter现已移到 HTTPS VIEW Filter剩余三个是本机未安装 API 37 和采用 AGP 官方默认 Gradle 9.4.1 的已知版本提示。
- 最终干净构建后 Lint 为 0 错误、3 个已知工具链版本提示WebView 危险 API 定向扫描无匹配。
- 最终交付 APK 位于 `deliverables/android/XQKQueue-Display-1.0.0-debug.apk`,大小 895,292 字节SHA-256 为 `5504D25C1FDB1310FF85DADCB779BA5C07F48706514B23F8265B492CE21CAB30`