# sanfentang **Repository Path**: lk666/sanfentang ## Basic Information - **Project Name**: sanfentang - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-06-09 - **Last Updated**: 2026-08-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 叁分糖 sanfentang — 汉服门店预约管理 > 传承千年华裳 · 探索东方美学的当代表达 本仓库是「叁分糖」汉服门店预约管理系统的完整工程,采用 monorepo 结构,包含三个子项目: ``` hanyun-miniprogram/ ├── miniprogram/ 微信小程序(原生 WXML/WXSS) — 用户端 ├── backend/ Java 21 + Spring Boot 3 — 后端 API ├── web-admin/ Vue 3 + Vite + Element Plus — 商家管理后台 └── docs/ 文档 ``` ## 技术栈 | 子项目 | 栈 | 端口 | |--------|-----|------| | miniprogram | 微信原生(后续可换 Taro / uni-app) | 微信开发者工具 | | backend | Java 21 / Spring Boot 3.2 / MyBatis-Plus 3.5 / H2(dev) + MySQL(prod) / JWT / Lombok / Knife4j | 3000 | | web-admin | Vue 3.5 / Vite 5 / Element Plus 2.8 / Pinia / vue-echarts | 5173 | ## 快速开始 ### 1. 后端(backend) 环境要求:**JDK 21+** 和 **Maven 3.8+** ```bash cd backend # 启动(开发模式,使用 H2 内存数据库 + 自动 seed 数据) mvn spring-boot:run # 或先编译再运行 mvn clean package java -jar target/sanfentang-backend.jar ``` 启动成功后: - API 根地址:`http://localhost:3000/api` - 健康检查:`http://localhost:3000/health` - 接口文档(Knife4j):`http://localhost:3000/doc.html` - H2 控制台:`http://localhost:3000/h2-console`(JDBC URL 同 `application-dev.yml`) #### 默认账号(由 DataSeeder 启动时创建) | 用户名 | 密码 | 角色 | 所属门店 | |--------|------|------|----------| | `admin` | `admin123` | 超级管理员 | 全部 | | `changan` | `admin123` | 店长 | 长安总店 | | `luoyang` | `admin123` | 店员 | 洛阳店 | ### 2. 商家管理后台(web-admin) ```bash cd web-admin npm install npm run dev # 开发模式,http://localhost:5173 npm run build # 产出 dist/ ``` 默认通过 Vite proxy 把 `/api` 转发到 `http://localhost:3000`(后端),如需修改改 `web-admin/.env.development` 中的 `VITE_API_PROXY`。 ### 3. 微信小程序(miniprogram) 1. 用微信开发者工具打开 `miniprogram/` 目录 2. 在 `project.private.config.json` 填入你的 AppID(已在 .gitignore 屏蔽) 3. 配置后端地址:打开 `miniprogram/app.js`,修改 `globalData.baseURL` - 默认 `http://localhost:3000/api`(开发者工具与后端同机时) - **真机预览**请改成你电脑的局域网 IP,例如 `http://192.168.1.10:3000/api` - 开发者工具中需勾选 **「详情 → 本地设置 → 不校验合法域名」** 4. 编译预览。小程序端 9 个页面已完整接入后端真实接口,请求层见 `miniprogram/utils/request.js`,接口封装见 `miniprogram/api/*` ## 架构与约定 - **金额**:统一以「分」(Long)存储,API 响应时除以 100 转为「元」返回 - **响应包装**:`ApiResponse = { code, message, data }`,`code=0` 表示成功 - **鉴权**:JWT,放在 `Authorization: Bearer `,过期时间 7 天 - **角色**:`user`(小程序用户)与 `merchant`(商家后台)共用一套 token 机制,通过 `type` 字段区分 - **图片**:`/uploads/**` 静态映射到 `sanfentang.upload.dir`,开发期默认 `./uploads` - **设计 token**:见 `web-admin/src/styles/index.scss`,与小程序端共用一套色卡 ## 核心数据模型 ``` users(用户) ─┐ ├─→ bookings(预约) ←── hanfu(汉服款式) stylists ┘ store(门店) coupon(优惠券) ai_tryon_records(AI 试穿) reviews(评价) merchants(商家) → store(所属门店) ``` ## 接口分组 - `/api/auth/*` 认证(短信/微信/商家) - `/api/hanfu/*` 汉服款式 - `/api/bookings/*` 预约(用户侧) - `/api/stylists/*` 造型师 - `/api/stores/*` 门店 - `/api/coupons/*` 优惠券 - `/api/ai/*` AI 试穿 - `/api/upload/*` 文件上传 - `/api/merchant/*` 商家端(需 merchant token) ## 本次实现说明(已联通能力) > 仓库初始为「结构完整、功能未联通」状态:后端逻辑基本就绪但未编译,小程序 9 个页面全是硬编码假数据,管理后台存在 2 处字段错配。本次已补齐到可联调。 ### 1. 小程序端(已从 0% 接入 → 完整联通) - 新建请求层 `miniprogram/utils/request.js`(自动拼接 baseURL、注入 `Bearer`、解包 `ApiResponse`)。 - 新建接口封装 `miniprogram/api/*`(auth / hanfu / book ing / stylist / store / coupon / ai / review / merchant)。 - 9 个页面全部改为调用真实后端:home(精选+朝代)、catalog(列表/筛选)、detail(详情+造型师+门店)、booking(创建预约)、login(验证码/微信登录)、profile(我的预约/券/评价)、ai-assistant(上传+AI 试穿+历史)、merchant-dashboard(经营概览/7 日营收/款式排行)、merchant-calendar(门店月历)。 - 配置入口:`miniprogram/app.js` 的 `globalData.baseURL`(已含 `/api`)。 ### 2. 后端新增接口 - **评价**:`GET /api/reviews?hanfuId=`(款式评价)、`GET /api/reviews/my`(我的)、`POST /api/reviews`(提交) - **优惠券发放(商家端)**:`POST /api/merchant/coupons`(指定用户或全体发放)、`GET /api/merchant/coupons`(列表) ### 3. 后端修复(影响正确性) - **门店隔离**:`JwtUtil` 现在把 `storeId` 写入 JWT 载荷,`JwtAuthFilter` 每次请求解析恢复,商家端预约/日历/统计严格按所属门店隔离(此前所有商家看到的是全部门店数据)。 - **字段补全**:商家预约列表返回补 `hanfuName`;门店月历返回补 `totalFee`(月历营收此前恒为 ¥0)。 - 管理后台 `BookingListView`(款式列)、`CalendarView`(营收/款式名)、`HanfuListView`(分页) 已同步修正。 ### 4. 联调默认账号 | 用户名 | 密码 | 角色 | 所属门店 | |--------|------|------|----------| | `admin` | `admin123` | 超级管理员 | 全部 | | `changan` | `admin123` | 店长 | 长安总店 | | `luoyang` | `admin123` | 店员 | 洛阳店 | > 小程序用户端通过「验证码登录」(开发态后端直接返回 `mockCode`)或「微信登录」(mock openid)进入;商家端在管理后台 `/login` 用上表账号登录。 ## 部署 / 运行 项目内置两套数据源配置,通过 Spring Profile 切换: | Profile | 文件 | 数据库 | 适用 | |---------|------|--------|------| | `dev`(默认) | `application-dev.yml` | H2 内存库 | 本地快速试跑,重启即清空 | | `prod` | `application-prod.yml` | **MySQL 8.x** | 持久化 / 本地或服务器 MySQL | ### 用 MySQL 运行(你选的方案) 默认连接参数(已写入 `application-prod.yml`,均可被 `DB_*` 环境变量覆盖): `jdbc:mysql://127.0.0.1:3306/fast_reservation`、`root / 123456`。 1. **先建库**(后端不会自动建库,只自动建表): ```sql CREATE DATABASE fast_reservation DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ``` 2. **启动后端,激活 prod profile**(任选一种): ```bash # 方式 A:命令行指定 profile cd backend mvn spring-boot:run -Dspring-boot.run.profiles=prod # 方式 B:环境变量(覆盖默认连接参数) set SPRING_PROFILES_ACTIVE=prod set DB_HOST=127.0.0.1 set DB_PORT=3306 set DB_NAME=fast_reservation set DB_USERNAME=root set DB_PASSWORD=123456 mvn spring-boot:run ``` > URL 中已附加 `&useSSL=false&allowPublicKeyRetrieval=true`: > 本地 MySQL 8 默认用 `caching_sha2_password` 认证,非 SSL 连接时必须允许公钥获取,否则会报 > `RSA public key is not available`。如你的环境不需要,可自行删去这两段参数。 3. **首次启动会自动建表 + 灌入种子数据**(门店/汉服/造型师/示例预约/评价/优惠券), 商家账号由 `DataSeeder` 用 BCrypt 现场创建:`admin/admin123`、`changan/admin123`、`luoyang/admin123`。 - 重复启动时主键冲突会被 `continue-on-error` 自动跳过,种子数据不会重复写入,可放心重启。 4. 打开 `http://localhost:3000/doc.html` 验证接口;管理后台 `npm run dev` 后访问 `http://localhost:5173`。 ### 文件服务器(MinIO) `prod` 模式下,上传接口(`POST /api/upload/image`)会把图片存到 **MinIO**,不再写本地磁盘。 - 配置(已写入 `application-prod.yml`,在 `sanfentang.minio` 下): ```yaml sanfentang: minio: endpoint: http://127.0.0.1:9000 accessKey: minioadmin secretKey: minioadmin bucketName: reservation ``` - 首次上传时若桶 `reservation` 不存在,后端会**自动创建并把桶设为公开读**, 因此返回的图片 URL 形如 `http://127.0.0.1:9000/reservation/.jpg`,前端/小程序可直接 `` 展示,无需签名。 - 依赖:`io.minio:minio:8.5.7`(已加入 `pom.xml`)。 - **未配置 MinIO 时(如 `dev` 用 H2)会自动回退到本地 `./uploads` 目录**,两种模式互不干扰。 - 前置:本地需先运行 MinIO Server(`minio server ./data --console-address :9001`), 并确认 `accessKey/secretKey` 与配置一致(默认 `minioadmin/minioadmin`)。 ### 打包部署到服务器 1. 后端:`mvn package -DskipTests` 产出 `target/sanfentang-backend.jar`, 服务器上 `java -jar sanfentang-backend.jar --spring.profiles.active=prod` 并用 `DB_*` 环境变量注入凭据。 2. 前端:`npm run build` 后用 Nginx 托管 `dist/`,反向代理 `/api` 到后端服务。 ## 功能闭环与线上发布要点 ### 1. 外部集成开关(本地 mock ↔ 真实服务) 所有外部依赖都做成「开关 + 配置」,本地不填任何密钥即可端到端跑通,上线时再注入真实凭据。 | 能力 | 配置项(application.yml) | 环境变量 | 本地默认 | 上线做法 | |------|------------------------|----------|----------|----------| | 数据库方言 | `sanfentang.db-type` | `DB_TYPE` | `MYSQL` | dev 改为 `H2` 可免装 MySQL | | 微信登录 | `sanfentang.wx.appid` / `secret` | `WX_APPID` / `WX_SECRET` | 空 | 填入小程序真实 AppID/Secret,走真实 `jscode2session` | | 支付(押金) | `sanfentang.pay.mock` | `PAY_MOCK` | `true` | 配微信支付商户号后设 `false`,预约 `create` 后需再调 `POST /api/bookings/{id}/pay` | | 短信验证码 | `sanfentang.sms.mock` | `SMS_MOCK` | `true` | 配短信服务商后设 `false`,`/api/auth/sms-code` 真正下发 | > mock 模式下:微信登录返回 `mock_openid_`、短信返回 `mockCode`(开发态前端会弹窗提示)、 > 预约提交即标记押金 `paid`(无需再调 pay)。这样无需任何外部账号即可联调全部流程。 ### 2. 已补齐的端到端流程(本次收尾) - **预约闭环**:booking 页支持「选优惠券 + 填备注 + 创建 + 支付 + 取消」。创建时把 `couponId/remark` 传给后端并按券类型(`amount` 满减 / `discount` 折扣)实时抵扣;mock 支付直接成功,真实支付需再调 `pay`。 profile 页可查看预约详情、取消(pending/confirmed 状态)。 - **优惠券**:领券中心 `GET /api/coupons/available` + 领取 `POST /api/coupons/claim/{id}`;我的券 `GET /api/coupons/my`;`detail` 与 `booking` 全流程使用。 - **评价**:款式详情可写评价(星级 + 内容),`GET /api/reviews/my` 查看我的评价, 商家端 `POST /api/merchant/reviews/{id}/reply` 回复。 - **AI 试穿**:`POST /api/ai/try-on` 真实返回 `resultImage`(汉服预览图)+ 稳定匹配分 + 推荐理由; 小程序结果卡与历史卡均渲染真实图片。 - **商家工作台**:小程序内置「商家登录」入口 → 月历全月视图(点击日期切换、有预约打点), 点击预约卡片可改状态(待确认/已确认/已完成/已取消,`PATCH /api/merchant/bookings/{id}/status`)。 - **个人中心**:真实头像 / 昵称 / 积分 / 会员等级;预约列表与详情、领券中心、我的评价、商家入口、退出登录。 ### 3. 新增 / 调整的接口 ``` GET /api/coupons/my 我的可用券 GET /api/coupons/available 领券中心(公开券) POST /api/coupons/claim/{id} 领取公开券 POST /api/bookings/{id}/pay 支付押金(mock 直接成功) GET /api/bookings 我的预约(含 hanfuName) GET /api/bookings/{id} 预约详情(含 hanfuName) POST /api/reviews/my 我的评价 POST /api/merchant/reviews/{id}/reply 商家回复评价 GET /api/merchant/bookings/calendar 商家月历(全月 byDate) PATCH /api/merchant/bookings/{id}/status 商家改预约状态 POST /api/auth/merchant 商家登录(返回 merchant + token) ``` ### 4. 上线发布域名校验要点 微信小程序**线上环境严格校验域名**,本地开发者工具「不校验合法域名」仅对开发/真机调试生效: 1. **HTTPS + ICP 备案**:所有 `request` / `uploadFile` / `downloadFile` 域名必须为 **https**,且已完成 ICP 备案。 2. **request 合法域名白名单**:在「微信公众平台 → 开发管理 → 开发设置 → 服务器域名」中, 把后端域名(如 `https://api.sanfentang.com`)加入 **request 合法域名**、`uploadFile` 域名加入 **uploadFile 合法域名**。 未加入白名单的域名线上会直接报 `不在 request 合法域名列表中`。 3. **微信支付**:需企业主体 + 微信支付商户号 + APIv3 密钥,并把 `PAY_MOCK=false`; 同时把支付域名加入「微信支付 API 白名单」。 4. **微信登录**:填真实 `WX_APPID` / `WX_SECRET`(须与小程序 AppID 一致)。 5. **真机预览**:`miniprogram/app.js` 的 `baseURL` 改成你电脑的局域网 IP(如 `http://192.168.1.10:3000/api`), 仍须在开发者工具勾选「不校验合法域名」才能访问 http 地址。 ## License MIT