Files
beads-group/README.md
T

130 lines
11 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.
# 豆间 · 拼豆工坊
首期单店私域小程序:图纸工具、个人作品、到店服务与店员工作台。业务数据带门店归属,预留未来扩店;目前管理员与小程序默认绑定 `store-001`,尚未实现跨店调度、总部权限和分布式同步。
## 工程与功能
| 工程 | 技术 | 已实现 |
| --- | --- | --- |
| `perler-beads-applet` | uni-app / Vue 3 / TypeScript / Pinia | 图纸浏览、搜索、收藏、图片转色号网格、文字图纸、手绘改色、本地草稿、作品保存、跟做高亮与进度、桌码到店、呼叫员工/补豆/熨烫/打印 |
| `perler-beads-server` | Go 1.25 / Gin / PostgreSQL / Redis | 微信登录、管理员鉴权、持久化、门店权限、幂等呼叫、任务状态机、实际尺寸 SVG、后台接口 |
| `perler-beads-webui` | Vue 3 / Element Plus / Pinia / Vue Router | 服务队列、接单完成、图纸导入与发布、色板与取料位置、桌位、门店设置 |
图片仅在顾客设备处理,上传保存的是色号网格。支付与储值只提供禁用的能力接口,没有交易、充值或自动计费。打印由员工下载 SVG 后操作打印机。参考 `example` 页面结构重新实现,演示图案为原创像素网格。
## 小程序页面与交互
主包保留图纸、制作、门店、我的四个 tab。创作设置/编辑、图纸详情/用料/打印、到店/申请/记录、个人图纸列表分别放入四个分包。选项采用分组设置行,点击后通过编辑对话或选择弹层确认,不使用 form 提交。分包页提供返回上页与所属主 tab 的入口。
路由、共享组件和本轮验收见 [UI 拆分记录](docs/applet-ui-refactor.md)。
## 本地启动
### 当前本地演示管理员
| 项目 | 值 |
| --- | --- |
| 后台地址 | http://127.0.0.1:5174 |
| 用户名 | `admin` |
| 密码 | `local-integration-only` |
以上为此前本机联调使用的账号,角色为管理员,所属门店为 `store-001`。这是本地演示配置,不是程序内置的默认密码,也不会自动应用到自行部署的环境。预览依赖开发服务持续运行。2026-10-14 已重新启动三端,继续使用下述独立 PostgreSQL 数据库。
自行部署时,账号由服务端环境变量 `ADMIN_USERNAME` 和 `ADMIN_PASSWORD` 决定。Docker Compose 从根目录 `.env` 读取;独立运行 Go 服务需自行导出这两个变量,应用不会自动加载 `.env`。示例用户名为 `admin`,密码占位符必须替换为自设密码(至少 12 个字符),不要将上述演示密码用于正式门店。
### 当前数据库连接
PostgreSQL 复用 `events-server` 配置中的实例 `192.168.31.98:5433` 和用户 `postgres`,拼豆独立使用 `perler_beads` 数据库。连接配置保存在被 Git 忽略的 `perler-beads-server/.env.local`(文件权限 600);密码不写入本文。`events` 库未修改。旧临时 `perler_test` 库的测试记录未迁入新库,新库初始化演示门店、色板和图纸。
Redis 当前仍为本机演示实例 `127.0.0.1:56379`。此处只切换 PostgreSQL,未复用 events 的 Redis 键空间。Go 不自动加载 `.env.local`,启动时须将其作为进程环境传入;当前后台进程已经使用该配置。
需要 Node.js 22.12+、npm;独立运行后端需要 Go 1.25+、PostgreSQL、Redis。容器路径需要 Docker Compose 插件。
### 容器启动服务端和后台
在根目录复制 `.env.example` 为 `.env`,将三个密码替换为独立随机值。数据库和 Redis 密码建议使用十六进制,避免连接串转义。示例显式设置 `APP_ENV=development`,仅供本地联调。
```sh
cp .env.example .env
# 编辑 .env 后执行
docker compose up --build -d
```
后台 `http://127.0.0.1:8088`,API `http://127.0.0.1:8080/api/health`。使用 `.env` 的管理员账号登录。数据库与 Redis 不映射宿主端口;业务数据保存在命名卷,停止时使用 `docker compose down`,不要随意删除卷。
当前开发机器没有 Docker,Compose 尚未实际启动验收;本次真实联调使用了独立临时 PostgreSQL/Redis 进程,见 [验收记录](docs/verification.md)。
### 顾客端 H5 预览
```sh
cd perler-beads-applet
npm ci
VITE_DEV_LOGIN=true npm run dev:h5
```
打开 `http://127.0.0.1:5173`。开发构建未配置域名时默认请求本机 8080。只有开发构建且显式启用 `VITE_DEV_LOGIN=true` 才显示演示登录;后端也必须为 development。演示用户是共享身份,不能用于真实顾客数据。初始化的桌位码为 `T01`、`T02`。
### 后台开发与后端独立运行
```sh
cd perler-beads-webui
npm ci
npm run dev
```
后台开发地址 `http://127.0.0.1:5174`,`/api` 代理本机 8080,不需要前端环境变量。生产构建 `npm run build` 输出 `dist`,可由提供的 Nginx 容器托管,或使用后端 `WEBUI_DIR` 指向其绝对路径。
后端按 `perler-beads-server/.env.example` 配置并导出环境变量,然后在该目录执行 `go run ./cmd/server`。Go 进程不自动加载 `.env`。启动会执行内嵌幂等数据库迁移;`SEED_DEMO=true` 仅在没有门店时初始化演示数据。
## 微信小程序构建
1. 复制 applet 内 `.env.example` 为 `.env.production`,填写公网、内网 HTTPS 域名和门店 ID;域名不包含 `/api`、路径或尾斜杠。生产不允许 HTTP、本机地址或开发登录。
2. 在 `src/manifest.json` 的 `mp-weixin.appid` 填入真实微信 AppID;服务端配置对应 AppID 与 AppSecret 并使用 `APP_ENV=production`。密钥仅进入服务端环境。
3. 在微信后台配置两个请求域名,按实际下载能力配置下载域名。保持 `urlCheck=true`,不要以关闭校验作为发布条件。
4. 执行 `npm run build:mp-weixin`,用微信开发者工具导入 `dist/build/mp-weixin`。先在合法域名校验开启的情况下完成体验版真机测试,再提交审核。
`npm run build:h5` 输出 `dist/build/h5`;H5 是工具与界面预览,正式顾客微信身份通过小程序登录。未实现生产 H5 微信网页授权。
## 独立域名与网络路径
```mermaid
flowchart TD
A[获取网络类型] --> B{是否 Wi-Fi}
B -->|否 / unknown| C[公网 HTTPS 域名]
B -->|是| D[探测指定内网域名 health,1秒超时]
D -->|服务标识与门店匹配| E[内网 HTTPS 直连]
D -->|失败 / 门店不匹配| C
C --> F[公网 frps → 门店 frpc → Nginx → Gin]
E --> G[门店 Nginx → Gin]
```
`none` 直接提示离线。未读取 SSID、BSSID 或扫描网段。线路选择使用 `uni.getNetworkType` 和网络变化监听,参考 [uni-app 官方文档](https://uniapp.dcloud.net.cn/api/system/network.html)。失败探测有 30 秒冷却,网络变化使旧探测结果失效。GET 可以回退重试;服务呼叫使用同一 UUID 和请求内容回退,后端持久幂等;业务错误不触发线路回退,其他写操作不会盲目自动重放。
部署模板在 `deploy/`:内网域名解析到门店局域网地址,公网域名解析到 frps 主机。门店 Nginx 在 443 提供两个域名都有效的 HTTPS 证书;frp HTTPS 代理按公网域名透传到门店 443。frpc/frps 间还配置了证书校验与 token,参考 [frp TLS 官方文档](https://gofrp.org/zh-cn/docs/features/common/network/network-tls/)。替换全部示例域名、证书路径与密钥后再部署。
店铺域名字段供后台记录维护;小程序实际路由目前以构建时 `VITE_*` 配置为准。修改域名后需要重新构建发布,不会从未经信任的响应自动切换地址。两条路径访问同一 Gin、数据库与 Redis,无需同步两份数据。门店设备停机时公网隧道也不可用。
到店状态由有效桌位码创建的会话定义,与走内网还是公网分离。它不是物理位置认证:知道桌码的已登录用户也能建立到店会话。若后续需要更严格的防远程呼叫,可增加短效入座码或员工确认。员工权限始终由后端鉴权,不由网络类型授予。
## 实时呼叫与语音提醒
后台通过同源 `/api/ws` 建立 WebSocket,登录后在所有工作台页面持续接收门店任务变更。首次连接和重连都会查询任务补齐数据,每 60 秒另做一次兜底同步;无需一直停在服务队列页。生产 HTTPS 页面自动使用 WSS,Vite 和 Nginx 示例已配置 Upgrade 转发。
点击工作台上方「开启语音」完成一次试听后,新待接单呼叫会播报桌位与服务类型,例如「T01 桌,呼叫员工」。使用浏览器提供的本机中文 TTS,无第三方密钥;无中文音色或播放失败会提示。首次打开不补播历史任务,同一任务不重复播报,试听期间的新任务继续排队,已被接单或取消的待播任务移出队列。
语音开启仅对当前页面会话生效,刷新后需重新点击;可随时关闭。多台设备或多个标签同时开启会分别播报,门店可指定一台接单设备。浏览器冻结、休眠或页面关闭后不能保证后台持续发声。首期 Hub 为单 Gin 实例,未来多副本需增加 Redis Pub/Sub 分发。协议、验证与边界见 [语音与 WS 说明](docs/voice-notifications.md)。
## 数据、色板与打印
- 初始十色 `DEMO*` 色板和四张 7×7 图纸仅用于演示,不代表任何品牌真实色号。上线前由后台维护品牌色号、颜色、库存可用状态与取料位置。
- 图纸最大 200×200,色板最多 512 色;保存时后端按门店权威色板校验,个人作品默认为私有。后台支持符合接口结构的 JSON 图纸导入。
- 跟做进度和未保存草稿在当前设备本地存储;保存的作品、收藏、到店会话与服务任务在服务端。跨设备草稿/逐格进度同步尚未实现。
- SVG 用毫米描述,默认珠距 5 mm,可传 2–10 mm;附色号、坐标、色量与 50 mm 标尺。打印选 100% 实际大小,测量标尺后使用;大图使用打印软件的海报分页。小程序内由门店任务交给员工下载打印,不直接控制打印设备。
- 数据库是业务真源;Redis 保存会话与登录限流。备份需覆盖 PostgreSQL;Redis 数据丢失会导致重新登录。当前使用 JSONB 文档存储加关系表,规模增长后再按查询负载拆分与索引。
## 验证与交付边界
测试命令、真实运行结果、尚待真机验收的项目见 [验收记录](docs/verification.md)。API 契约见 [实施计划](docs/implementation-plan.md),具体审查结论见 [服务端报告](docs/server-report.md) 和 [后台报告](docs/webui-report.md)。
uni-app 当前稳定工具链仍有 24 项 npm 审计记录(9 high / 15 moderate);已做兼容补丁升级,剩余集中于工具链,详见 [依赖报告](docs/dependency-report.md)。不要把 Vite 开发服务暴露公网或用于生产。后台 npm 审计为零。依赖审计、构建成功与真机验收是不同检查,当前没有宣称已生产上线。