+ +
+
+
+
-
-
消费与到店
-
-
耗卡总金额¥{{ formatMoney(member.totalConsumeAmount) }}
-
开卡总金额¥{{ formatMoney(member.totalBillingAmount) }}
-
剩余权益总金额¥{{ formatMoney(member.remainingRightsAmount) }}
-
到店天数{{ member.visitDays || 0 }} 天
-
沉睡天数{{ member.sleepDays || 0 }} 天
-
最后到店{{ member.lastVisitTime || member.lastVisit || '—' }}
-
-
等级与生日
-
-
消费等级{{ member.consumeLevelName || member.consumeLevel || '—' }}
-
阳历生日{{ member.yanglsr || '—' }}
-
阴历生日{{ member.yinlsr || '—' }}
-
生美/医美/科技/教育{{ memberTypeSummary }}
-
+
-
-
-
-
- + +
+ +
+
+ + + + + + + + + + + + + + + + +
- -
+ +
- - - - - + + + + + + + -
- -
+
+
+
+
- - - - - + + + + + + + + + + -
- -
+
+
+
+
- - - - - - + + + + + + + + + - + + + + -
- -
+
+
+
+
- - - - - + + + + + + + + + + + + + -
- -
+
+
+
-
+ +
- - - - - - - - + + + + + -
- -
+
+
+
-
-
- - - - - - - - - - + +
+
+ + + + + + +
+
+ +
+
+ + +
+
+ + + + + - - + + + -
- -
+
+
+
-
-
@@ -271,20 +328,24 @@ export default { }, data() { return { - recordsTab: 'invite', + recordsTab: 'rights', searchRights: '', searchBilling: '', searchConsume: '', searchInvite: '', searchBooking: '', searchRefund: '', + searchServiceLog: '', + searchOldLog: '', pageSize: 5, rightsPage: 1, billingPage: 1, consumePage: 1, invitePage: 1, bookingPage: 1, - refundPage: 1 + refundPage: 1, + serviceLogPage: 1, + oldLogPage: 1 } }, computed: { @@ -299,7 +360,16 @@ export default { const n = this.displayName return n ? n[0] : '会' }, - // 兼容 RemainingItems(PC 接口)与 remainingItems + consumeLevelText() { + const level = this.member.consumeLevel + const map = { 0: 'D', 1: 'C', 2: 'B', 3: 'A', 4: 'A+', 5: 'A++' } + return map[level] !== undefined ? map[level] : (this.member.consumeLevelName || '') + }, + consumeLevelClass() { + const level = this.member.consumeLevel + const map = { 0: 'level--d', 1: 'level--c', 2: 'level--b', 3: 'level--a', 4: 'level--aplus', 5: 'level--aplusplus' } + return map[level] || 'level--default' + }, remainingItems() { const list = this.member.RemainingItems || this.member.remainingItems || [] return Array.isArray(list) ? list : [] @@ -316,6 +386,22 @@ export default { if (this.member.isEducationMember === 1) t.push('教育') return t.length ? t.join(' / ') : '—' }, + formattedBirthday() { + const m = this.member + const yang = m.yanglsr || '' + const yin = m.yinlsr || '' + if (yang && yin) return `${yang}(${yin})` + if (yang) return yang + if (yin) return yin + return '—' + }, + memberTypeList() { + const list = [] + if (this.member.isBeautyMember === 1) list.push({ type: 'beauty', label: '生美' }) + if (this.member.isMedicalMember === 1) list.push({ type: 'medical', label: '医美' }) + if (this.member.isTechMember === 1) list.push({ type: 'tech', label: '科美' }) + return list + }, filteredRightsAll() { const kw = (this.searchRights || '').trim() const list = this.remainingItems @@ -345,9 +431,9 @@ export default { const list = this.billingRecords if (!kw) return list return list.filter(row => { - const orderNo = String(row.orderNo || '') - const product = String(row.productName || '') - return orderNo.includes(kw) || product.includes(kw) + const items = String(row.Items || '') + const creator = String(row.CreatorName || '') + return items.includes(kw) || creator.includes(kw) }) }, billingTotalCount() { @@ -370,8 +456,9 @@ export default { const list = this.consumeRecords if (!kw) return list return list.filter(row => { - const name = String(row.itemName || '') - return name.includes(kw) + const items = String(row.Items || '') + const operator = String(row.OperatorName || '') + return items.includes(kw) || operator.includes(kw) }) }, consumeTotalCount() { @@ -394,9 +481,9 @@ export default { const list = this.inviteRecords if (!kw) return list return list.filter(row => { - const txt = String(row.inviteContent || '') - const inviter = String(row.inviter || '') - return txt.includes(kw) || inviter.includes(kw) + const record = String(row.ContactRecord || '') + const inviter = String(row.InviterName || '') + return record.includes(kw) || inviter.includes(kw) }) }, inviteTotalCount() { @@ -419,9 +506,9 @@ export default { const list = this.bookingRecords if (!kw) return list return list.filter(row => { - const project = String(row.projectName || '') - const staff = String(row.staffName || '') - return project.includes(kw) || staff.includes(kw) + const item = String(row.ExperienceItem || '') + const coach = String(row.HealthCoachName || '') + return item.includes(kw) || coach.includes(kw) }) }, bookingTotalCount() { @@ -444,9 +531,8 @@ export default { const list = this.refundRecords if (!kw) return list return list.filter(row => { - const orderNo = String(row.orderNo || '') - const project = String(row.projectName || '') - return orderNo.includes(kw) || project.includes(kw) + const reason = String(row.RefundReason || '') + return reason.includes(kw) }) }, refundTotalCount() { @@ -460,14 +546,62 @@ export default { const start = (page - 1) * size return list.slice(start, start + size) }, + serviceLogRecords() { + const list = this.member.serviceLogRecords || [] + return Array.isArray(list) ? list : [] + }, + filteredServiceLogAll() { + const kw = (this.searchServiceLog || '').trim() + const list = this.serviceLogRecords + if (!kw) return list + return list.filter(row => { + const remark = String(row.Remark || '') + const creator = String(row.CreatorName || '') + return remark.includes(kw) || creator.includes(kw) + }) + }, + serviceLogTotalCount() { return this.filteredServiceLogAll.length }, + filteredServiceLogRecords() { + const list = this.filteredServiceLogAll + const size = this.pageSize + const maxPage = Math.max(1, Math.ceil((list.length || 1) / size)) + const page = Math.min(this.serviceLogPage || 1, maxPage) + const start = (page - 1) * size + return list.slice(start, start + size) + }, + oldLogRecords() { + const list = this.member.oldLogRecords || [] + return Array.isArray(list) ? list : [] + }, + filteredOldLogAll() { + const kw = (this.searchOldLog || '').trim() + const list = this.oldLogRecords + if (!kw) return list + return list.filter(row => { + const no = String(row.OrderNo || '') + const remarks = String(row.Remarks || '') + return no.includes(kw) || remarks.includes(kw) + }) + }, + oldLogTotalCount() { return this.filteredOldLogAll.length }, + filteredOldLogRecords() { + const list = this.filteredOldLogAll + const size = this.pageSize + const maxPage = Math.max(1, Math.ceil((list.length || 1) / size)) + const page = Math.min(this.oldLogPage || 1, maxPage) + const start = (page - 1) * size + return list.slice(start, start + size) + }, recordTabs() { return [ + { key: 'rights', label: '权益明细' }, { key: 'invite', label: '邀约记录' }, { key: 'booking', label: '预约记录' }, { key: 'billing', label: '开单记录' }, { key: 'consume', label: '消耗记录' }, - { key: 'refund', label: '退卡记录' }, - { key: 'rights', label: '剩余权益' } + { key: 'serviceLog', label: '服务日志' }, + { key: 'oldLog', label: '旧日志' }, + { key: 'refund', label: '退卡列表' } ] }, currentSearch: { @@ -479,6 +613,8 @@ export default { case 'consume': return this.searchConsume case 'refund': return this.searchRefund case 'rights': return this.searchRights + case 'serviceLog': return this.searchServiceLog + case 'oldLog': return this.searchOldLog default: return '' } }, @@ -490,17 +626,21 @@ export default { case 'consume': this.searchConsume = val; break case 'refund': this.searchRefund = val; break case 'rights': this.searchRights = val; break + case 'serviceLog': this.searchServiceLog = val; break + case 'oldLog': this.searchOldLog = val; break } } }, currentSearchPlaceholder() { switch (this.recordsTab) { - case 'invite': return '按内容 / 邀约人搜索' - case 'booking': return '按项目 / 服务人员搜索' - case 'billing': return '按单号 / 项目搜索' - case 'consume': return '按项目名称搜索' - case 'refund': return '按单号 / 项目搜索' + case 'invite': return '按联系记录/邀约人搜索' + case 'booking': return '按体验项目/健康师搜索' + case 'billing': return '按品项/开单人员搜索' + case 'consume': return '按品项/操作人员搜索' + case 'refund': return '按退卡原因搜索' case 'rights': return '按项目名称搜索' + case 'serviceLog': return '按备注/添加人搜索' + case 'oldLog': return '按开单号/备注搜索' default: return '输入关键字搜索' } }, @@ -511,7 +651,6 @@ export default { const width = 100 / count return { width: `${width}%`, - // translateX 百分比基于自身宽度,移动一个 tab 宽度用 100% 为一步 transform: `translateX(${index * 100}%)` } } @@ -533,180 +672,344 @@ export default { }, close() { this.visibleProxy = false + }, + relativeTime(dateStr) { + if (!dateStr) return '—' + const date = new Date(dateStr) + if (isNaN(date.getTime())) return dateStr + const now = new Date() + const diff = now - date + const days = Math.floor(diff / (1000 * 60 * 60 * 24)) + if (days < 0) return dateStr + if (days === 0) return '今天' + if (days === 1) return '昨天' + if (days < 7) return `${days}天前` + if (days < 30) return `${Math.floor(days / 7)}周前` + if (days < 365) return `${Math.floor(days / 30)}个月前` + return `${Math.floor(days / 365)}年前` + }, + statusClass(status) { + if (!status) return 'status--default' + const greenList = ['已到店', '已完成', '已签到', '已服务'] + const orangeList = ['待跟进', '待确认', '待服务', '进行中'] + const redList = ['已取消', '已退卡', '已退款', '已过期'] + const blueList = ['已预约', '待到店', '处理中', '已确认'] + if (greenList.includes(status)) return 'status--green' + if (orangeList.includes(status)) return 'status--orange' + if (redList.includes(status)) return 'status--red' + if (blueList.includes(status)) return 'status--blue' + return 'status--default' } } } diff --git a/store-pc/src/components/RefundDialog.vue b/store-pc/src/components/RefundDialog.vue new file mode 100644 index 0000000..abbe56c --- /dev/null +++ b/store-pc/src/components/RefundDialog.vue @@ -0,0 +1,817 @@ + + + + + diff --git a/store-pc/src/components/RefundListDialog.vue b/store-pc/src/components/RefundListDialog.vue new file mode 100644 index 0000000..2ab824e --- /dev/null +++ b/store-pc/src/components/RefundListDialog.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/store-pc/src/components/TuokeListDialog.vue b/store-pc/src/components/TuokeListDialog.vue new file mode 100644 index 0000000..e566f9e --- /dev/null +++ b/store-pc/src/components/TuokeListDialog.vue @@ -0,0 +1,191 @@ + + + + + diff --git a/store-pc/src/views/dashboard/index.vue b/store-pc/src/views/dashboard/index.vue index 5473246..535de64 100644 --- a/store-pc/src/views/dashboard/index.vue +++ b/store-pc/src/views/dashboard/index.vue @@ -7,14 +7,8 @@
今日邀约 · 预约 · 开单,一眼总览
@@ -49,17 +43,9 @@
- - + +
{{ module.title }}
@@ -74,13 +60,11 @@
{{ module.metricLabel }}
- + {{ module.primaryAction }} - {{ module.secondaryText }} + {{ module.secondaryText + }}
@@ -98,11 +82,7 @@
-
+
{{ item.time }}
@@ -113,11 +93,7 @@ 电话是否有效:{{ item.dhsfyx }} · {{ item.lxjl }} -
@@ -139,11 +115,7 @@ 预约项目:{{ item.project }} · 预约时间:{{ item.date }} {{ item.timeRange }} -
@@ -156,20 +128,19 @@
- - - - + + + + + + + + + + + + +
@@ -178,6 +149,15 @@ import MemberProfileDialog from '@/components/MemberProfileDialog.vue' import TuokeLeadDialog from '@/components/TuokeLeadDialog.vue' import InviteAddDialog from '@/components/InviteAddDialog.vue' import BookingDialog from '@/components/BookingDialog.vue' +import BillingDialog from '@/components/BillingDialog.vue' +import ConsumeDialog from '@/components/ConsumeDialog.vue' +import RefundDialog from '@/components/RefundDialog.vue' +import TuokeListDialog from '@/components/TuokeListDialog.vue' +import InviteListDialog from '@/components/InviteListDialog.vue' +import BookingCalendarDialog from '@/components/BookingCalendarDialog.vue' +import BillingListDialog from '@/components/BillingListDialog.vue' +import ConsumeListDialog from '@/components/ConsumeListDialog.vue' +import RefundListDialog from '@/components/RefundListDialog.vue' export default { name: 'Dashboard', @@ -185,7 +165,16 @@ export default { MemberProfileDialog, TuokeLeadDialog, InviteAddDialog, - BookingDialog + BookingDialog, + BillingDialog, + ConsumeDialog, + RefundDialog, + TuokeListDialog, + InviteListDialog, + BookingCalendarDialog, + BillingListDialog, + ConsumeListDialog, + RefundListDialog }, data() { return { @@ -225,9 +214,8 @@ export default { iconBg: 'linear-gradient(135deg, #6366f1, #a855f7)', metricValue: 0, metricLabel: '今日新增潜客', - primaryAction: '录入拓客信息', - secondaryText: '查看拓客数据', - route: '/tuoke' + primaryAction: '新建拓客', + secondaryText: '查看拓客数据' }, { key: 'invite', @@ -237,9 +225,8 @@ export default { iconBg: 'linear-gradient(135deg, #0ea5e9, #22c55e)', metricValue: 0, metricLabel: '待跟进邀约', - primaryAction: '去邀约', - secondaryText: '查看邀约记录', - route: '/invite' + primaryAction: '新建邀约', + secondaryText: '查看邀约记录' }, { key: 'booking', @@ -250,8 +237,7 @@ export default { metricValue: 0, metricLabel: '今日预约', primaryAction: '新建预约', - secondaryText: '打开预约日历', - route: '/booking' + secondaryText: '打开预约日历' }, { key: 'order', @@ -261,9 +247,8 @@ export default { iconBg: 'linear-gradient(135deg, #3b82f6, #2563eb)', metricValue: 0, metricLabel: '今日开单', - primaryAction: '快速开单', - secondaryText: '查看开单记录', - route: '/orders' + primaryAction: '新建开单', + secondaryText: '查看开单记录' }, { key: 'consume', @@ -273,9 +258,8 @@ export default { iconBg: 'linear-gradient(135deg, #22c55e, #16a34a)', metricValue: 0, metricLabel: '今日消耗人次', - primaryAction: '记录消耗', - secondaryText: '查看消耗记录', - route: '/consume' + primaryAction: '新建消耗', + secondaryText: '查看消耗记录' }, { key: 'refund', @@ -285,9 +269,8 @@ export default { iconBg: 'linear-gradient(135deg, #f97316, #ef4444)', metricValue: 0, metricLabel: '今日退卡', - primaryAction: '发起退卡', - secondaryText: '查看售后记录', - route: '/refund' + primaryAction: '新建退卡', + secondaryText: '查看退卡记录' } ], todayInvite: [ @@ -500,7 +483,17 @@ export default { bookingPrefill: { name: '', phone: '' - } + }, + billingDialogVisible: false, + billingPrefill: {}, + consumeDialogVisible: false, + refundDialogVisible: false, + tuokeListVisible: false, + inviteListVisible: false, + bookingCalendarVisible: false, + billingListVisible: false, + consumeListVisible: false, + refundListVisible: false } }, computed: { @@ -533,82 +526,105 @@ export default { this.bookingDialogVisible = true return } - this.goModule(module) + if (module.key === 'order') { + this.billingPrefill = {} + this.billingDialogVisible = true + return + } + if (module.key === 'consume') { + this.consumeDialogVisible = true + return + } + if (module.key === 'refund') { + this.refundDialogVisible = true + return + } }, handleMemberSearch() { const keyword = (this.memberKeyword || '').trim() if (!keyword) return this.activeMember = { - id: '10001', - dah: 'LX202603010001', - khmc: '林小纤', - sjh: keyword || '13800138000', + id: 'GK2020082505128', + dah: 'GK2020082505128', + khmc: '刘泽蓉', + sjh: '15982188353', xb: '女', - gsmdName: this.$store.state.storeInfo?.storeName || '绿纤门店', - khlxName: '散客', - zcsj: '2024-08-15 15:32', - jdqd: '小程序拓客', - tjrName: '老客户-王女士', - mainHealthUserName: '—', - subHealthUserName: '赵美美', + gsmdName: '静居寺', + khlxName: '高端客户', + zcsj: '2020-08-25', + jdqd: '19.9卡', + tjrName: '—', + mainHealthUserName: '董顺秀', + subHealthUserName: '张丽', expandUserName: '—', - lxdz: '杭州市 · 西湖区 · 文三路', - bz: '偏好安静包间,对香味略敏感', - totalConsumeAmount: 12000, - totalBillingAmount: 15280, - remainingRightsAmount: 3280, - visitDays: 18, - sleepDays: 5, - lastVisitTime: '2026-03-02 16:20', - lastConsumeTime: '2026-03-02 16:20', - consumeLevelName: '金卡会员', - yanglsr: '08-18', - yinlsr: '七月初五', + lxdz: '--', + bz: '--', + totalConsumeAmount: 290473.63, + totalBillingAmount: 1028692.14, + remainingRightsAmount: 738218.51, + sleepDays: 6, + firstVisitTime: '2025-10-08', + lastVisitTime: '2026-02-08 14:45', + lastConsumeTime: '2026-02-08 14:45', + consumeLevel: 5, + yanglsr: '1990-06-15', + yinlsr: '五月廿三', isBeautyMember: 1, - isMedicalMember: 0, - isTechMember: 0, + isMedicalMember: 1, + isTechMember: 1, isEducationMember: 0, RemainingItems: [ - { ItemName: '面部深层护理(次卡)', ItemPrice: 380, SourceType: '购买', TotalPurchased: 10, ConsumedCount: 4, RemainingCount: 6 }, - { ItemName: '肩颈调理(疗程)', ItemPrice: 268, SourceType: '购买', TotalPurchased: 5, ConsumedCount: 2, RemainingCount: 3 }, - { ItemName: '身体舒缓护理', ItemPrice: 498, SourceType: '购买', TotalPurchased: 3, ConsumedCount: 1, RemainingCount: 2 }, - { ItemName: '眼周护理套餐', ItemPrice: 198, SourceType: '赠送', TotalPurchased: 4, ConsumedCount: 1, RemainingCount: 3 }, - { ItemName: '颈肩放松体验', ItemPrice: 168, SourceType: '活动', TotalPurchased: 2, ConsumedCount: 0, RemainingCount: 2 } + { ItemName: '美拉-面部', ItemPrice: 2800, SourceType: '购买', TotalPurchased: 12, ConsumedCount: 8, RefundedCount: 0, DeductCount: 0, RemainingCount: 4 }, + { ItemName: '美拉-眼部', ItemPrice: 1500, SourceType: '购买', TotalPurchased: 10, ConsumedCount: 6, RefundedCount: 0, DeductCount: 0, RemainingCount: 4 }, + { ItemName: '逆龄胶原-眼部', ItemPrice: 9800, SourceType: '购买', TotalPurchased: 4, ConsumedCount: 1, RefundedCount: 0, DeductCount: 0, RemainingCount: 3 }, + { ItemName: '生命之波', ItemPrice: 680, SourceType: '购买', TotalPurchased: 20, ConsumedCount: 15, RefundedCount: 0, DeductCount: 0, RemainingCount: 5 }, + { ItemName: 'CELL神经', ItemPrice: 580, SourceType: '购买', TotalPurchased: 15, ConsumedCount: 10, RefundedCount: 0, DeductCount: 0, RemainingCount: 5 }, + { ItemName: '精雕', ItemPrice: 3500, SourceType: '购买', TotalPurchased: 6, ConsumedCount: 4, RefundedCount: 0, DeductCount: 0, RemainingCount: 2 }, + { ItemName: '微雕-面部', ItemPrice: 12000, SourceType: '购买', TotalPurchased: 3, ConsumedCount: 1, RefundedCount: 0, DeductCount: 0, RemainingCount: 2 } + ], + inviteRecords: [ + { InviteDate: '2026-01-17 14:06', StoreName: '静居寺', InviterName: '张丽', ContactTime: '2026-01-17 14:06', ContactRecord: '媳妇3:30过来', PhoneValid: '是' }, + { InviteDate: '2026-01-16 19:13', StoreName: '静居寺', InviterName: '张丽', ContactTime: '2026-01-16 19:13', ContactRecord: '14:00去468做科技部', PhoneValid: '是' }, + { InviteDate: '2025-12-21 18:52', StoreName: '静居寺', InviterName: '张丽', ContactTime: '2025-12-21 18:52', ContactRecord: '媳妇过来做', PhoneValid: '是' }, + { InviteDate: '2025-12-17 20:46', StoreName: '静居寺', InviterName: '张丽', ContactTime: '2025-12-17 20:46', ContactRecord: '去医院做项目', PhoneValid: '是' } + ], + bookingRecords: [ + { AppointmentDate: '2026-01-17 15:30', StoreName: '静居寺', InviterName: '张丽', HealthCoachName: '张丽', ExperienceItem: '美拉-面部+眼部+颈部', Status: '已确认', NoDealRemark: '' }, + { AppointmentDate: '2026-01-16 13:30', StoreName: '静居寺', InviterName: '张丽', HealthCoachName: '张丽', ExperienceItem: '逆龄胶原-眼部+颈部', Status: '已确认', NoDealRemark: '' }, + { AppointmentDate: '2025-12-21 14:30', StoreName: '静居寺', InviterName: '张丽', HealthCoachName: '张丽', ExperienceItem: 'CELL+生命之波', Status: '已预约', NoDealRemark: '' }, + { AppointmentDate: '2025-12-17 09:00', StoreName: '静居寺', InviterName: '张丽', HealthCoachName: '张丽', ExperienceItem: '微雕-面部+精雕', Status: '已预约', NoDealRemark: '' }, + { AppointmentDate: '2025-12-02 13:30', StoreName: '静居寺', InviterName: '张丽', HealthCoachName: '张丽', ExperienceItem: '精雕+太极神灸', Status: '已预约', NoDealRemark: '' } ], billingRecords: [ - { orderNo: 'BD202603020001', billingTime: '2026-03-02 14:30', productName: '面部深层护理(次卡)', amount: 2280, operator: '赵美美' }, - { orderNo: 'BD202602150002', billingTime: '2026-02-15 10:20', productName: '肩颈调理(疗程)', amount: 1340, operator: '赵美美' }, - { orderNo: 'BD202601300003', billingTime: '2026-01-30 16:05', productName: '身体舒缓护理', amount: 1494, operator: '李丽' }, - { orderNo: 'BD202601120004', billingTime: '2026-01-12 11:20', productName: '眼周护理套餐', amount: 792, operator: '李丽' }, - { orderNo: 'BD202512250005', billingTime: '2025-12-25 19:30', productName: '颈肩放松体验', amount: 336, operator: '王芳' } + { BillingDate: '2026-01-30 16:39', StoreName: '静居寺', CreatorName: '陈怡名', HealthCoachNames: '静居寺T区', TechTeacherNames: '科技一部T区', Items: '美拉-面部、美拉-眼部', Amount: 0, DebtAmount: 0, ActivityName: '' }, + { BillingDate: '2026-01-17 10:30', StoreName: '静居寺', CreatorName: '陈怡名', HealthCoachNames: '静居寺T区', TechTeacherNames: '科技一部T区', Items: '美拉-面部、美拉-眼部、美拉-颈部', Amount: 0, DebtAmount: 0, ActivityName: '' }, + { BillingDate: '2026-01-16 18:47', StoreName: '静居寺', CreatorName: '樊琳', HealthCoachNames: '张丽、董顺秀', TechTeacherNames: '杨琴、王方贤', Items: '逆龄胶原-眼部、逆龄胶原-颈部', Amount: 33240, DebtAmount: 0, ActivityName: '' }, + { BillingDate: '2025-12-17 16:38', StoreName: '静居寺', CreatorName: '樊琳', HealthCoachNames: '张丽、董顺秀', TechTeacherNames: '', Items: '微雕-面部、医美精雕', Amount: 96000, DebtAmount: 0, ActivityName: '' }, + { BillingDate: '2025-11-27 20:04', StoreName: '静居寺', CreatorName: '樊琳', HealthCoachNames: '董顺秀', TechTeacherNames: '', Items: '直播-精雕定金、直播-富贵包定金、直播-脂间艺术定金', Amount: 597, DebtAmount: 0, ActivityName: '' } ], consumeRecords: [ - { consumeTime: '2026-03-02 16:20', itemName: '面部深层护理', count: 1, operator: '小李' }, - { consumeTime: '2026-02-28 15:00', itemName: '肩颈调理', count: 1, operator: '小李' }, - { consumeTime: '2026-02-20 18:30', itemName: '身体舒缓护理', count: 1, operator: '小王' }, - { consumeTime: '2026-02-10 13:40', itemName: '眼周护理套餐', count: 1, operator: '小王' }, - { consumeTime: '2026-01-30 10:15', itemName: '颈肩放松体验', count: 1, operator: '小李' } + { ConsumeDate: '2026-02-08 22:45', StoreName: '绿纤静居寺店', OperatorName: '董顺秀', HealthCoachNames: '董顺秀', TechTeacherNames: '', Items: '生命之波、CELL神经', Amount: 1036.90, LaborCost: 38 }, + { ConsumeDate: '2026-02-05 19:32', StoreName: '绿纤静居寺店', OperatorName: '陈怡名', HealthCoachNames: '静居寺T区', TechTeacherNames: '科技一部T区', Items: '冻龄宝宝、BIO、宝马仪器、水氧-面部、水氧-眼部、水氧-颈部、维密包', Amount: 50143.96, LaborCost: 1155 }, + { ConsumeDate: '2026-01-30 16:37', StoreName: '绿纤静居寺店', OperatorName: '陈怡名', HealthCoachNames: '静居寺T区', TechTeacherNames: '', Items: '日式温背、RETVS、护理(盛世)、精雕、太极神灸、胸腺保养、水氧-面部、砭石床', Amount: 25330.57, LaborCost: 684 }, + { ConsumeDate: '2026-01-27 21:50', StoreName: '绿纤静居寺店', OperatorName: '董顺秀', HealthCoachNames: '董顺秀', TechTeacherNames: '', Items: '生命之波、鼎轩-童颜女神', Amount: 4905.73, LaborCost: 40 }, + { ConsumeDate: '2026-01-27 20:18', StoreName: '绿纤静居寺店', OperatorName: '张丽', HealthCoachNames: '张丽', TechTeacherNames: '', Items: 'CELL、鼎轩-青春美肤(9D)', Amount: 1182, LaborCost: 74 } ], - inviteRecords: [ - { inviteTime: '2026-03-01 09:00', inviteContent: '周末护理体验邀约', inviter: '赵美美', status: '已到店' }, - { inviteTime: '2026-02-25 14:00', inviteContent: '春季护肤专场', inviter: '赵美美', status: '已到店' }, - { inviteTime: '2026-02-18 10:30', inviteContent: '肩颈调理舒缓活动', inviter: '李丽', status: '待跟进' }, - { inviteTime: '2026-02-05 16:20', inviteContent: '身体舒缓护理体验', inviter: '李丽', status: '未接通' }, - { inviteTime: '2026-01-28 11:10', inviteContent: '生日关怀邀约', inviter: '王芳', status: '已到店' } + serviceLogRecords: [ + { CreateTime: '2026-01-17 22:50', CreatorName: '张丽', Remark: '罗米伽 刘姐媳妇 有抗衰和医美需求 但是目前对我们不信任 需要多相处 今天店长给她送了暖心客情 送了2盒医院面膜 修复她的皮肤 还是很开心', KjbRemark: '' }, + { CreateTime: '2026-01-16 22:17', CreatorName: '张丽', Remark: '陪刘姐去468做科技部 今天消耗了美拉+淋巴+眼部框架 对效果认可 很认可王专家 成交33240 送她一次大手臂的逆龄胶原', KjbRemark: '' }, + { CreateTime: '2025-12-21 21:23', CreatorName: '张丽', Remark: '刘泽蓉媳妇 今天约到468做项目 引导了cell效果 让她坚持做 对宫寒有改善 对医美有需求 想做鼻子和下巴', KjbRemark: '' } ], - bookingRecords: [ - { bookingTime: '2026-03-05 14:00', projectName: '面部深层护理', staffName: '小李', status: '待服务' }, - { bookingTime: '2026-03-02 16:00', projectName: '面部深层护理', staffName: '小李', status: '已完成' }, - { bookingTime: '2026-02-26 10:30', projectName: '肩颈调理', staffName: '小王', status: '已取消' }, - { bookingTime: '2026-02-15 19:00', projectName: '身体舒缓护理', staffName: '小王', status: '已完成' }, - { bookingTime: '2026-01-31 11:20', projectName: '眼周护理套餐', staffName: '小李', status: '待确认' } + oldLogRecords: [ + { CreateTime: '2025-12-25', OrderNo: 'SY202507190016', MemberName: '刘泽蓉', Remarks: '和张顾问一起给刘姐渲染考证 成交66600 后续又成交臻咪88000' }, + { CreateTime: '2025-12-25', OrderNo: 'SY202507190017', MemberName: '刘泽蓉', Remarks: '给她体验做生命源波 了解到想做胸部 体检正常 成交88000' }, + { CreateTime: '2025-12-25', OrderNo: 'SY202410190018', MemberName: '刘泽蓉', Remarks: '和张顾问一起做好服务' } ], refundRecords: [ - { refundTime: '2026-02-20 11:30', orderNo: 'TK202602200001', projectName: '肩颈调理(疗程)', amount: 536, operator: '赵美美' }, - { refundTime: '2026-02-10 15:10', orderNo: 'TK202602100002', projectName: '面部深层护理(次卡)', amount: 760, operator: '赵美美' }, - { refundTime: '2026-01-28 17:40', orderNo: 'TK202601280003', projectName: '身体舒缓护理', amount: 498, operator: '李丽' }, - { refundTime: '2026-01-15 13:05', orderNo: 'TK202601150004', projectName: '眼周护理套餐', amount: 198, operator: '李丽' }, - { refundTime: '2025-12-30 16:25', orderNo: 'TK202512300005', projectName: '颈肩放松体验', amount: 168, operator: '王芳' } + { RefundDate: '2026-02-11 15:48', StoreName: '绿纤西站店', RefundAmount: 133.34, ActualRefundAmount: 133, RefundReason: '项目不适合' }, + { RefundDate: '2026-02-11 15:34', StoreName: '绿纤南湖店', RefundAmount: 1199, ActualRefundAmount: 1199, RefundReason: '搬家' }, + { RefundDate: '2026-02-11 13:48', StoreName: '绿纤保利店', RefundAmount: 3054.59, ActualRefundAmount: 868, RefundReason: '' }, + { RefundDate: '2026-02-08 15:36', StoreName: '绿纤双流店', RefundAmount: 1000, ActualRefundAmount: 1000, RefundReason: '' }, + { RefundDate: '2026-02-06 18:12', StoreName: '绿纤融创店', RefundAmount: 10000, ActualRefundAmount: 10000, RefundReason: '' } ] } this.memberDialogVisible = true @@ -621,12 +637,28 @@ export default { this.bookingDialogVisible = true }, handleQuickBilling(item) { - this.$router.push('/orders') + this.billingPrefill = { + name: item.name, + memberId: '', + fromBooking: true, + bookingProject: item.project, + bookingDate: item.date, + bookingTimeRange: item.timeRange, + bookingStaff: item.staffName + } + this.billingDialogVisible = true }, - goModule(module) { - if (module.route) { - this.$router.push(module.route) + handleModuleSecondary(module) { + const map = { + tuoke: 'tuokeListVisible', + invite: 'inviteListVisible', + booking: 'bookingCalendarVisible', + order: 'billingListVisible', + consume: 'consumeListVisible', + refund: 'refundListVisible' } + const key = map[module.key] + if (key) this[key] = true } } } @@ -655,6 +687,7 @@ export default { color: #111827; letter-spacing: 0.5px; } + .store-subtitle { margin-top: 4px; font-size: 13px; @@ -670,6 +703,7 @@ export default { padding: 0 20px; border-radius: 0 999px 999px 0; } + ::v-deep .el-input__inner { border-radius: 999px 0 0 999px; padding-left: 40px; @@ -745,10 +779,12 @@ export default { align-items: center; justify-content: space-between; margin-bottom: 4px; + .label { font-size: 13px; color: #6b7280; } + .tag { font-size: 11px; padding: 2px 8px; @@ -796,6 +832,7 @@ export default { font-weight: 600; color: #111827; } + .module-subtitle { margin-top: 2px; font-size: 12px; @@ -811,6 +848,7 @@ export default { align-items: center; justify-content: center; color: #fff; + i { font-size: 20px; } @@ -818,11 +856,13 @@ export default { .module-meta { margin-top: 8px; + .meta-value { font-size: 22px; font-weight: 600; color: #111827; } + .meta-label { margin-top: 2px; font-size: 12px; @@ -835,6 +875,7 @@ export default { display: flex; align-items: center; justify-content: space-between; + .primary-action { display: inline-flex; align-items: center; @@ -849,9 +890,16 @@ export default { font-weight: 500; box-shadow: 0 4px 10px rgba(37, 99, 235, 0.35); } + .secondary-text { font-size: 12px; color: #9ca3af; + cursor: pointer; + transition: color 0.15s; + + &:hover { + color: #2563eb; + } } } @@ -881,8 +929,7 @@ export default { color: #2563eb; } -.timeline-list { -} +.timeline-list {} .timeline-item { display: grid; @@ -892,7 +939,7 @@ export default { font-size: 12px; } -.timeline-item + .timeline-item { +.timeline-item+.timeline-item { border-top: 1px dashed #e5e7eb; } @@ -906,20 +953,24 @@ export default { display: flex; align-items: center; gap: 6px; + .name { color: #111827; font-weight: 500; } + .mobile { color: #6b7280; } } + .line-sub { margin-top: 2px; display: flex; align-items: center; justify-content: space-between; gap: 8px; + .project { color: #6b7280; flex: 1; @@ -1001,10 +1052,12 @@ export default { .dashboard-page { padding: 16px; } + .top-bar { grid-template-columns: minmax(0, 1fr); row-gap: 12px; } + .layout-grid { grid-template-columns: minmax(0, 1fr); }