Files
hotel-biz-h5/docs/frontend-practices.md
2026-06-18 15:54:47 +08:00

102 lines
7.8 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.

# 员工端 H5 前端经验总结
这份文档记录当前员工端 H5 在页面规划、接口接入、移动端兼容、扫码核销和部署上的经验。后续改页面时,优先按这里的约定处理,避免重复踩坑。
## 页面规划
- 第一版页面以业务闭环为主,不做后台管理式的大而全页面。
- 当前核心页面包括:登录、工作台、订单列表、订单详情、扫码核销、核销确认、核销结果、事件列表、发布事件、我的。
- 工作台上的统计数据必须有明确后端依据。没有独立统计接口时,可以展示列表接口能稳定支持的指标,例如待确认订单、生效事件、近期订单、近期事件。
- 不要把 mock 推导出的数据当成真实业务指标。比如订单表没有可直接查询的核销状态或核销时间时,不要在工作台展示“今日核销”这类指标。
- 页面文案保持员工端视角,产品名称统一使用“员工端”。
## 登录与组织关系
- 登录使用手机号验证码流程,登录成功后必须主动调用 `/hotelStaff/organizationMember/bindUserInfoAndGetUserMemberInfoByPhone` 获取当前用户组织关系。
- 如果组织关系获取失败,统一提示“未绑定组织,请联系管理员”。
- 当前不需要调用 `/user/checkUserHasBindPhone`
- 登录态只代表认证成功,不代表用户一定拥有员工端组织关系,业务页面入口应以后续组织关系接口成功为准。
- 接口返回“请求令牌已过期”、`401` 或 token 失效类错误时,要统一清理本地登录态并跳转 `/login`,同时带上当前页面作为 `redirect`,避免用户继续停留在失效页面。
## 接口路径
- 所有真实接口都通过后端网关访问,由网关按路由转发到具体服务。
- 本地开发使用 Vite proxy当前开发网关是 `http://192.168.3.211:9999`
- 员工端接口前缀是 `/hotelStaff`,订单接口路径是 `/hotelStaff/order/...`,事件接口路径是 `/hotelStaff/event/...`
- 登录接口走 `/auth`,验证码和用户相关接口走 `/admin`
- 不要在业务代码里硬编码完整网关地址,统一从环境变量和 `src/utils/env.ts` 读取。
## 环境与部署
- 本地开发使用 `.env.local`,测试打包使用 `.env.test`,生产打包使用 `.env.production`
- `VITE_API_BASE_URL` 为空时,前端会按当前站点同源请求接口,适合 Nginx 反向代理部署。
- 前后端分离部署时,优先用 Nginx 把 `/auth``/admin``/hotelStaff``/hotelBiz` 等路径代理到后端网关,这样浏览器看到的是同源请求,跨域问题最少。
- 如果直接把 `VITE_API_BASE_URL` 配成后端网关 IP 或域名,跨域就需要后端网关正确返回 CORS 头;这不是前端代码能完全解决的。
- SPA 路由需要 Nginx `location / { try_files $uri $uri/ /index.html; }`
## 移动端布局
- H5 页面不要依赖固定宽度,所有主容器都应具备 `width: 100%``max-width: 100%``min-width: 0` 这类约束。
- flex 或 grid 中承载长文本的区域要使用 `min-width: 0`grid 列建议用 `minmax(0, 1fr)`,否则长订单号、手机号、商品名容易撑出横向滚动。
- `html``body``#app` 可以限制 `overflow-x: hidden`,但这只是兜底。真正要处理的是子元素宽度、长文本换行和 flex 收缩。
- 图片、视频、canvas 必须有 `max-width: 100%`,避免媒体元素撑破视口。
- 固定底部导航、按钮区域需要考虑 `safe-area-inset-bottom`,兼容 iPhone 底部安全区。
## 输入框兼容
- iOS Safari 和微信内置浏览器中,输入框字号小于 16px 时,聚焦输入框会触发页面自动放大,容易出现横向滚动和布局错位。
- 全局真实输入控件,包括 `input``textarea``select``.van-field__control`,应保持 `font-size: 16px`
- 不建议通过 `maximum-scale=1``user-scalable=no` 禁止用户缩放,这会影响可访问性,也不能从根上解决布局问题。
- 搜索框、登录手机号、验证码、日期时间输入都要按真实输入控件处理,不要只调整外层字体。
## Vant 组件样式
- 修改全局样式时要避免过宽的选择器,例如 `.meta-row span` 会误伤 Vant 的 `van-tag`,导致“生效中”“已取消”等标签在 Chrome 里被拉伸或错位。
- 对普通文本列可以使用 `.meta-row > span:not(.van-tag)`,状态标签应单独设置 `flex: 0 0 auto``white-space: nowrap`
- Vant 组件内部结构可能使用 `span``button``input` 等基础标签,写全局选择器时要先确认是否会影响组件内部 DOM。
- 共享样式要放在 `src/styles/main.css`,页面个性化样式放在对应 `.vue` 的 scoped style。
## 扫码核销
- 当前二维码内容规则是 `orderId&packageName`,其中 `packageName` 是套餐名称。
- 前端解析时必须兼容只有 `orderId` 的情况。
- 扫码流程是:点击进行扫码 -> 调起摄像头 -> 解析二维码 -> 查询订单详情 -> 展示核销确认 -> 调用核销接口。
- 当前核销入口不提供手动输入订单号兜底,页面文案保持“点击进行扫码”。
- 扫码内容带 `packageName` 时,核销确认页只能展示并核销当前扫码进入的套餐商品;不能让员工切换到其他套餐。
- 扫码内容只有 `orderId` 时,核销确认页可以按订单详情里的套餐配置展示可选套餐。
- 浏览器扫码优先使用原生 `BarcodeDetector`,不支持时使用 `jsQR` 读取视频画面进行解析。
- 摄像头能力通常要求 HTTPS 或 localhost。微信内置浏览器如果 `getUserMedia` 受限,后续可以考虑接入微信 JSSDK 的 `scanQRCode`,但需要公众号配置、签名接口和 JS 安全域名配合。
## 订单与核销记录
- 订单列表当前保留手机号搜索和订单状态筛选。
- 订单详情可以发起核销,核销确认页需要展示订单核心信息,避免员工误核销。
- 核销确认页必须展示可核销商品数、已核销商品数、总数量,优先使用后端套餐配置里的 `count``writeOffCount``packageStatus` 字段。
- 当可核销商品数为 0 时,确认核销按钮应禁用,并提示当前套餐商品已核销完。
- `/hotelStaff/order/writeOff` 返回值是 `Boolean`,前端不能只看 HTTP 成功;如果返回 `false`,必须按核销失败处理。
- 后端状态机会限制超量核销并控制核销记录数量,前端职责是正确展示剩余数量并正确处理失败态。后端如果能透传“该套餐商品已被核销完”等具体错误,会让前端提示更准确。
- 订单详情的核销记录中,如果后端返回套餐名称,要展示套餐名称,便于员工核对。
- “使用信息”里不要展示核销地点,当前后端和页面需求不需要这个字段。
## 事件模块
- 发布事件页面里的“实体名称”已改为“事件标题”。
- 事件列表搜索提示文案为“搜索事件标题”。
- 事件列表不需要开启和关闭按钮,也不需要以开启/关闭作为主要筛选交互。
- 列表上的状态展示要谨慎处理样式,不能影响 Vant 标签的自然宽度。
## 验证清单
每次改动移动端布局、表单、列表或扫码能力后,至少检查:
- `yarn typecheck`
- `yarn build:test`
- 320px 和 375px 宽度下是否出现横向滚动
- 登录页输入框聚焦后是否自动放大
- 订单搜索输入框聚焦后是否自动放大
- Chrome 里订单状态、事件状态标签是否保持正常宽度
- 真机或微信内置浏览器里扫码入口是否能正常申请摄像头权限
- 扫码带套餐进入核销确认页时,只能看到当前套餐
- 核销确认页的可核销商品数、已核销商品数、总数量和后端返回一致
- `/writeOff` 返回 `false` 或失败时,前端不能展示核销成功