豆间 · 拼豆工坊

首期单店私域小程序:图纸工具、个人作品、到店服务与店员工作台。业务数据带门店归属,预留未来扩店;目前管理员与小程序默认绑定 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 拆分记录。

本地启动

当前本地演示管理员

项目 值
后台地址 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,仅供本地联调。

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 进程,见 验收记录。

顾客端 H5 预览

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。

后台开发与后端独立运行

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 微信网页授权。

独立域名与网络路径

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 官方文档。失败探测有 30 秒冷却,网络变化使旧探测结果失效。GET 可以回退重试;服务呼叫使用同一 UUID 和请求内容回退,后端持久幂等;业务错误不触发线路回退,其他写操作不会盲目自动重放。

部署模板在 deploy/:内网域名解析到门店局域网地址,公网域名解析到 frps 主机。门店 Nginx 在 443 提供两个域名都有效的 HTTPS 证书;frp HTTPS 代理按公网域名透传到门店 443。frpc/frps 间还配置了证书校验与 token,参考 frp TLS 官方文档。替换全部示例域名、证书路径与密钥后再部署。

店铺域名字段供后台记录维护;小程序实际路由目前以构建时 VITE_* 配置为准。修改域名后需要重新构建发布,不会从未经信任的响应自动切换地址。两条路径访问同一 Gin、数据库与 Redis,无需同步两份数据。门店设备停机时公网隧道也不可用。

到店状态由有效桌位码创建的会话定义,与走内网还是公网分离。它不是物理位置认证:知道桌码的已登录用户也能建立到店会话。若后续需要更严格的防远程呼叫,可增加短效入座码或员工确认。员工权限始终由后端鉴权,不由网络类型授予。

实时呼叫与语音提醒

后台通过同源 /api/ws 建立 WebSocket,登录后在所有工作台页面持续接收门店任务变更。首次连接和重连都会查询任务补齐数据,每 60 秒另做一次兜底同步;无需一直停在服务队列页。生产 HTTPS 页面自动使用 WSS,Vite 和 Nginx 示例已配置 Upgrade 转发。

点击工作台上方「开启语音」完成一次试听后,新待接单呼叫会播报桌位与服务类型,例如「T01 桌,呼叫员工」。使用浏览器提供的本机中文 TTS,无第三方密钥;无中文音色或播放失败会提示。首次打开不补播历史任务,同一任务不重复播报,试听期间的新任务继续排队,已被接单或取消的待播任务移出队列。

语音开启仅对当前页面会话生效,刷新后需重新点击;可随时关闭。多台设备或多个标签同时开启会分别播报,门店可指定一台接单设备。浏览器冻结、休眠或页面关闭后不能保证后台持续发声。首期 Hub 为单 Gin 实例,未来多副本需增加 Redis Pub/Sub 分发。协议、验证与边界见 语音与 WS 说明。

数据、色板与打印

  • 初始十色 DEMO* 色板和四张 7×7 图纸仅用于演示,不代表任何品牌真实色号。上线前由后台维护品牌色号、颜色、库存可用状态与取料位置。
  • 图纸最大 200×200,色板最多 512 色;保存时后端按门店权威色板校验,个人作品默认为私有。后台支持符合接口结构的 JSON 图纸导入。
  • 跟做进度和未保存草稿在当前设备本地存储;保存的作品、收藏、到店会话与服务任务在服务端。跨设备草稿/逐格进度同步尚未实现。
  • SVG 用毫米描述,默认珠距 5 mm,可传 2–10 mm;附色号、坐标、色量与 50 mm 标尺。打印选 100% 实际大小,测量标尺后使用;大图使用打印软件的海报分页。小程序内由门店任务交给员工下载打印,不直接控制打印设备。
  • 数据库是业务真源;Redis 保存会话与登录限流。备份需覆盖 PostgreSQL;Redis 数据丢失会导致重新登录。当前使用 JSONB 文档存储加关系表,规模增长后再按查询负载拆分与索引。

验证与交付边界

测试命令、真实运行结果、尚待真机验收的项目见 验收记录。API 契约见 实施计划,具体审查结论见 服务端报告 和 后台报告。

uni-app 当前稳定工具链仍有 24 项 npm 审计记录(9 high / 15 moderate);已做兼容补丁升级,剩余集中于工具链,详见 依赖报告。不要把 Vite 开发服务暴露公网或用于生产。后台 npm 审计为零。依赖审计、构建成功与真机验收是不同检查,当前没有宣称已生产上线。

S
Description
No description provided
Readme
981 KiB
Languages
JavaScript 100%