|
@@ -1,5 +1,5 @@
|
|
|
<template>
|
|
<template>
|
|
|
- <scroll-view class="container" scroll-y>
|
|
|
|
|
|
|
+ <scroll-view class="container" scroll-y scroll-with-animation>
|
|
|
<!-- 邀请码区域 -->
|
|
<!-- 邀请码区域 -->
|
|
|
<view class="invite-card">
|
|
<view class="invite-card">
|
|
|
<view class="code-section">
|
|
<view class="code-section">
|
|
@@ -13,6 +13,103 @@
|
|
|
<button class="share-btn" @click="shareCard">分享邀请卡</button>
|
|
<button class="share-btn" @click="shareCard">分享邀请卡</button>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
|
|
+ <!-- 家庭公共收益总览 -->
|
|
|
|
|
+ <view class="family-earnings-card" v-if="familySummary">
|
|
|
|
|
+ <view class="fe-header">
|
|
|
|
|
+ <view class="fe-title-row">
|
|
|
|
|
+ <text class="fe-title">🏠 家庭公共收益</text>
|
|
|
|
|
+ <text class="fe-badge" v-if="isAdmin">管理员</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="fe-subtitle">家庭成员共同努力的成果</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="fe-grid">
|
|
|
|
|
+ <view class="fe-item">
|
|
|
|
|
+ <text class="fe-value orange">{{ fenToYuan(familySummary.totalEarned) }}</text>
|
|
|
|
|
+ <text class="fe-label">累计推荐收入</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="fe-item">
|
|
|
|
|
+ <text class="fe-value blue">{{ fenToYuan(familySummary.availableAmount) }}</text>
|
|
|
|
|
+ <text class="fe-label">可支配余额</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="fe-item">
|
|
|
|
|
+ <text class="fe-value green">{{ fenToYuan(familySummary.withdrawnAmount) }}</text>
|
|
|
|
|
+ <text class="fe-label">已提现</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="fe-item">
|
|
|
|
|
+ <text class="fe-value purple">{{ fenToYuan(familySummary.distributedAmount) }}</text>
|
|
|
|
|
+ <text class="fe-label">已分配</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 管理员操作按钮(仅管理员可见) -->
|
|
|
|
|
+ <view class="fe-actions" v-if="isAdmin">
|
|
|
|
|
+ <button class="fe-btn fe-btn-withdraw" @click="showWithdrawSheet = true">提现</button>
|
|
|
|
|
+ <button class="fe-btn fe-btn-distribute" @click="showDistributeSheet = true">分配收益</button>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 成员贡献榜 -->
|
|
|
|
|
+ <view class="members-card" v-if="members && members.length > 0">
|
|
|
|
|
+ <view class="members-header">
|
|
|
|
|
+ <text class="members-title">👥 成员贡献榜</text>
|
|
|
|
|
+ <text class="members-toggle" @click="membersExpanded = !membersExpanded">
|
|
|
|
|
+ {{ membersExpanded ? '收起' : '展开全部(' + members.length + ')' }}
|
|
|
|
|
+ </text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="member-list">
|
|
|
|
|
+ <view class="member-item" v-for="(m, idx) in displayMembers" :key="m.userId">
|
|
|
|
|
+ <view class="member-rank">
|
|
|
|
|
+ <text class="rank-num" v-if="idx < 3 && !showAllRanks">🏅</text>
|
|
|
|
|
+ <text class="rank-num rank-plain" v-else>{{ idx + 1 }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <image v-if="m.avatar" class="member-avatar" :src="m.avatar" mode="aspectFill"></image>
|
|
|
|
|
+ <text v-else class="member-avatar-placeholder">{{ m.nickname ? m.nickname.charAt(0) : '?' }}</text>
|
|
|
|
|
+ <view class="member-info">
|
|
|
|
|
+ <text class="member-name">{{ m.nickname || '用户' }}</text>
|
|
|
|
|
+ <text class="member-role-tag" v-if="m.isAdmin">管理员</text>
|
|
|
|
|
+ <text class="member-balance-tag" v-if="m.canUseFamilyBalance">池可用</text>
|
|
|
|
|
+ <text class="member-balance-tag disabled-tag" v-else>池关闭</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <view class="member-amounts">
|
|
|
|
|
+ <text class="member-amount allocated">+{{ fenToYuan(m.allocatedAmount) }}</text>
|
|
|
|
|
+ <text class="member-amount consumed">-{{ fenToYuan(m.consumedAmount) }}</text>
|
|
|
|
|
+ <text class="member-amount available">={{ fenToYuan(m.availableAmount) }}</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <!-- 管理员可切换成员池权限 -->
|
|
|
|
|
+ <switch v-if="isAdmin && !m.isAdmin" class="member-switch" :checked="m.canUseFamilyBalance" @change="toggleMemberAccess(m)" color="#F97316"></switch>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 提现弹窗 -->
|
|
|
|
|
+ <view class="sheet-mask" v-if="showWithdrawSheet" @click="showWithdrawSheet = false">
|
|
|
|
|
+ <view class="sheet-content" @click.stop>
|
|
|
|
|
+ <text class="sheet-title">家庭收益提现</text>
|
|
|
|
|
+ <text class="sheet-hint">可提现余额: {{ fenToYuan(familySummary ? familySummary.availableAmount : 0) }}</text>
|
|
|
|
|
+ <input class="sheet-input" type="digit" v-model="withdrawAmount" placeholder="输入提现金额(分)" />
|
|
|
|
|
+ <view class="sheet-actions">
|
|
|
|
|
+ <button class="sheet-cancel" @click="showWithdrawSheet = false">取消</button>
|
|
|
|
|
+ <button class="sheet-confirm" @click="doWithdraw" :disabled="!withdrawAmount || withdrawAmount <= 0">确认提现</button>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 分配弹窗 -->
|
|
|
|
|
+ <view class="sheet-mask" v-if="showDistributeSheet" @click="showDistributeSheet = false">
|
|
|
|
|
+ <view class="sheet-content" @click.stop>
|
|
|
|
|
+ <text class="sheet-title">分配收益</text>
|
|
|
|
|
+ <text class="sheet-hint">选择成员并输入分配金额(分)</text>
|
|
|
|
|
+ <picker class="sheet-picker" mode="selector" :range="memberOptions" :value="distributeMemberIdx" @change="onDistributeMemberChange">
|
|
|
|
|
+ <text>{{ distributeMemberIdx >= 0 ? memberOptions[distributeMemberIdx] : '选择成员' }}</text>
|
|
|
|
|
+ </picker>
|
|
|
|
|
+ <input class="sheet-input" type="digit" v-model="distributeAmount" placeholder="输入分配金额(分)" />
|
|
|
|
|
+ <view class="sheet-actions">
|
|
|
|
|
+ <button class="sheet-cancel" @click="showDistributeSheet = false">取消</button>
|
|
|
|
|
+ <button class="sheet-confirm" @click="doDistribute" :disabled="distributeMemberIdx < 0 || !distributeAmount || distributeAmount <= 0">确认分配</button>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ </view>
|
|
|
|
|
+
|
|
|
<!-- 统计卡片 -->
|
|
<!-- 统计卡片 -->
|
|
|
<view class="stats-cards">
|
|
<view class="stats-cards">
|
|
|
<view class="stat-card today-card">
|
|
<view class="stat-card today-card">
|
|
@@ -33,15 +130,14 @@
|
|
|
<view class="funnel-section" v-if="funnelSteps && funnelSteps.length > 0">
|
|
<view class="funnel-section" v-if="funnelSteps && funnelSteps.length > 0">
|
|
|
<text class="section-title">转化漏斗</text>
|
|
<text class="section-title">转化漏斗</text>
|
|
|
<view class="funnel">
|
|
<view class="funnel">
|
|
|
- <view class="funnel-step" v-for="(step, index) in funnelSteps" :key="index"
|
|
|
|
|
- :style="{width: step.width + '%'}">
|
|
|
|
|
|
|
+ <view class="funnel-step" v-for="(step, index) in funnelSteps" :key="index" :style="{width: step.width + '%'}">
|
|
|
<text class="funnel-label">{{ step.label }}</text>
|
|
<text class="funnel-label">{{ step.label }}</text>
|
|
|
<text class="funnel-count">{{ step.count }}</text>
|
|
<text class="funnel-count">{{ step.count }}</text>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
- <!-- 收益概览 -->
|
|
|
|
|
|
|
+ <!-- 收益总览 -->
|
|
|
<view class="earnings-card">
|
|
<view class="earnings-card">
|
|
|
<view class="earnings-header">
|
|
<view class="earnings-header">
|
|
|
<text class="earnings-title">收益总览</text>
|
|
<text class="earnings-title">收益总览</text>
|
|
@@ -75,7 +171,7 @@
|
|
|
</view>
|
|
</view>
|
|
|
<text class="menu-text">佣金明细</text>
|
|
<text class="menu-text">佣金明细</text>
|
|
|
</view>
|
|
</view>
|
|
|
- <view class="menu-item" @click="goWithdraw">
|
|
|
|
|
|
|
+ <view class="menu-item" @click="goWithdraw" v-if="!isChild">
|
|
|
<view class="menu-icon-wrap icon-withdraw">
|
|
<view class="menu-icon-wrap icon-withdraw">
|
|
|
<text class="menu-icon-text">💰</text>
|
|
<text class="menu-icon-text">💰</text>
|
|
|
</view>
|
|
</view>
|
|
@@ -99,15 +195,23 @@
|
|
|
</view>
|
|
</view>
|
|
|
<text class="menu-text">推广排行榜</text>
|
|
<text class="menu-text">推广排行榜</text>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
+ <view class="menu-item" @click="goRecords" v-if="isAdmin">
|
|
|
|
|
+ <view class="menu-icon-wrap icon-records">
|
|
|
|
|
+ <text class="menu-icon-text">📊</text>
|
|
|
|
|
+ </view>
|
|
|
|
|
+ <text class="menu-text">家庭流水</text>
|
|
|
|
|
+ </view>
|
|
|
</view>
|
|
</view>
|
|
|
|
|
|
|
|
- <SharePoster :show="showPoster" :referralCode="referralCode" :qrCodeBase64="qrCodeBase64" :nickname="userNickname" :userAvatar="userAvatar" @close="showPoster = false" />
|
|
|
|
|
|
|
+ <!-- 底部安全区 -->
|
|
|
|
|
+ <view style="height:40rpx"></view>
|
|
|
|
|
|
|
|
|
|
+ <SharePoster :show="showPoster" :referralCode="referralCode" :qrCodeBase64="qrCodeBase64" :nickname="userNickname" :userAvatar="userAvatar" @close="showPoster = false" />
|
|
|
</scroll-view>
|
|
</scroll-view>
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
<script>
|
|
|
-import { getReferralCode, getReferralSummary, getCommissionSummary, getInviteQrCode } from '../../utils/api.js'
|
|
|
|
|
|
|
+import { getReferralCode, getReferralSummary, getCommissionSummary, getInviteQrCode, getFamilyEarningsSummary, getFamilyEarningsMembers, getFamilyEarningsRecords, distributeToMember, toggleMemberBalance, withdrawFamilyEarnings } from '../../utils/api.js'
|
|
|
import SharePoster from '@/components/SharePoster.vue'
|
|
import SharePoster from '@/components/SharePoster.vue'
|
|
|
|
|
|
|
|
export default {
|
|
export default {
|
|
@@ -124,12 +228,41 @@ export default {
|
|
|
userNickname: '',
|
|
userNickname: '',
|
|
|
stats: {},
|
|
stats: {},
|
|
|
funnelData: {},
|
|
funnelData: {},
|
|
|
- funnelSteps: []
|
|
|
|
|
|
|
+ funnelSteps: [],
|
|
|
|
|
+ // 家庭收益
|
|
|
|
|
+ familySummary: null,
|
|
|
|
|
+ members: [],
|
|
|
|
|
+ membersExpanded: false,
|
|
|
|
|
+ showAllRanks: false,
|
|
|
|
|
+ // 弹窗
|
|
|
|
|
+ showWithdrawSheet: false,
|
|
|
|
|
+ showDistributeSheet: false,
|
|
|
|
|
+ withdrawAmount: '',
|
|
|
|
|
+ distributeAmount: '',
|
|
|
|
|
+ distributeMemberIdx: -1,
|
|
|
|
|
+ memberOptions: []
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
computed: {
|
|
computed: {
|
|
|
isLoggedIn() {
|
|
isLoggedIn() {
|
|
|
return !!uni.getStorageSync('token')
|
|
return !!uni.getStorageSync('token')
|
|
|
|
|
+ },
|
|
|
|
|
+ role() {
|
|
|
|
|
+ return uni.getStorageSync('role') || ''
|
|
|
|
|
+ },
|
|
|
|
|
+ isAdmin() {
|
|
|
|
|
+ // 管理员 = parent 或 teacher 角色
|
|
|
|
|
+ var r = this.role
|
|
|
|
|
+ return r === 'parent' || r === 'teacher'
|
|
|
|
|
+ },
|
|
|
|
|
+ isChild() {
|
|
|
|
|
+ return this.role === 'child'
|
|
|
|
|
+ },
|
|
|
|
|
+ displayMembers() {
|
|
|
|
|
+ if (this.membersExpanded || this.showAllRanks) {
|
|
|
|
|
+ return this.members
|
|
|
|
|
+ }
|
|
|
|
|
+ return this.members.slice(0, 5)
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
onLoad() {
|
|
onLoad() {
|
|
@@ -138,6 +271,7 @@ export default {
|
|
|
onShow() {
|
|
onShow() {
|
|
|
this.loadStats()
|
|
this.loadStats()
|
|
|
this.loadFunnelData()
|
|
this.loadFunnelData()
|
|
|
|
|
+ this.loadFamilyData()
|
|
|
},
|
|
},
|
|
|
onShareAppMessage() {
|
|
onShareAppMessage() {
|
|
|
var code = this.referralCode || ''
|
|
var code = this.referralCode || ''
|
|
@@ -154,7 +288,7 @@ export default {
|
|
|
methods: {
|
|
methods: {
|
|
|
async loadData() {
|
|
async loadData() {
|
|
|
try {
|
|
try {
|
|
|
- const codeRes = await getReferralCode()
|
|
|
|
|
|
|
+ var codeRes = await getReferralCode()
|
|
|
if (codeRes.data) {
|
|
if (codeRes.data) {
|
|
|
this.referralCode = codeRes.data.referralCode || codeRes.data.code || ''
|
|
this.referralCode = codeRes.data.referralCode || codeRes.data.code || ''
|
|
|
}
|
|
}
|
|
@@ -162,7 +296,7 @@ export default {
|
|
|
console.error('获取邀请码失败', e)
|
|
console.error('获取邀请码失败', e)
|
|
|
}
|
|
}
|
|
|
try {
|
|
try {
|
|
|
- const summaryRes = await getReferralSummary()
|
|
|
|
|
|
|
+ var summaryRes = await getReferralSummary()
|
|
|
if (summaryRes.data) {
|
|
if (summaryRes.data) {
|
|
|
this.totalEarnings = summaryRes.data.totalEarnings || '0.00'
|
|
this.totalEarnings = summaryRes.data.totalEarnings || '0.00'
|
|
|
}
|
|
}
|
|
@@ -170,7 +304,7 @@ export default {
|
|
|
console.error('获取邀请统计失败', e)
|
|
console.error('获取邀请统计失败', e)
|
|
|
}
|
|
}
|
|
|
try {
|
|
try {
|
|
|
- const comRes = await getCommissionSummary()
|
|
|
|
|
|
|
+ var comRes = await getCommissionSummary()
|
|
|
if (comRes.data) {
|
|
if (comRes.data) {
|
|
|
this.summary = comRes.data
|
|
this.summary = comRes.data
|
|
|
this.availableAmount = comRes.data.availableAmount || '0.00'
|
|
this.availableAmount = comRes.data.availableAmount || '0.00'
|
|
@@ -179,7 +313,38 @@ export default {
|
|
|
console.error('获取佣金总览失败', e)
|
|
console.error('获取佣金总览失败', e)
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
- loadStats: function() {
|
|
|
|
|
|
|
+ async loadFamilyData() {
|
|
|
|
|
+ if (this.isChild) {
|
|
|
|
|
+ // 孩子只读:仅加载概要,不加载管理员功能
|
|
|
|
|
+ try {
|
|
|
|
|
+ var sRes = await getFamilyEarningsSummary()
|
|
|
|
|
+ if (sRes.data) {
|
|
|
|
|
+ this.familySummary = sRes.data
|
|
|
|
|
+ this.members = sRes.data.members || []
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('获取家庭收益概览失败', e)
|
|
|
|
|
+ }
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ var sRes = await getFamilyEarningsSummary()
|
|
|
|
|
+ if (sRes.data) {
|
|
|
|
|
+ this.familySummary = sRes.data
|
|
|
|
|
+ this.members = sRes.data.members || []
|
|
|
|
|
+ // 构建picker选项
|
|
|
|
|
+ var opts = []
|
|
|
|
|
+ var arr = this.members
|
|
|
|
|
+ for (var i = 0; i < arr.length; i++) {
|
|
|
|
|
+ opts.push((arr[i].nickname || '用户' + arr[i].userId) + ' (余额:' + this.fenToYuan(arr[i].availableAmount) + ')')
|
|
|
|
|
+ }
|
|
|
|
|
+ this.memberOptions = opts
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.error('获取家庭收益概览失败', e)
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ loadStats() {
|
|
|
var self = this
|
|
var self = this
|
|
|
var token = uni.getStorageSync('token')
|
|
var token = uni.getStorageSync('token')
|
|
|
var baseUrl = ''
|
|
var baseUrl = ''
|
|
@@ -200,7 +365,7 @@ export default {
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
|
- loadFunnelData: function() {
|
|
|
|
|
|
|
+ loadFunnelData() {
|
|
|
var self = this
|
|
var self = this
|
|
|
var token = uni.getStorageSync('token')
|
|
var token = uni.getStorageSync('token')
|
|
|
var baseUrl = ''
|
|
var baseUrl = ''
|
|
@@ -222,7 +387,7 @@ export default {
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
},
|
|
},
|
|
|
- buildFunnelSteps: function() {
|
|
|
|
|
|
|
+ buildFunnelSteps() {
|
|
|
var data = this.funnelData
|
|
var data = this.funnelData
|
|
|
var max = Math.max(data.invites || 1, data.registered || 0, data.purchased || 0, data.repeatPurchased || 0, data.totalOrders || 0)
|
|
var max = Math.max(data.invites || 1, data.registered || 0, data.purchased || 0, data.repeatPurchased || 0, data.totalOrders || 0)
|
|
|
if (max < 1) max = 1
|
|
if (max < 1) max = 1
|
|
@@ -234,6 +399,95 @@ export default {
|
|
|
{ label: '订单', count: data.totalOrders || 0, width: Math.round(((data.totalOrders || 0) / max) * 100) }
|
|
{ label: '订单', count: data.totalOrders || 0, width: Math.round(((data.totalOrders || 0) / max) * 100) }
|
|
|
]
|
|
]
|
|
|
},
|
|
},
|
|
|
|
|
+ fenToYuan(fen) {
|
|
|
|
|
+ if (fen === null || fen === undefined) return '0.00'
|
|
|
|
|
+ var num = Number(fen)
|
|
|
|
|
+ if (isNaN(num)) return '0.00'
|
|
|
|
|
+ return (num / 100).toFixed(2)
|
|
|
|
|
+ },
|
|
|
|
|
+ formatPriceWithSymbol(val) {
|
|
|
|
|
+ if (!val && val !== 0) return '¥0.00'
|
|
|
|
|
+ var num = Number(val)
|
|
|
|
|
+ if (isNaN(num)) return '¥0.00'
|
|
|
|
|
+ // val 已经是元单位(后端返回的 commission summary 是元)
|
|
|
|
|
+ return '¥' + Number(num).toFixed(2)
|
|
|
|
|
+ },
|
|
|
|
|
+ // 管理员操作
|
|
|
|
|
+ toggleMemberAccess(m) {
|
|
|
|
|
+ var self = this
|
|
|
|
|
+ var enabled = !m.canUseFamilyBalance
|
|
|
|
|
+ uni.showLoading({ title: '操作中...' })
|
|
|
|
|
+ toggleMemberBalance({ userId: m.userId, enabled: enabled }).then(function(res) {
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
|
+ m.canUseFamilyBalance = enabled
|
|
|
|
|
+ uni.showToast({ title: '操作成功', icon: 'success' })
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.showToast({ title: res.message || '操作失败', icon: 'none' })
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(function(e) {
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+ uni.showToast({ title: '操作失败', icon: 'none' })
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ onDistributeMemberChange(e) {
|
|
|
|
|
+ this.distributeMemberIdx = e.detail.value
|
|
|
|
|
+ },
|
|
|
|
|
+ doDistribute() {
|
|
|
|
|
+ var idx = this.distributeMemberIdx
|
|
|
|
|
+ if (idx < 0 || !this.members[idx]) {
|
|
|
|
|
+ uni.showToast({ title: '请选择成员', icon: 'none' })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ var amount = Number(this.distributeAmount)
|
|
|
|
|
+ if (!amount || amount <= 0) {
|
|
|
|
|
+ uni.showToast({ title: '请输入有效金额', icon: 'none' })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ var self = this
|
|
|
|
|
+ uni.showLoading({ title: '分配中...' })
|
|
|
|
|
+ distributeToMember({ userId: this.members[idx].userId, amount: amount }).then(function(res) {
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
|
+ uni.showToast({ title: '分配成功', icon: 'success' })
|
|
|
|
|
+ self.showDistributeSheet = false
|
|
|
|
|
+ self.distributeAmount = ''
|
|
|
|
|
+ self.distributeMemberIdx = -1
|
|
|
|
|
+ self.loadFamilyData()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.showToast({ title: res.message || '分配失败', icon: 'none' })
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(function(e) {
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+ uni.showToast({ title: '分配失败', icon: 'none' })
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ doWithdraw() {
|
|
|
|
|
+ var amount = Number(this.withdrawAmount)
|
|
|
|
|
+ if (!amount || amount <= 0) {
|
|
|
|
|
+ uni.showToast({ title: '请输入有效金额', icon: 'none' })
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ var self = this
|
|
|
|
|
+ uni.showLoading({ title: '提现中...' })
|
|
|
|
|
+ withdrawFamilyEarnings({ amount: amount }).then(function(res) {
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
|
+ uni.showToast({ title: '提现申请已提交', icon: 'success' })
|
|
|
|
|
+ self.showWithdrawSheet = false
|
|
|
|
|
+ self.withdrawAmount = ''
|
|
|
|
|
+ self.loadFamilyData()
|
|
|
|
|
+ } else {
|
|
|
|
|
+ uni.showToast({ title: res.message || '提现失败', icon: 'none' })
|
|
|
|
|
+ }
|
|
|
|
|
+ }).catch(function(e) {
|
|
|
|
|
+ uni.hideLoading()
|
|
|
|
|
+ uni.showToast({ title: '提现失败', icon: 'none' })
|
|
|
|
|
+ })
|
|
|
|
|
+ },
|
|
|
|
|
+ goRecords() {
|
|
|
|
|
+ uni.navigateTo({ url: '/pages/promotion/records' })
|
|
|
|
|
+ },
|
|
|
copyCode() {
|
|
copyCode() {
|
|
|
if (!this.referralCode) return
|
|
if (!this.referralCode) return
|
|
|
uni.setClipboardData({
|
|
uni.setClipboardData({
|
|
@@ -331,6 +585,300 @@ export default {
|
|
|
.share-btn::after { border: none; }
|
|
.share-btn::after { border: none; }
|
|
|
.share-btn:active { opacity: 0.8; }
|
|
.share-btn:active { opacity: 0.8; }
|
|
|
|
|
|
|
|
|
|
+/* ===== 家庭公共收益卡 ===== */
|
|
|
|
|
+.family-earnings-card {
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border-radius: 20rpx;
|
|
|
|
|
+ padding: 30rpx;
|
|
|
|
|
+ margin-bottom: 30rpx;
|
|
|
|
|
+ box-shadow: 0 2rpx 12rpx rgba(249,115,22,0.08);
|
|
|
|
|
+ border-left: 6rpx solid #F97316;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-header {
|
|
|
|
|
+ margin-bottom: 24rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-title-row {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-title {
|
|
|
|
|
+ font-size: 30rpx;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #1E293B;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-badge {
|
|
|
|
|
+ font-size: 20rpx;
|
|
|
|
|
+ color: #F97316;
|
|
|
|
|
+ background: #FFF7ED;
|
|
|
|
|
+ padding: 4rpx 14rpx;
|
|
|
|
|
+ border-radius: 20rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-subtitle {
|
|
|
|
|
+ font-size: 22rpx;
|
|
|
|
|
+ color: #94A3B8;
|
|
|
|
|
+ margin-top: 6rpx;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-grid {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ margin-bottom: 20rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-item {
|
|
|
|
|
+ width: 50%;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ padding: 16rpx 0;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-value {
|
|
|
|
|
+ font-size: 36rpx;
|
|
|
|
|
+ font-weight: bold;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-value.orange { color: #F97316; }
|
|
|
|
|
+.fe-value.blue { color: #0EA5E9; }
|
|
|
|
|
+.fe-value.green { color: #10B981; }
|
|
|
|
|
+.fe-value.purple { color: #8B5CF6; }
|
|
|
|
|
+.fe-label {
|
|
|
|
|
+ font-size: 22rpx;
|
|
|
|
|
+ color: #94A3B8;
|
|
|
|
|
+ margin-top: 6rpx;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-actions {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 20rpx;
|
|
|
|
|
+ padding-top: 16rpx;
|
|
|
|
|
+ border-top: 1rpx solid #FED7AA;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-btn {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 64rpx;
|
|
|
|
|
+ line-height: 64rpx;
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ border-radius: 32rpx;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-btn::after { border: none; }
|
|
|
|
|
+.fe-btn-withdraw {
|
|
|
|
|
+ background: #F97316;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+}
|
|
|
|
|
+.fe-btn-distribute {
|
|
|
|
|
+ background: #FFF7ED;
|
|
|
|
|
+ color: #F97316;
|
|
|
|
|
+ border: 1rpx solid #FED7AA;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ===== 成员贡献榜 ===== */
|
|
|
|
|
+.members-card {
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border-radius: 20rpx;
|
|
|
|
|
+ padding: 30rpx;
|
|
|
|
|
+ margin-bottom: 30rpx;
|
|
|
|
|
+ box-shadow: 0 2rpx 12rpx rgba(249,115,22,0.08);
|
|
|
|
|
+}
|
|
|
|
|
+.members-header {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ margin-bottom: 20rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.members-title {
|
|
|
|
|
+ font-size: 30rpx;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #1E293B;
|
|
|
|
|
+}
|
|
|
|
|
+.members-toggle {
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #F97316;
|
|
|
|
|
+}
|
|
|
|
|
+.member-list {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+}
|
|
|
|
|
+.member-item {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ padding: 16rpx 0;
|
|
|
|
|
+ border-bottom: 1rpx solid #FFF7ED;
|
|
|
|
|
+}
|
|
|
|
|
+.member-item:last-child {
|
|
|
|
|
+ border-bottom: none;
|
|
|
|
|
+}
|
|
|
|
|
+.member-rank {
|
|
|
|
|
+ width: 48rpx;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+}
|
|
|
|
|
+.rank-num {
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.rank-plain {
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #94A3B8;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+}
|
|
|
|
|
+.member-avatar {
|
|
|
|
|
+ width: 56rpx;
|
|
|
|
|
+ height: 56rpx;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ margin-right: 16rpx;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ background: #FEF3C7;
|
|
|
|
|
+}
|
|
|
|
|
+.member-avatar-placeholder {
|
|
|
|
|
+ width: 56rpx;
|
|
|
|
|
+ height: 56rpx;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ margin-right: 16rpx;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ background: #FEF3C7;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #F97316;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ line-height: 56rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.member-info {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 8rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.member-name {
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: #1E293B;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ max-width: 140rpx;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+}
|
|
|
|
|
+.member-role-tag {
|
|
|
|
|
+ font-size: 18rpx;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ background: #F97316;
|
|
|
|
|
+ padding: 2rpx 10rpx;
|
|
|
|
|
+ border-radius: 12rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.member-balance-tag {
|
|
|
|
|
+ font-size: 18rpx;
|
|
|
|
|
+ color: #10B981;
|
|
|
|
|
+ background: #D1FAE5;
|
|
|
|
|
+ padding: 2rpx 10rpx;
|
|
|
|
|
+ border-radius: 12rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.member-balance-tag.disabled-tag {
|
|
|
|
|
+ color: #94A3B8;
|
|
|
|
|
+ background: #F1F5F9;
|
|
|
|
|
+}
|
|
|
|
|
+.member-amounts {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ align-items: flex-end;
|
|
|
|
|
+ margin-right: 12rpx;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+}
|
|
|
|
|
+.member-amount {
|
|
|
|
|
+ font-size: 20rpx;
|
|
|
|
|
+ line-height: 1.6;
|
|
|
|
|
+}
|
|
|
|
|
+.member-amount.allocated { color: #10B981; }
|
|
|
|
|
+.member-amount.consumed { color: #EF4444; }
|
|
|
|
|
+.member-amount.available { color: #F97316; font-weight: 600; }
|
|
|
|
|
+.member-switch {
|
|
|
|
|
+ transform: scale(0.7);
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/* ===== 弹窗 ===== */
|
|
|
|
|
+.sheet-mask {
|
|
|
|
|
+ position: fixed;
|
|
|
|
|
+ top: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ right: 0;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ background: rgba(0,0,0,0.4);
|
|
|
|
|
+ z-index: 999;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: flex-end;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+}
|
|
|
|
|
+.sheet-content {
|
|
|
|
|
+ background: #fff;
|
|
|
|
|
+ border-radius: 30rpx 30rpx 0 0;
|
|
|
|
|
+ padding: 40rpx 32rpx;
|
|
|
|
|
+ padding-bottom: calc(40rpx + env(safe-area-inset-bottom));
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ max-width: 750rpx;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+}
|
|
|
|
|
+.sheet-title {
|
|
|
|
|
+ font-size: 32rpx;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ color: #1E293B;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ margin-bottom: 12rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.sheet-hint {
|
|
|
|
|
+ font-size: 24rpx;
|
|
|
|
|
+ color: #94A3B8;
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ margin-bottom: 24rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.sheet-input {
|
|
|
|
|
+ height: 80rpx;
|
|
|
|
|
+ border: 1rpx solid #FED7AA;
|
|
|
|
|
+ border-radius: 16rpx;
|
|
|
|
|
+ padding: 0 24rpx;
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ color: #1E293B;
|
|
|
|
|
+ margin-bottom: 24rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.sheet-picker {
|
|
|
|
|
+ height: 80rpx;
|
|
|
|
|
+ border: 1rpx solid #FED7AA;
|
|
|
|
|
+ border-radius: 16rpx;
|
|
|
|
|
+ padding: 0 24rpx;
|
|
|
|
|
+ font-size: 26rpx;
|
|
|
|
|
+ color: #1E293B;
|
|
|
|
|
+ margin-bottom: 24rpx;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+}
|
|
|
|
|
+.sheet-actions {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 20rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.sheet-cancel {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 72rpx;
|
|
|
|
|
+ line-height: 72rpx;
|
|
|
|
|
+ background: #F1F5F9;
|
|
|
|
|
+ color: #64748B;
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ border-radius: 36rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.sheet-cancel::after { border: none; }
|
|
|
|
|
+.sheet-confirm {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 72rpx;
|
|
|
|
|
+ line-height: 72rpx;
|
|
|
|
|
+ background: #F97316;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ font-size: 28rpx;
|
|
|
|
|
+ border-radius: 36rpx;
|
|
|
|
|
+}
|
|
|
|
|
+.sheet-confirm::after { border: none; }
|
|
|
|
|
+.sheet-confirm[disabled] {
|
|
|
|
|
+ opacity: 0.5;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/* ===== 统计卡片 ===== */
|
|
/* ===== 统计卡片 ===== */
|
|
|
.stats-cards {
|
|
.stats-cards {
|
|
|
display: flex;
|
|
display: flex;
|
|
@@ -460,7 +1008,7 @@ export default {
|
|
|
box-shadow: 0 2rpx 12rpx rgba(249,115,22,0.08);
|
|
box-shadow: 0 2rpx 12rpx rgba(249,115,22,0.08);
|
|
|
}
|
|
}
|
|
|
.menu-item {
|
|
.menu-item {
|
|
|
- width: 50%;
|
|
|
|
|
|
|
+ width: 33.33%;
|
|
|
display: flex;
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
align-items: center;
|
|
@@ -481,6 +1029,7 @@ export default {
|
|
|
.icon-invite { background: #D1FAE5; }
|
|
.icon-invite { background: #D1FAE5; }
|
|
|
.icon-team { background: #FCE7F3; }
|
|
.icon-team { background: #FCE7F3; }
|
|
|
.icon-leaderboard { background: #FFF3CD; }
|
|
.icon-leaderboard { background: #FFF3CD; }
|
|
|
|
|
+.icon-records { background: #EDE9FE; }
|
|
|
.menu-icon-text {
|
|
.menu-icon-text {
|
|
|
font-size: 36rpx;
|
|
font-size: 36rpx;
|
|
|
}
|
|
}
|