微信小程序页面迁移校验之前 P5任务处理之前
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"navigationBarTitleText": "业绩详情",
|
||||
"usingComponents": {
|
||||
"ai-float-button": "/components/ai-float-button/ai-float-button",
|
||||
"metric-card": "/components/metric-card/metric-card",
|
||||
"t-icon": "tdesign-miniprogram/icon/icon",
|
||||
"t-loading": "tdesign-miniprogram/loading/loading"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
// TODO: 联调时替换为真实 API 调用
|
||||
|
||||
/** 业绩明细项(本月/上月) */
|
||||
interface IncomeItem {
|
||||
icon: string
|
||||
label: string
|
||||
desc: string
|
||||
value: string
|
||||
}
|
||||
|
||||
/** 服务记录(按日期分组后的展示结构) */
|
||||
interface ServiceRecord {
|
||||
customerName: string
|
||||
avatarChar: string
|
||||
avatarGradient: string
|
||||
timeRange: string
|
||||
hours: string
|
||||
courseType: string
|
||||
courseTypeClass: string
|
||||
location: string
|
||||
income: string
|
||||
}
|
||||
|
||||
interface DateGroup {
|
||||
date: string
|
||||
records: ServiceRecord[]
|
||||
}
|
||||
|
||||
Page({
|
||||
data: {
|
||||
pageState: 'loading' as 'loading' | 'empty' | 'normal',
|
||||
|
||||
/** Banner 数据 */
|
||||
coachName: '小燕',
|
||||
coachRole: '助教',
|
||||
storeName: '广州朗朗桌球',
|
||||
monthlyIncome: '¥6,206',
|
||||
lastMonthIncome: '¥16,880',
|
||||
|
||||
/** 收入档位 */
|
||||
currentTier: {
|
||||
basicRate: 80,
|
||||
incentiveRate: 95,
|
||||
},
|
||||
nextTier: {
|
||||
basicRate: 90,
|
||||
incentiveRate: 114,
|
||||
},
|
||||
upgradeHoursNeeded: 15,
|
||||
upgradeBonus: 800,
|
||||
|
||||
/** 本月业绩明细 */
|
||||
incomeItems: [] as IncomeItem[],
|
||||
monthlyTotal: '¥6,950.5',
|
||||
|
||||
/** 服务记录 */
|
||||
thisMonthRecords: [] as DateGroup[],
|
||||
thisMonthRecordsExpanded: false,
|
||||
/** 默认显示前 N 条日期组 */
|
||||
visibleRecordGroups: 2,
|
||||
|
||||
/** 新客列表 */
|
||||
newCustomers: [] as Array<{ name: string; avatarChar: string; gradient: string; lastService: string; count: number }>,
|
||||
newCustomerExpanded: false,
|
||||
|
||||
/** 常客列表 */
|
||||
regularCustomers: [] as Array<{ name: string; avatarChar: string; gradient: string; hours: number; income: string; count: number }>,
|
||||
regularCustomerExpanded: false,
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadData()
|
||||
},
|
||||
|
||||
loadData() {
|
||||
this.setData({ pageState: 'loading' })
|
||||
|
||||
setTimeout(() => {
|
||||
// TODO: 替换为真实 API
|
||||
const incomeItems: IncomeItem[] = [
|
||||
{ icon: '🎱', label: '基础课', desc: '80元/h × 75h', value: '¥6,000' },
|
||||
{ icon: '⭐', label: '激励课', desc: '95.05元/h × 10h', value: '¥950.5' },
|
||||
{ icon: '💰', label: '充值激励', desc: '客户充值返佣', value: '¥500' },
|
||||
{ icon: '🏆', label: 'TOP3 销冠奖', desc: '全店业绩前三名奖励', value: '继续努力' },
|
||||
]
|
||||
|
||||
const gradients = [
|
||||
'from-blue', 'from-pink', 'from-teal', 'from-green',
|
||||
'from-orange', 'from-purple', 'from-violet', 'from-amber',
|
||||
]
|
||||
|
||||
// 模拟服务记录按日期分组
|
||||
const thisMonthRecords: DateGroup[] = [
|
||||
{
|
||||
date: '2月7日',
|
||||
records: [
|
||||
{ customerName: '王先生', avatarChar: '王', avatarGradient: gradients[0], timeRange: '20:00-22:00', hours: '2.0h', courseType: '基础课', courseTypeClass: 'tag-basic', location: '3号台', income: '¥160' },
|
||||
{ customerName: '李女士', avatarChar: '李', avatarGradient: gradients[1], timeRange: '16:00-18:00', hours: '2.0h', courseType: '包厢课', courseTypeClass: 'tag-vip', location: 'VIP1号房', income: '¥190' },
|
||||
],
|
||||
},
|
||||
{
|
||||
date: '2月6日',
|
||||
records: [
|
||||
{ customerName: '张先生', avatarChar: '张', avatarGradient: gradients[2], timeRange: '19:00-21:00', hours: '2.0h', courseType: '基础课', courseTypeClass: 'tag-basic', location: '5号台', income: '¥160' },
|
||||
],
|
||||
},
|
||||
{
|
||||
date: '2月5日',
|
||||
records: [
|
||||
{ customerName: '陈女士', avatarChar: '陈', avatarGradient: gradients[2], timeRange: '20:00-22:00', hours: '2.0h', courseType: '基础课', courseTypeClass: 'tag-basic', location: '2号台', income: '¥160' },
|
||||
{ customerName: '赵先生', avatarChar: '赵', avatarGradient: gradients[5], timeRange: '14:00-16:00', hours: '2.0h', courseType: '基础课', courseTypeClass: 'tag-basic', location: '7号台', income: '¥160' },
|
||||
],
|
||||
},
|
||||
{
|
||||
date: '2月4日',
|
||||
records: [
|
||||
{ customerName: '孙先生', avatarChar: '孙', avatarGradient: gradients[6], timeRange: '19:00-21:00', hours: '2.0h', courseType: '包厢课', courseTypeClass: 'tag-vip', location: 'VIP2号房', income: '¥190' },
|
||||
{ customerName: '吴女士', avatarChar: '吴', avatarGradient: gradients[2], timeRange: '15:00-17:00', hours: '2.0h', courseType: '基础课', courseTypeClass: 'tag-basic', location: '1号台', income: '¥160' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const newCustomers = [
|
||||
{ name: '王先生', avatarChar: '王', gradient: gradients[0], lastService: '2月7日', count: 2 },
|
||||
{ name: '李女士', avatarChar: '李', gradient: gradients[1], lastService: '2月7日', count: 1 },
|
||||
{ name: '刘先生', avatarChar: '刘', gradient: gradients[4], lastService: '2月6日', count: 1 },
|
||||
]
|
||||
|
||||
const regularCustomers = [
|
||||
{ name: '张先生', avatarChar: '张', gradient: gradients[2], hours: 12, income: '¥960', count: 6 },
|
||||
{ name: '陈女士', avatarChar: '陈', gradient: gradients[2], hours: 10, income: '¥800', count: 5 },
|
||||
{ name: '赵先生', avatarChar: '赵', gradient: gradients[5], hours: 8, income: '¥640', count: 4 },
|
||||
{ name: '孙先生', avatarChar: '孙', gradient: gradients[6], hours: 6, income: '¥570', count: 3 },
|
||||
]
|
||||
|
||||
this.setData({
|
||||
pageState: 'normal',
|
||||
incomeItems,
|
||||
thisMonthRecords,
|
||||
newCustomers,
|
||||
regularCustomers,
|
||||
})
|
||||
}, 500)
|
||||
},
|
||||
|
||||
/** 展开/收起本月服务记录 */
|
||||
toggleThisMonthRecords() {
|
||||
this.setData({ thisMonthRecordsExpanded: !this.data.thisMonthRecordsExpanded })
|
||||
},
|
||||
|
||||
/** 查看全部 → 跳转业绩明细 */
|
||||
goToRecords() {
|
||||
wx.navigateTo({ url: '/pages/performance-records/performance-records' })
|
||||
},
|
||||
|
||||
/** 展开/收起新客列表 */
|
||||
toggleNewCustomer() {
|
||||
this.setData({ newCustomerExpanded: !this.data.newCustomerExpanded })
|
||||
},
|
||||
|
||||
/** 展开/收起常客列表 */
|
||||
toggleRegularCustomer() {
|
||||
this.setData({ regularCustomerExpanded: !this.data.regularCustomerExpanded })
|
||||
},
|
||||
|
||||
/** 点击客户卡片 → 跳转任务详情 */
|
||||
onCustomerTap(e: WechatMiniprogram.TouchEvent) {
|
||||
const { name } = e.currentTarget.dataset
|
||||
wx.navigateTo({
|
||||
url: `/pages/task-detail/task-detail?customerName=${name}`,
|
||||
fail: () => wx.showToast({ title: '页面跳转失败', icon: 'none' }),
|
||||
})
|
||||
},
|
||||
|
||||
/** 点击收入概览卡片 → 跳转业绩记录 */
|
||||
onIncomeCardTap() {
|
||||
wx.navigateTo({ url: '/pages/performance-records/performance-records' })
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,272 @@
|
||||
<!-- 加载态 -->
|
||||
<view class="page-loading" wx:if="{{pageState === 'loading'}}">
|
||||
<t-loading theme="circular" size="80rpx" text="加载中..." />
|
||||
</view>
|
||||
|
||||
<block wx:elif="{{pageState === 'empty'}}">
|
||||
<view class="page-empty">
|
||||
<t-icon name="chart-bar" size="120rpx" color="#dcdcdc" />
|
||||
<text class="empty-text">暂无业绩数据</text>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<block wx:else>
|
||||
<!-- Banner -->
|
||||
<view class="banner-section">
|
||||
<!-- banner 背景用 CSS 渐变替代图片 -->
|
||||
<view class="banner-bg-gradient"></view>
|
||||
<view class="banner-content">
|
||||
<!-- 个人信息 -->
|
||||
<view class="coach-info">
|
||||
<view class="coach-avatar">
|
||||
<text class="avatar-emoji">👤</text>
|
||||
</view>
|
||||
<view class="coach-meta">
|
||||
<view class="coach-name-row">
|
||||
<text class="coach-name">{{coachName}}</text>
|
||||
<text class="coach-role-tag">{{coachRole}}</text>
|
||||
</view>
|
||||
<text class="coach-store">{{storeName}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 核心收入数据 -->
|
||||
<view class="income-overview" bindtap="onIncomeCardTap">
|
||||
<view class="income-card">
|
||||
<text class="income-label">本月预计收入</text>
|
||||
<text class="income-value">{{monthlyIncome}}</text>
|
||||
</view>
|
||||
<view class="income-card">
|
||||
<text class="income-label">上月收入</text>
|
||||
<text class="income-value income-highlight">{{lastMonthIncome}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 收入情况 -->
|
||||
<view class="section-card">
|
||||
<view class="section-title">
|
||||
<view class="title-dot dot-primary"></view>
|
||||
<text>收入情况</text>
|
||||
</view>
|
||||
|
||||
<!-- 当前档位 -->
|
||||
<view class="tier-card tier-current">
|
||||
<view class="tier-badge badge-current">当前档位</view>
|
||||
<view class="tier-row">
|
||||
<view class="tier-icon-label">
|
||||
<text class="tier-emoji">📊</text>
|
||||
<text class="tier-label tier-label-green">当前档位</text>
|
||||
</view>
|
||||
<view class="tier-rates">
|
||||
<view class="rate-item">
|
||||
<view class="rate-value-row">
|
||||
<text class="rate-value rate-green">{{currentTier.basicRate}}</text>
|
||||
<text class="rate-unit rate-green-light">元/h</text>
|
||||
</view>
|
||||
<text class="rate-desc rate-green-light">基础课到手</text>
|
||||
</view>
|
||||
<view class="rate-divider"></view>
|
||||
<view class="rate-item">
|
||||
<view class="rate-value-row">
|
||||
<text class="rate-value rate-green">{{currentTier.incentiveRate}}</text>
|
||||
<text class="rate-unit rate-green-light">元/h</text>
|
||||
</view>
|
||||
<text class="rate-desc rate-green-light">激励课到手</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 下一阶段 -->
|
||||
<view class="tier-card tier-next">
|
||||
<view class="tier-badge badge-next">下一阶段</view>
|
||||
<view class="tier-row">
|
||||
<view class="tier-icon-label">
|
||||
<text class="tier-emoji">🎯</text>
|
||||
<text class="tier-label tier-label-yellow">下一阶段</text>
|
||||
</view>
|
||||
<view class="tier-rates">
|
||||
<view class="rate-item">
|
||||
<view class="rate-value-row">
|
||||
<text class="rate-value rate-yellow">{{nextTier.basicRate}}</text>
|
||||
<text class="rate-unit rate-yellow-light">元/h</text>
|
||||
</view>
|
||||
<text class="rate-desc rate-yellow-light">基础课到手</text>
|
||||
</view>
|
||||
<view class="rate-divider rate-divider-yellow"></view>
|
||||
<view class="rate-item">
|
||||
<view class="rate-value-row">
|
||||
<text class="rate-value rate-yellow">{{nextTier.incentiveRate}}</text>
|
||||
<text class="rate-unit rate-yellow-light">元/h</text>
|
||||
</view>
|
||||
<text class="rate-desc rate-yellow-light">激励课到手</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 升级提示 -->
|
||||
<view class="upgrade-hint">
|
||||
<view class="upgrade-left">
|
||||
<text class="upgrade-emoji">⏱️</text>
|
||||
<view class="upgrade-text">
|
||||
<text class="upgrade-label">距离下一阶段</text>
|
||||
<view class="upgrade-hours">
|
||||
<text>需完成 </text>
|
||||
<text class="upgrade-hours-num">{{upgradeHoursNeeded}}</text>
|
||||
<text> 小时</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="upgrade-bonus">
|
||||
<text class="bonus-label">到达即得</text>
|
||||
<text class="bonus-value">{{upgradeBonus}}元</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 本月业绩 -->
|
||||
<view class="section-card">
|
||||
<view class="section-title">
|
||||
<view class="title-dot dot-success"></view>
|
||||
<text>本月业绩 预估</text>
|
||||
</view>
|
||||
|
||||
<view class="income-list">
|
||||
<view class="income-row" wx:for="{{incomeItems}}" wx:key="label">
|
||||
<view class="income-row-left">
|
||||
<view class="income-icon-box">
|
||||
<text>{{item.icon}}</text>
|
||||
</view>
|
||||
<view class="income-info">
|
||||
<text class="income-item-label">{{item.label}}</text>
|
||||
<text class="income-item-desc">{{item.desc}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<text class="income-item-value">{{item.value}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 合计 -->
|
||||
<view class="income-total">
|
||||
<text class="total-label">本月合计 预估</text>
|
||||
<text class="total-value">{{monthlyTotal}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 服务记录明细 -->
|
||||
<view class="service-records-section">
|
||||
<view class="service-records-header">
|
||||
<text class="service-records-emoji">📋</text>
|
||||
<text class="service-records-title">我的服务记录明细</text>
|
||||
</view>
|
||||
|
||||
<block wx:for="{{thisMonthRecords}}" wx:key="date" wx:if="{{thisMonthRecordsExpanded || index < visibleRecordGroups}}">
|
||||
<view class="date-divider">
|
||||
<text class="dd-date">{{item.date}}</text>
|
||||
</view>
|
||||
<view class="record-item" wx:for="{{item.records}}" wx:for-item="rec" wx:key="customerName">
|
||||
<view class="record-avatar avatar-{{rec.avatarGradient}}">
|
||||
<text>{{rec.avatarChar}}</text>
|
||||
</view>
|
||||
<view class="record-content">
|
||||
<view class="record-top">
|
||||
<view class="record-name-time">
|
||||
<text class="record-name">{{rec.customerName}}</text>
|
||||
<text class="record-time">{{rec.timeRange}}</text>
|
||||
</view>
|
||||
<text class="record-hours">{{rec.hours}}</text>
|
||||
</view>
|
||||
<view class="record-bottom">
|
||||
<view class="record-tags">
|
||||
<text class="course-tag {{rec.courseTypeClass}}">{{rec.courseType}}</text>
|
||||
<text class="record-location">{{rec.location}}</text>
|
||||
</view>
|
||||
<text class="record-income">我的预估收入 <text class="record-income-val">{{rec.income}}</text></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<view class="records-toggle" bindtap="toggleThisMonthRecords" wx:if="{{thisMonthRecords.length > visibleRecordGroups}}">
|
||||
<text>{{thisMonthRecordsExpanded ? '收起' : '展开更多'}}</text>
|
||||
<t-icon name="{{thisMonthRecordsExpanded ? 'chevron-up' : 'chevron-down'}}" size="28rpx" />
|
||||
</view>
|
||||
|
||||
<view class="records-view-all" bindtap="goToRecords">
|
||||
<text>查看全部</text>
|
||||
<t-icon name="chevron-right" size="32rpx" color="#0052d9" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 我的新客 -->
|
||||
<view class="section-card">
|
||||
<view class="section-title">
|
||||
<view class="title-dot dot-cyan"></view>
|
||||
<text>我的新客</text>
|
||||
</view>
|
||||
|
||||
<view class="customer-list">
|
||||
<view
|
||||
class="customer-item"
|
||||
wx:for="{{newCustomers}}"
|
||||
wx:key="name"
|
||||
wx:if="{{newCustomerExpanded || index < 2}}"
|
||||
data-name="{{item.name}}"
|
||||
bindtap="onCustomerTap"
|
||||
>
|
||||
<view class="customer-avatar avatar-{{item.gradient}}">
|
||||
<text>{{item.avatarChar}}</text>
|
||||
</view>
|
||||
<view class="customer-info">
|
||||
<text class="customer-name">{{item.name}}</text>
|
||||
<text class="customer-detail">最近服务: {{item.lastService}} · {{item.count}}次</text>
|
||||
</view>
|
||||
<t-icon name="chevron-right" size="32rpx" color="#c5c5c5" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="toggle-btn" bindtap="toggleNewCustomer" wx:if="{{newCustomers.length > 2}}">
|
||||
<text>{{newCustomerExpanded ? '收起 ↑' : '查看更多 ↓'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 我的常客 -->
|
||||
<view class="section-card">
|
||||
<view class="section-title">
|
||||
<view class="title-dot dot-pink"></view>
|
||||
<text>我的常客</text>
|
||||
</view>
|
||||
|
||||
<view class="customer-list">
|
||||
<view
|
||||
class="customer-item"
|
||||
wx:for="{{regularCustomers}}"
|
||||
wx:key="name"
|
||||
wx:if="{{regularCustomerExpanded || index < 2}}"
|
||||
data-name="{{item.name}}"
|
||||
bindtap="onCustomerTap"
|
||||
>
|
||||
<view class="customer-avatar avatar-{{item.gradient}}">
|
||||
<text>{{item.avatarChar}}</text>
|
||||
</view>
|
||||
<view class="customer-info">
|
||||
<text class="customer-name">{{item.name}}</text>
|
||||
<text class="customer-detail">{{item.count}}次 · {{item.hours}}h · {{item.income}}</text>
|
||||
</view>
|
||||
<t-icon name="chevron-right" size="32rpx" color="#c5c5c5" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="toggle-btn" bindtap="toggleRegularCustomer" wx:if="{{regularCustomers.length > 2}}">
|
||||
<text>{{regularCustomerExpanded ? '收起 ↑' : '查看更多 ↓'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
<!-- AI 悬浮按钮 -->
|
||||
<ai-float-button bottom="{{120}}" />
|
||||
|
||||
<dev-fab />
|
||||
@@ -0,0 +1,657 @@
|
||||
/* ============================================
|
||||
* 加载态 / 空态
|
||||
* ============================================ */
|
||||
.page-loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.page-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 60vh;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: var(--font-sm);
|
||||
color: var(--color-gray-6);
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
* Banner
|
||||
* ============================================ */
|
||||
.banner-section {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.banner-bg-gradient {
|
||||
width: 100%;
|
||||
height: 480rpx;
|
||||
background: linear-gradient(135deg, #0052d9, #0080ff);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.banner-content {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 24rpx 40rpx 32rpx;
|
||||
}
|
||||
|
||||
.coach-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
margin-bottom: 40rpx;
|
||||
margin-top: 16rpx;
|
||||
}
|
||||
|
||||
.coach-avatar {
|
||||
width: 112rpx;
|
||||
height: 112rpx;
|
||||
border-radius: 24rpx;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
overflow: hidden;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.avatar-img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.avatar-emoji {
|
||||
font-size: 56rpx;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.coach-meta {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.coach-name-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.coach-name {
|
||||
font-size: 40rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.coach-role-tag {
|
||||
padding: 4rpx 16rpx;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 24rpx;
|
||||
font-size: var(--font-xs);
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.coach-store {
|
||||
font-size: var(--font-sm);
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
/* 收入概览卡片 */
|
||||
.income-overview {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.income-card {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 24rpx;
|
||||
padding: 24rpx;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(4px);
|
||||
}
|
||||
|
||||
.income-label {
|
||||
display: block;
|
||||
font-size: var(--font-xs);
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.income-value {
|
||||
display: block;
|
||||
font-size: var(--font-2xl);
|
||||
font-weight: 700;
|
||||
color: #ffffff;
|
||||
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.income-highlight {
|
||||
color: #a7f3d0;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
* 通用 Section 卡片
|
||||
* ============================================ */
|
||||
.section-card {
|
||||
background: #ffffff;
|
||||
border-radius: 32rpx;
|
||||
padding: 32rpx;
|
||||
margin: 24rpx 24rpx 0;
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 24rpx;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 600;
|
||||
color: var(--color-gray-13);
|
||||
}
|
||||
|
||||
.title-dot {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.dot-primary { background: var(--color-primary); }
|
||||
.dot-success { background: var(--color-success); }
|
||||
.dot-cyan { background: #06b6d4; }
|
||||
.dot-pink { background: #ec4899; }
|
||||
|
||||
/* ============================================
|
||||
* 收入档位
|
||||
* ============================================ */
|
||||
.tier-card {
|
||||
position: relative;
|
||||
padding: 24rpx;
|
||||
border-radius: 24rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.tier-current {
|
||||
background: linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%);
|
||||
border: 2rpx solid #86efac;
|
||||
}
|
||||
|
||||
.tier-next {
|
||||
background: linear-gradient(135deg, #fefce8 0%, #fef9c3 100%);
|
||||
border: 2rpx solid #fde047;
|
||||
}
|
||||
|
||||
.tier-badge {
|
||||
position: absolute;
|
||||
top: -16rpx;
|
||||
right: 24rpx;
|
||||
padding: 4rpx 20rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 20rpx;
|
||||
font-weight: 600;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.badge-current {
|
||||
background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
|
||||
}
|
||||
|
||||
.badge-next {
|
||||
background: linear-gradient(135deg, #eab308 0%, #ca8a04 100%);
|
||||
}
|
||||
|
||||
.tier-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tier-icon-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.tier-emoji {
|
||||
font-size: 48rpx;
|
||||
}
|
||||
|
||||
.tier-label {
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tier-label-green { color: #15803d; }
|
||||
.tier-label-yellow { color: #a16207; }
|
||||
|
||||
.tier-rates {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.rate-item {
|
||||
text-align: center;
|
||||
width: 128rpx;
|
||||
}
|
||||
|
||||
.rate-value-row {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
gap: 4rpx;
|
||||
}
|
||||
|
||||
.rate-value {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.rate-unit {
|
||||
font-size: var(--font-xs);
|
||||
}
|
||||
|
||||
.rate-desc {
|
||||
font-size: 20rpx;
|
||||
margin-top: 4rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.rate-green { color: #15803d; }
|
||||
.rate-green-light { color: #16a34a; }
|
||||
.rate-yellow { color: #a16207; }
|
||||
.rate-yellow-light { color: #ca8a04; }
|
||||
|
||||
.rate-divider {
|
||||
width: 2rpx;
|
||||
height: 64rpx;
|
||||
background: #bbf7d0;
|
||||
}
|
||||
|
||||
.rate-divider-yellow {
|
||||
background: #fef08a;
|
||||
}
|
||||
|
||||
/* 升级提示 */
|
||||
.upgrade-hint {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background: linear-gradient(to right, #eff6ff, #eef2ff);
|
||||
border-radius: 24rpx;
|
||||
padding: 24rpx;
|
||||
border: 2rpx solid #bfdbfe;
|
||||
}
|
||||
|
||||
.upgrade-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.upgrade-emoji {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.upgrade-label {
|
||||
font-size: var(--font-xs);
|
||||
color: var(--color-gray-9);
|
||||
display: block;
|
||||
}
|
||||
|
||||
.upgrade-hours {
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 600;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.upgrade-hours-num {
|
||||
font-size: var(--font-base);
|
||||
}
|
||||
|
||||
.upgrade-bonus {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
background: linear-gradient(to right, #fbbf24, #f97316);
|
||||
color: #ffffff;
|
||||
padding: 12rpx 24rpx;
|
||||
border-radius: 16rpx;
|
||||
}
|
||||
|
||||
.bonus-label {
|
||||
font-size: 20rpx;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
.bonus-value {
|
||||
font-size: 36rpx;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
* 本月业绩明细
|
||||
* ============================================ */
|
||||
.income-list {
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.income-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16rpx 0;
|
||||
border-bottom: 2rpx solid var(--color-gray-1);
|
||||
}
|
||||
|
||||
.income-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.income-row-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.income-icon-box {
|
||||
width: 64rpx;
|
||||
height: 64rpx;
|
||||
border-radius: 16rpx;
|
||||
background: var(--color-gray-1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: var(--font-sm);
|
||||
}
|
||||
|
||||
.income-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.income-item-label {
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-gray-13);
|
||||
}
|
||||
|
||||
.income-item-desc {
|
||||
font-size: 20rpx;
|
||||
color: var(--color-gray-5);
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.income-item-value {
|
||||
font-size: var(--font-base);
|
||||
font-weight: 700;
|
||||
color: var(--color-gray-13);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
.income-total {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-top: 16rpx;
|
||||
border-top: 2rpx solid var(--color-gray-1);
|
||||
}
|
||||
|
||||
.total-label {
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-gray-7);
|
||||
}
|
||||
|
||||
.total-value {
|
||||
font-size: 40rpx;
|
||||
font-weight: 700;
|
||||
color: var(--color-success);
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
* 服务记录
|
||||
* ============================================ */
|
||||
.service-records-section {
|
||||
margin-top: 32rpx;
|
||||
margin: 32rpx -32rpx -32rpx;
|
||||
padding: 32rpx;
|
||||
background: rgba(243, 243, 243, 0.7);
|
||||
border-radius: 0 0 32rpx 32rpx;
|
||||
}
|
||||
|
||||
.service-records-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.service-records-emoji {
|
||||
font-size: var(--font-sm);
|
||||
}
|
||||
|
||||
.service-records-title {
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 600;
|
||||
color: var(--color-gray-13);
|
||||
}
|
||||
|
||||
.date-divider {
|
||||
padding: 20rpx 0 8rpx;
|
||||
}
|
||||
|
||||
.dd-date {
|
||||
font-size: 22rpx;
|
||||
color: var(--color-gray-7);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.record-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
padding: 16rpx 0;
|
||||
}
|
||||
|
||||
.record-avatar {
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #ffffff;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* 头像渐变色 */
|
||||
.avatar-from-blue { background: linear-gradient(135deg, #60a5fa, #6366f1); }
|
||||
.avatar-from-pink { background: linear-gradient(135deg, #f472b6, #f43f5e); }
|
||||
.avatar-from-teal { background: linear-gradient(135deg, #2dd4bf, #10b981); }
|
||||
.avatar-from-green { background: linear-gradient(135deg, #4ade80, #14b8a6); }
|
||||
.avatar-from-orange { background: linear-gradient(135deg, #fb923c, #f59e0b); }
|
||||
.avatar-from-purple { background: linear-gradient(135deg, #c084fc, #8b5cf6); }
|
||||
.avatar-from-violet { background: linear-gradient(135deg, #a78bfa, #7c3aed); }
|
||||
.avatar-from-amber { background: linear-gradient(135deg, #fbbf24, #eab308); }
|
||||
|
||||
.record-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.record-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.record-name-time {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.record-name {
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-gray-13);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.record-time {
|
||||
font-size: var(--font-xs);
|
||||
color: var(--color-gray-6);
|
||||
}
|
||||
|
||||
.record-hours {
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 700;
|
||||
color: #059669;
|
||||
font-variant-numeric: tabular-nums;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.record-bottom {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.record-tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.course-tag {
|
||||
padding: 2rpx 12rpx;
|
||||
border-radius: 8rpx;
|
||||
font-size: 22rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.tag-basic {
|
||||
background: #ecfdf5;
|
||||
color: #15803d;
|
||||
}
|
||||
|
||||
.tag-vip {
|
||||
background: #eff6ff;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.tag-tip {
|
||||
background: #fffbeb;
|
||||
color: #a16207;
|
||||
}
|
||||
|
||||
.record-location {
|
||||
font-size: var(--font-xs);
|
||||
color: var(--color-gray-7);
|
||||
}
|
||||
|
||||
.record-income {
|
||||
font-size: 22rpx;
|
||||
color: var(--color-gray-5);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.record-income-val {
|
||||
font-weight: 500;
|
||||
color: var(--color-gray-9);
|
||||
}
|
||||
|
||||
.records-toggle {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8rpx;
|
||||
padding: 16rpx 0;
|
||||
font-size: var(--font-sm);
|
||||
color: var(--color-gray-7);
|
||||
}
|
||||
|
||||
.records-view-all {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 4rpx;
|
||||
padding: 12rpx 0;
|
||||
font-size: var(--font-sm);
|
||||
color: var(--color-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
* 新客 / 常客列表
|
||||
* ============================================ */
|
||||
.customer-list {
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.customer-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
padding: 16rpx 0;
|
||||
border-bottom: 2rpx solid var(--color-gray-1);
|
||||
}
|
||||
|
||||
.customer-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.customer-avatar {
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
border-radius: 16rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #ffffff;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.customer-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.customer-name {
|
||||
display: block;
|
||||
font-size: var(--font-sm);
|
||||
font-weight: 500;
|
||||
color: var(--color-gray-13);
|
||||
}
|
||||
|
||||
.customer-detail {
|
||||
display: block;
|
||||
font-size: var(--font-xs);
|
||||
color: var(--color-gray-6);
|
||||
margin-top: 4rpx;
|
||||
}
|
||||
|
||||
.toggle-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 12rpx 0;
|
||||
font-size: var(--font-sm);
|
||||
color: var(--color-gray-7);
|
||||
}
|
||||
Reference in New Issue
Block a user