From ec4015aabad9fafd64ad1af81f9ef3ff487015fb Mon Sep 17 00:00:00 2001
From: malei <>
Date: Sat, 1 Aug 2026 20:31:53 +0800
Subject: [PATCH] feat: collect customer identity for assisted bookings
---
README.md | 4 +++
src/api/index.js | 2 +-
src/pages/appointment/AppointmentDetail.vue | 4 +--
.../appointment/CustAppointmentCreate.vue | 2 +-
src/pages/home/Home.vue | 33 +++++++++++++++++--
src/pages/report/Report.vue | 1 -
6 files changed, 38 insertions(+), 8 deletions(-)
diff --git a/README.md b/README.md
index f051ff3..0161e32 100644
--- a/README.md
+++ b/README.md
@@ -135,6 +135,10 @@ npm run dev:h5
当前实现:**提交时登录 + guest 草稿恢复**。未登录用户可填写预约表单,提交时跳转登录页(带 `redirect` 回预约页并保留 `storeId`),登录成功后回到预约页并恢复 guest 草稿(草稿 key 不依赖 `userInfo.id`,避免 `userId: undefined`)。登录态用户继续按 `userId` 维度保存草稿。草稿有效期 7 天。
+### 门店代客预约身份
+
+老板/员工在首页新建预约时必须填写宠主手机号,可选填宠主称呼。后端按手机号关联或创建 customer,并分别记录 `customerUserId` 与 `createdByUserId`;前端不得再把当前员工 `userId` 当作宠主提交。预约详情优先读取 `assignedStaffId`,兼容旧字段 `assignedUserId`。
+
## 前端 RC 发布门禁
发布前必须依次执行并全部通过:
diff --git a/src/api/index.js b/src/api/index.js
index afebc9a..7abe2c9 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -83,7 +83,7 @@ export const getAppointmentList = (/* userId, storeId, */ options = {}) =>
// 预约详情
export const getAppointmentDetail = (id) => get('/appointment/detail', { id })
-// 创建预约(userId/storeId 由后端从上下文派生;前端仍传 storeId 供 customer 选店场景,后端会按 role 决定是否采纳)
+// 创建预约:登录人身份始终由后端派生;customer 传选中门店,门店代客预约传 customerUserId 或 customerPhone
export const createAppointment = (data) => post('/appointment/create', data)
/** 门店某日可预约半小时档(可约 / 已满 / 已过);公开接口 */
diff --git a/src/pages/appointment/AppointmentDetail.vue b/src/pages/appointment/AppointmentDetail.vue
index 8343438..df5916f 100644
--- a/src/pages/appointment/AppointmentDetail.vue
+++ b/src/pages/appointment/AppointmentDetail.vue
@@ -42,9 +42,9 @@
备注
-
+
服务技师
- #{{ detail.assignedUserId }}
+ #{{ detail.assignedStaffId || detail.assignedUserId }}
预约编号 {{ detail.id }}
diff --git a/src/pages/appointment/CustAppointmentCreate.vue b/src/pages/appointment/CustAppointmentCreate.vue
index 26ed0af..8dd9cb8 100644
--- a/src/pages/appointment/CustAppointmentCreate.vue
+++ b/src/pages/appointment/CustAppointmentCreate.vue
@@ -593,7 +593,7 @@ const confirmNewAppt = async () => {
uni.showToast({ title: '宠物档案保存失败,请重试', icon: 'none' })
return
}
- const payload = { ...a, storeId, userId: userInfo.id }
+ const payload = { ...a, storeId }
payload.petId = ensuredPet.id
const res = await createAppointment(payload)
creatingAppt.value = false
diff --git a/src/pages/home/Home.vue b/src/pages/home/Home.vue
index 6c596cf..72043fb 100644
--- a/src/pages/home/Home.vue
+++ b/src/pages/home/Home.vue
@@ -199,6 +199,20 @@
+
+ 宠主手机号
+
+
+
+ 宠主称呼(可选)
+
+
宠物名字
@@ -387,7 +401,16 @@ const petTypes = [
{ label: '其他', value: '其他' }
]
-const newAppt = ref({ petName: '', petType: '', serviceType: '', appointmentTime: '', remark: '' })
+const emptyStaffAppointment = () => ({
+ customerPhone: '',
+ customerName: '',
+ petName: '',
+ petType: '',
+ serviceType: '',
+ appointmentTime: '',
+ remark: ''
+})
+const newAppt = ref(emptyStaffAppointment())
const appointmentTime = computed(() => {
const raw = newAppt.value.appointmentTime || ''
if (!raw.includes('T')) return ''
@@ -671,6 +694,10 @@ const goReport = (item) => {
const confirmNewAppt = async () => {
const a = newAppt.value
+ if (!/^1[3-9]\d{9}$/.test(a.customerPhone || '')) {
+ uni.showToast({ title: '请输入正确的宠主手机号', icon: 'none' })
+ return
+ }
if (!a.petName) { uni.showToast({ title: '请输入宠物名字', icon: 'none' }); return }
if (!a.petType) { uni.showToast({ title: '请选择宠物类型', icon: 'none' }); return }
if (!a.serviceType) { uni.showToast({ title: '请选择服务类型', icon: 'none' }); return }
@@ -681,11 +708,11 @@ const confirmNewAppt = async () => {
return
}
creatingAppt.value = true
- const res = await createAppointment({ ...a, storeId: storeInfo.id, userId: userInfo.id })
+ const res = await createAppointment({ ...a, storeId: storeInfo.id })
creatingAppt.value = false
if (res.code === 200) {
uni.showToast({ title: '预约成功', icon: 'success' })
- newAppt.value = { petName: '', petType: '', serviceType: '', appointmentTime: '', remark: '' }
+ newAppt.value = emptyStaffAppointment()
showNewAppt.value = false
fetchAppointments()
} else {
diff --git a/src/pages/report/Report.vue b/src/pages/report/Report.vue
index 59b6a4c..da2449a 100644
--- a/src/pages/report/Report.vue
+++ b/src/pages/report/Report.vue
@@ -700,7 +700,6 @@ const submitReport = async () => {
const payload = {
appointmentId: currentAppointmentId.value || null,
- userId: userInfo.id,
petName: report.value.petName,
serviceType: report.value.serviceType,
appointmentTime: report.value.appointmentTime || null,