# 宠小它 - 产品设计文档 > **本体对齐**:本文档与 [`ontology/objects.md`](./ontology/objects.md) 对齐(`entity:store`/`entity:user`/`entity:appointment`/`entity:report`),规则见 [`ontology/rules.md`](./ontology/rules.md)。冲突以本体为准。 > > 版本:v1.9 > 日期:2026-04-18(v1.9:对外品牌统一为「宠小它」及主/副 Slogan;v1.8:成片「可变时长 + 双编排」与 §5.3 对齐专文 §0) > **品牌**:宠小它 · **主 Slogan**:用心宠小它,温暖伴一生 · **副 Slogan**:智慧宠物门店服务系统 > **Logo / VI**:[《宠小它-Logo与品牌识别说明》](./宠小它-Logo与品牌识别说明.md)(含概念草案图) > 状态:产品设计确认中;**本期迭代重点:洗美过程短视频自动成片(竖屏、可变时长、双编排)** **相关子文档:** - [洗美报告短视频成片方案](./洗美报告短视频成片方案.md) — **本期迭代主方案**:过程短视频与自动成片(与 §5.3 服务报告延伸能力对应;时长与编排以专文「与工程实现同步」为准) - [产品改进建议](./产品改进建议.md) — 中长期方向库;**§〇** 为本期重点说明 - [产品全方位优化说明 v1](./产品全方位优化说明-v1.md) — 定位/IA/交互/UI/商业化/小程序体验汇总与排期切片(**与专文互补**,冲突以评审更新为准) - [**P0 研发落地清单**](./P0-研发落地清单.md) — **本期必做**:后端状态机、Tab 筛选、发送报告话术、H5 隐私提示、宠主路径、埋点最小集等(**可直接拆 issue**) --- ## 一、产品定位 **平台定位:** 宠物店服务管理 SaaS 平台,支持多家宠物店入驻 **目标用户(v1):** - 宠物店老板 / 员工(管理预约 + 填写报告 + 发送报告 + 回访池) - 宠主(在线预约、查看公开报告、留资回访、报告分享) > **本期 P0 范围(冻结口径):** > - 门店端:预约列表、开始服务、填写报告、发送报告、回访池。 > - 宠主端:预约填单、公开报告页、下次服务提醒留资、报告打开基础埋点。 > - 报告能力:服务前/服务后照片、服务过程素材、短片生成与下载、分享链接/二维码/话术。 > > **不进入 P0:** > - 会员、储值、套餐、复杂 CRM。 > - 宠主账号内历史报告汇总。 > - 完整经营分析看板。 **登录方式:** - 微信授权登录(老板/员工主要登录方式) - 手机号+短信验证码(备用) --- ## 二、核心功能闭环(v1) ``` 预约创建(宠主/老板/员工,下单即生效)→ 待开始(new) → 开始服务(剪毛/正式开做时点击,谁点谁技师)→ 进行中(doing) → 提交报告并完成(done) → 发送给宠主 → 显式确认发送 ↘ 已取消(cancel) → 在「已完成」Tab 与完成单并列展示 ``` **报告分享流程(v1 重点):** ``` 填写并提交报告(照片+备注)→ 选择传播方式 → 宠主实际收到 → 员工「确认已发送」 ├── 复制链接/话术(发给宠主微信) ├── 当面展示二维码(现场扫码) └── 其他可核实方式 ``` --- ## 三、数据模型 ### t_store(店铺表) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键 | | name | VARCHAR | 店铺名称 | | logo | VARCHAR | 店铺Logo | | phone | VARCHAR | 联系电话 | | address | VARCHAR | 地址 | | intro | TEXT | 简介 | | owner_id | BIGINT | 老板用户ID | | invite_code | VARCHAR | 员工邀请码(8位) | | booking_day_start | TIME | 每日首个容量桶开始时间 | | booking_last_slot_start | TIME | 每日最后一个容量桶开始时间 | | booking_capacity | INT | 门店并发接待数(1~10) | | create_time | DATETIME | 创建时间 | | update_time | DATETIME | 更新时间 | ### t_user(用户表) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键 | | username | VARCHAR | 用户名 | | password | VARCHAR | 密码 | | name | VARCHAR | 姓名/技师名 | | phone | VARCHAR | 手机号 | | avatar | VARCHAR | 头像 | | store_id | BIGINT | 所属店铺 | | role | VARCHAR | boss / staff / customer | | create_time | DATETIME | 创建时间 | | update_time | DATETIME | 更新时间 | ### t_store_customer(门店客户主档) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 本店客户稳定主键 | | store_id | BIGINT | 门店 ID | | customer_user_id | BIGINT | 全局 customer 账号,留资客户可空 | | phone | VARCHAR(20) | 本店最后确认手机号,API 默认脱敏 | | display_name | VARCHAR(64) | 门店视角客户称呼 | | source | VARCHAR(32) | customer_booking / assisted_booking / report_lead | | first_contact_at / last_contact_at | DATETIME | 首次/最近接触时间 | | create_time / update_time | DATETIME | 创建/更新时间 | | deleted | TINYINT | 软删除标记 | ### t_business_event(不可变业务事件) | 字段 | 类型 | 说明 | |------|------|------| | id / event_id | BIGINT / VARCHAR(36) | 内部主键 / 随机事件 ID | | event_type / event_version | VARCHAR(64) / INT | 过去时事件类型 / schema 版本 | | store_id / store_customer_id | BIGINT | 门店范围 / 可选客户关系 | | aggregate_type / aggregate_id | VARCHAR(32) / BIGINT | 关联预约、报告或留资 | | actor_user_id / actor_role | BIGINT / VARCHAR(16) | 操作人快照,匿名事件可空 | | source | VARCHAR(32) | customer / admin / public_report / system / migration | | occurred_at / create_time | DATETIME(3) | 业务发生 / 入库时间 | | metadata_json | TEXT | 服务端白名单低敏维度,不存原始请求 | | idempotency_key | VARCHAR(128) | 可选稳定幂等键 | ### t_appointment(预约表) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键 | | pet_name | VARCHAR | 宠物名称 | | pet_type | VARCHAR | 宠物类型(猫/狗/其他) | | service_type | VARCHAR | 服务类型 | | appointment_time | DATETIME | 预约开始时间(半小时粒度) | | duration_minutes | INT | 下单时服务时长快照;修改服务项目不影响历史预约 | | status | VARCHAR | new(待开始)/ doing(服务中)/ done(已完成)/ cancel(已取消) | | store_id | BIGINT | 店铺ID | | customer_user_id | BIGINT | 被服务客户账号 | | created_by_user_id | BIGINT | 实际创建预约的账号 | | user_id | BIGINT | legacy 兼容,新数据镜像 customer_user_id | | assigned_user_id | BIGINT | 服务技师ID(开始服务时赋值,API 别名 assignedStaffId) | | remark | TEXT | 备注 | | create_time | DATETIME | 创建时间 | | update_time | DATETIME | 更新时间 | ### t_report(报告表) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键 | | appointment_id | BIGINT | 预约ID | | remark | TEXT | 备注 | | customer_user_id | BIGINT | 报告归属客户,从预约派生 | | author_staff_id | BIGINT | 实际提交报告的门店账号 | | user_id | BIGINT | legacy 兼容,新数据镜像 author_staff_id | | store_id | BIGINT | 店铺ID | | report_token | VARCHAR | 报告访问令牌(UUID,永久有效) | | pet_name | VARCHAR | 宠物名(冗余) | | service_type | VARCHAR | 服务类型(冗余) | | appointment_time | DATETIME | 服务时间(冗余) | | staff_name | VARCHAR | 服务技师名快照(冗余) | | send_status | VARCHAR(16) | unknown(历史不可确认)/ unsent(新报告待发送)/ sent(已显式确认) | | sent_at | DATETIME | 首次显式确认发送时间 | | sent_by_user_id | BIGINT | 首次确认发送员工 | | send_channel | VARCHAR(16) | wechat / qr / other;首次确认后不可覆盖 | | create_time | DATETIME | 创建时间 | | update_time | DATETIME | 更新时间 | ### t_report_image(报告媒体表) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键 | | report_id | BIGINT | 关联报告ID | | photo_url | VARCHAR(500) | 媒体URL | | photo_type | VARCHAR(20) | before / after / during | | sort_order | INT | 同类型内排序序号 | | create_time | DATETIME | 创建时间 | > 说明:当前后端已按 `photo_type` 存储前后图与过程素材;`media_type`(photo/video)为前端语义,后端字段化会在后续迭代补齐。 ### t_service_type(服务类型表) | 字段 | 类型 | 说明 | |------|------|------| | id | BIGINT | 主键 | | store_id | BIGINT | 店铺ID(NULL表示系统默认) | | name | VARCHAR | 服务名称 | | duration_minutes | INT | 预计服务时长(30~480,30 分钟粒度) | | create_time | DATETIME | 创建时间 | --- ## 四、角色权限 | 功能 | 老板(boss) | 员工(staff) | |------|-------------|---------------| | 预约列表 | ✅ | ✅ | | 新建预约 | ✅ | ✅ | | 开始服务/填写报告 | ✅ | ✅ | | 发送报告 | ✅ | ✅ | | 员工管理 | ✅ | ❌ | | 邀请码 | ✅ | ❌ | | 店铺设置 | ✅ | ❌ | | 服务类型管理 | ✅ | ❌ | ### 页面入口 - **index.html(统一入口)**:老板/员工同一套页面,通过「我的」页面区分功能 - 老板「我的」:员工管理 / 服务类型 / 店铺设置 / 我的订单 - 员工「我的」:我的订单 --- ## 五、核心功能详解 ### 5.1 登录体系 **微信授权登录**(主) - 老板/员工均可使用微信授权登录 **手机号+短信验证码登录**(备用) **员工入职流程:** - 老板后台生成邀请码 → 员工点链接注册 → 自动关联店铺 - 老板后台直接新增员工 → 系统生成随机6位密码 → 员工用手机号+密码登录 ### 5.2 预约管理 **创建预约:** - 老板/员工均可手动创建 - 字段:宠物名字、宠物类型(猫/狗/其他)、服务类型、预约时间、备注 - 建档人 = 当前登录用户 - 号源以服务项目预计时长、门店营业容量时段、门店并发接待数、线上预约与手动占用共同计算;创建时检查服务覆盖的每个半小时桶,并串行化同店容量判定避免超卖 - 线上预约当前不预选技师,容量是门店对外承诺的并发接待数;个人技师日历在具备预约前分配技师能力后再引入 **服务类型:** - 系统默认:洗澡、美容、洗澡+美容、剪指甲、驱虫 - 老板可在默认基础上新增/编辑/删除自定义服务类型,并配置 30~480 分钟的预计时长 - 员工只能使用,不能管理 **预约状态语义(与界面文案对齐):** - **new = 待开始**:下单即占号生效,**无**门店单独「确认接单」环节;到店、洗吹等若尚未到「开剪/正式开做」,仍属待开始。 - **doing = 服务中**:店员在**剪毛/正式开做**时点击「开始服务」进入本状态。 - **done = 已完成**:提交服务报告时,后端将关联预约置为已完成(见 ReportService)。 - **cancel = 已取消**:取消后在前端「已完成」Tab 中与完成单并列展示(含历史取消)。 **开始服务:** - 点击「开始服务」→ 状态变为「进行中」 - assigned_user_id = 当前登录用户(谁点谁服务) #### 预约状态迁移矩阵(产品规则 · 供开发/测试验收) | 当前状态 | 目标状态 | 触发 | 操作角色 | 备注 | |----------|----------|------|----------|------| | (创建) | new | 成功创建预约 | 宠主/老板/员工 | 下单即生效,占号 | | new | doing | 点击「开始服务」 | boss / staff | 建议在剪毛/正式开做时点击 | | new | cancel | 取消预约 | 宠主(C 端)/ 门店侧 | 业务可约定开始前可取消 | | doing | done | 提交服务报告(创建 Report) | boss / staff | 后端 `ReportService.create` 内将预约置 done | | doing | cancel | 取消(若允许) | 视业务 | **建议**:仅允许店长或限定条件,当前接口需防滥用 | | done | — | 终态 | — | 不回退 | | cancel | — | 终态 | — | 不回退 | **期望约束(建议在接口层逐步收紧):** `new → doing` 仅当当前为 `new`;`doing → done` 由报告提交触发;取消仅允许自 `new` / `doing`(按产品最终规则)。当前部分接口未校验前置状态,以实际上线前补校验为准。 ### 5.3 服务报告 **填写报告(进行中状态可操作):** **报告提交必填项:** - 宠物名称 - 服务类型 - 服务时间 - 服务前照片至少 1 张 - 服务后照片至少 1 张 服务过程中照片/视频、备注为选填。 - 技师 = 开始服务时分配的用户 - 提交后锁死,不可再修改 - 一约一份报告(同一 `appointmentId` 第二次提交返回 `REPORT_ALREADY_EXISTS`) - 报告必须绑定预约 `appointmentId`;无预约报告不作为本期主路径 > **本期迭代重点:** 洗美报告「过程短视频 + 自动生成 **竖屏成片(9:16)**」,**成片时长随素材量变化**(配置级总时长上限),支持 **预设顺序 / 穿插** 两种编排(`highlight_compose_mode`)。产品边界、参考分镜、成本与工程机制见子文档 [《洗美报告短视频成片方案》](./洗美报告短视频成片方案.md)。成片以服务端模板化拼接(如 FFmpeg)为主,成片可在报告页/H5 播放与分享。 > > **实现对齐备注(2026-04)**:服务端已落库过程素材,报告查询接口对 `duringMedia` 的回传需与成片任务对齐;`highlight_video_*`、`highlight_duration_sec`、`highlight_compose_mode` 等字段承载成片 URL、时长、编排方式与任务状态,本期需完成**发起 → 异步生成 → 成功播放 / 失败提示**闭环。 ### 5.4 发送报告(v1 核心功能) **操作入口:** 报告提交成功后进入「发送给宠主」弹层;后台报告列表也可继续处理待发送报告。 **发送方式:** 1. **复制链接** — 生成报告链接,一键复制到剪贴板,可发给宠主微信 2. **当面扫码** — 展示报告二维码,宠主现场扫码打开 3. **其他方式** — 仅在员工能够确认宠主实际收到时使用 **确认口径:** - 复制链接、复制话术、生成/展示二维码、预览或打开报告,**都不自动等于已发送**。 - 宠主实际收到后,由本店 boss/staff 选择真实渠道并点击「确认已发送」。 - 首次确认写入 `sent_at/sent_by_user_id/send_channel` 和 `report_sent` 事件;重复点击幂等成功,不覆盖首次回执。 - 历史报告没有可靠发送证据,迁移后统一为 `unknown`;只有迁移后新报告默认 `unsent` 并进入工作台待办。 **报告链接:** - URL:`https://域名/report.html?token=xxx` - Token = UUID,永久有效 - 宠主打开无需登录(v1 免登录) **报告二维码:** - 扫码直接打开报告页 - 打印出来可贴在墙上/前台,方便宠主扫码 ### 5.5 H5 报告页 **访问方式:** 链接或二维码扫码,免登录 **报告页内容:** - 品牌头部:店铺 Logo + 店铺名称 + 联系电话 + 地址 - 服务信息卡片:宠物名、服务项目、服务时间、技师名 - 前后对比照片(并排展示) - 服务过程中素材区(照片/短视频) - 技师备注 - 底部品牌信息(即使链接被转发,店铺信息持续透出) **分享能力:** - 长按图片可保存 - 链接可复制转发微信 ### 5.6 老板后台(合并到「我的」页面) **员工管理:** - 员工邀请码(复制分享) - 新增员工(姓名+手机号,系统生成密码) - 删除员工 **服务类型:** - 新增服务类型 - 删除自定义服务类型(系统默认不可删) **店铺设置:** - 店铺名称 - 店铺Logo - 联系电话 - 地址 - 简介 --- ## 六、技术方案 | 端 | 技术 | |----|------| | APP前端 | uniapp + Vue3 | | H5报告页 | Vue3(独立部署) | | 后端 | Spring Boot 3.2 + JPA | | 数据库 | MySQL | | 图片存储 | 本地存储(后续可平滑切换OSS) | --- ## 七、开发进度 | 优先级 | 功能 | 状态 | |--------|------|------| | P0 | 老板入驻/登录 | ✅ | | P0 | 员工邀请码注册 | ✅ | | P0 | 员工登录(微信+验证码) | ✅ | | P0 | 预约列表 | ✅ | | P0 | 预约创建 | ✅ | | P0 | 服务时长 + 门店并发预约容量 + 连续占用 | ✅ | | P0 | 开始服务(分配技师) | ✅ | | P0 | 报告填写 | ✅ | | P0 | 报告过程素材上传(照片/短视频) | ✅ 基础能力已接入 | | P0 | 发送报告(复制链接+下载二维码) | 🔨 本次 | | P0 | H5报告页(品牌信息强化) | 🔨 本次 | | P0 | H5报告页(链接+二维码) | ✅ | | P1 | 报告过程素材回传(duringMedia) | 🔨 进行中 | | **P0** | **洗美过程短视频自动成片(可变时长、双编排、模板拼接)** | **🔨 本期迭代重点** | | P0 | 老板后台(员工管理+邀请码) | ✅ 已合并到index.html | | P0 | 老板后台(预约概览) | ✅ 已合并到index.html | | P1 | 服务类型管理(老板后台) | ✅ | | P1 | 店铺设置(老板后台) | ✅ | | P1 | 本地文件上传(替代base64) | ✅ | | P2 | 宠主端(历史报告汇总) | ⏳ P2(不进入本期 P0) | --- ## 八、数据库变更 ```sql -- 预约表新增技师字段 ALTER TABLE t_appointment ADD COLUMN assigned_user_id BIGINT COMMENT '技师ID'; -- 店铺表新增简介字段 ALTER TABLE t_store ADD COLUMN intro TEXT COMMENT '简介'; -- 服务类型表 CREATE TABLE t_service_type ( id BIGINT PRIMARY KEY AUTO_INCREMENT, store_id BIGINT COMMENT '店铺ID,NULL表示系统默认', name VARCHAR(50) NOT NULL, duration_minutes INT NOT NULL DEFAULT 60, create_time DATETIME ); -- 系统默认服务类型 INSERT INTO t_service_type (store_id, name, duration_minutes, create_time) VALUES (NULL, '洗澡', 60, NOW()), (NULL, '美容', 120, NOW()), (NULL, '洗澡+美容', 150, NOW()), (NULL, '剪指甲', 30, NOW()), (NULL, '驱虫', 30, NOW()); -- 真实预约容量字段(完整回填与验证见 backend/db/migrations/20260801_create_booking_capacity.sql) ALTER TABLE t_appointment ADD COLUMN duration_minutes INT NOT NULL DEFAULT 60; ALTER TABLE t_schedule_block ADD COLUMN duration_minutes INT NOT NULL DEFAULT 30; ALTER TABLE t_store ADD COLUMN booking_capacity INT NOT NULL DEFAULT 1; -- 报告显式确认发送字段(完整历史兼容与验证见 backend/db/migrations/20260801_create_report_send_status.sql) ALTER TABLE t_report ADD COLUMN send_status VARCHAR(16) NOT NULL DEFAULT 'unsent'; ALTER TABLE t_report ADD COLUMN sent_at DATETIME NULL; ALTER TABLE t_report ADD COLUMN sent_by_user_id BIGINT NULL; ALTER TABLE t_report ADD COLUMN send_channel VARCHAR(16) NULL; -- 报告媒体表(前后图 + 过程素材) CREATE TABLE t_report_image ( id BIGINT PRIMARY KEY AUTO_INCREMENT, report_id BIGINT NOT NULL COMMENT '关联报告ID', photo_url VARCHAR(500) NOT NULL COMMENT '媒体URL', photo_type VARCHAR(20) NOT NULL COMMENT 'before/after/during', sort_order INT DEFAULT 0 COMMENT '同类型排序', create_time DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_report_image_report_id (report_id), INDEX idx_report_image_report_type_sort (report_id, photo_type, sort_order) ); ``` --- ## 九、后续事项(开放清单) - [ ] 宠小它 Logo 素材 - [ ] 图片存储方案(本地 / OSS) - [ ] 短信验证码服务商接入 - [ ] 微信授权登录 AppID/AppSecret - [ ] H5页面域名及部署方案 - [ ] 宠主账号内历史报告汇总(P2,不进入本期 P0) - [ ] 会员、储值、套餐、复杂 CRM(P1/P2,不进入本期 P0)