Files
CKB-mini-program/pages/channel/statistics.vue
2026-01-07 11:00:09 +08:00

2184 lines
50 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-container">
<!-- 顶部蓝色头部 -->
<view class="header-section">
<view class="header-content">
<view class="header-title-row">
<view class="header-title-group">
<text class="header-title">分销获客统计</text>
<text class="header-subtitle">实时数据 · 精准统计</text>
</view>
<view class="header-actions">
<view class="settings-btn" @click="openChangePasswordPopup">
<view class="settings-circle">
<uni-icons type="gear" size="20" color="#2563eb"></uni-icons>
</view>
<text class="settings-text">设置</text>
</view>
</view>
</view>
<view class="channel-row">
<view class="channel-left">
<text class="channel-label">渠道名称</text>
<text class="channel-name">{{ channelInfo.name || '--' }}</text>
</view>
<view class="channel-code-pill">
<text class="channel-code-label">分销编码</text>
<text class="channel-code-text">{{ channelInfo.code || '--' }}</text>
</view>
</view>
</view>
</view>
<!-- 统计卡片区域严格贴近视觉稿布局 -->
<view class="stats-section">
<!-- 顶部大卡片可提现金额 + 收益概览 -->
<view class="stats-main-card">
<!-- 当前可提现金额 -->
<view class="withdraw-header-row">
<view class="withdraw-title-wrap">
<view class="withdraw-icon-wrap">
<uni-icons type="wallet" size="18" color="#4f46e5"></uni-icons>
</view>
<text class="withdraw-label">当前可提现金额</text>
</view>
</view>
<view class="withdraw-amount-row">
<text class="withdraw-currency">¥</text>
<text class="withdraw-amount-text">
{{ (statistics.withdrawableAmount || 0).toFixed(2) }}
</text>
</view>
<view class="withdraw-button-row">
<button class="withdraw-button" :disabled="statisticsLoading" @click="handleWithdraw">
<uni-icons v-if="!statisticsLoading" type="arrow-up" size="20" color="#fff"></uni-icons>
<uni-icons v-else type="spinner-cycle" size="20" color="#fff"></uni-icons>
<text class="withdraw-btn-text">{{ statisticsLoading ? '处理中...' : '一键提现' }}</text>
</button>
</view>
<!-- 底部三栏收益概览 -->
<view class="revenue-divider"></view>
<view class="revenue-row">
<view class="revenue-item">
<text class="revenue-label">总收益</text>
<text class="revenue-value">¥{{ (statistics.totalRevenue || 0).toFixed(2) }}</text>
</view>
<view class="revenue-item">
<text class="revenue-label">待审核</text>
<text class="revenue-value pending">¥{{ (statistics.pendingReview || 0).toFixed(2) }}</text>
</view>
<view class="revenue-item">
<text class="revenue-label">已提现</text>
<text class="revenue-value">¥{{ (statistics.withdrawn || 0).toFixed(2) }}</text>
</view>
</view>
</view>
<!-- 下方两张小卡片总加好友数 / 总获客数 -->
<view class="acquisition-row">
<view class="acquisition-card">
<view class="acquisition-header-row">
<view class="acquisition-icon friends-icon">
<uni-icons type="plusempty" size="30" color="#4f46e5"></uni-icons>
</view>
<text class="acquisition-title-text">总加好友数</text>
</view>
<view class="acquisition-bottom-row">
<text class="acquisition-main-number">{{ statistics.totalFriends || 0 }}</text>
<text class="acquisition-main-sub">今日 {{ statistics.todayFriends || 0 }}</text>
</view>
<view class="acquisition-bg-circle friends-circle"></view>
</view>
<view class="acquisition-card">
<view class="acquisition-header-row">
<view class="acquisition-icon customer-icon">
<uni-icons type="person-filled" size="30" color="#a855f7"></uni-icons>
</view>
<text class="acquisition-title-text">总获客数</text>
</view>
<view class="acquisition-bottom-row">
<text class="acquisition-main-number">{{ statistics.totalCustomers || 0 }}</text>
<text class="acquisition-main-sub">今日 {{ statistics.todayCustomers || 0 }}</text>
</view>
<view class="acquisition-bg-circle customer-circle"></view>
</view>
</view>
</view>
<!-- 明细记录整体卡片 -->
<view class="records-section">
<view class="records-header">
<uni-icons type="list" size="20" color="#333"></uni-icons>
<text class="records-title">明细记录</text>
</view>
<!-- 标签页胶囊样式 -->
<view class="tabs-container">
<view class="tabs-pill">
<view
class="tab-item"
:class="{'active': currentTab === 'revenue'}"
@click="switchTab('revenue')"
>
收益明细
</view>
<view
class="tab-item"
:class="{'active': currentTab === 'withdraw'}"
@click="switchTab('withdraw')"
>
提现明细
</view>
</view>
</view>
<!-- 筛选条件卡片始终展开 -->
<view class="filter-section">
<view class="filter-card">
<view class="filter-header-row">
<view class="filter-header-left">
<uni-icons type="spinner" size="18" color="#6b7280"></uni-icons>
<text class="filter-title">筛选条件</text>
</view>
<!-- 预留图标位可去掉展开/收起逻辑 -->
<uni-icons type="arrowdown" size="16" color="#d1d5db"></uni-icons>
</view>
<view class="filter-content">
<!-- 收益明细类型 + 时间 -->
<template v-if="currentTab === 'revenue'">
<view class="filter-item">
<text class="filter-label">类型</text>
<picker mode="selector" :range="typeOptions" :value="selectedTypeIndex" @change="onTypeChange">
<view class="filter-picker">
<text>{{ typeOptions[selectedTypeIndex] }}</text>
<uni-icons type="arrowdown" size="14" color="#9ca3af"></uni-icons>
</view>
</picker>
</view>
<view class="filter-item">
<text class="filter-label">时间</text>
<picker mode="date" :value="selectedDate" @change="onDateChange">
<view class="filter-picker">
<text>{{ selectedDate || '选择日期' }}</text>
<uni-icons type="calendar" size="14" color="#9ca3af"></uni-icons>
</view>
</picker>
</view>
</template>
<!-- 提现明细状态 + 到账方式 -->
<template v-else>
<view class="filter-item">
<text class="filter-label">状态</text>
<picker mode="selector" :range="statusOptions" :value="selectedStatusIndex" @change="onStatusChange">
<view class="filter-picker">
<text>{{ statusOptions[selectedStatusIndex] }}</text>
<uni-icons type="arrowdown" size="14" color="#9ca3af"></uni-icons>
</view>
</picker>
</view>
<view class="filter-item">
<text class="filter-label">到账方式</text>
<picker mode="selector" :range="payTypeOptions" :value="selectedPayTypeIndex" @change="onPayTypeChange">
<view class="filter-picker">
<text>{{ payTypeOptions[selectedPayTypeIndex] }}</text>
<uni-icons type="arrowdown" size="14" color="#9ca3af"></uni-icons>
</view>
</picker>
</view>
</template>
</view>
</view>
</view>
<!-- 记录列表 -->
<view class="records-list">
<view class="records-count">
<text>{{ totalRecords }}条记录</text>
<view class="records-count-pill">
<text class="current-count">
{{ Math.min(currentPage * pageSize, totalRecords) }} / {{ totalRecords }}
</text>
</view>
</view>
<!-- 加载中状态 -->
<view v-if="loading && recordsList.length === 0" class="loading-state">
<uni-icons type="spinner-cycle" size="40" color="#6366f1"></uni-icons>
<text class="loading-text">加载中...</text>
</view>
<!-- 空状态 -->
<view v-else-if="recordsList.length === 0 && !loading" class="empty-state">
<uni-icons type="info" size="40" color="#ccc"></uni-icons>
<text class="empty-text">暂无记录</text>
</view>
<!-- 记录列表 -->
<view v-else>
<!-- 收益明细样式 -->
<view v-if="currentTab === 'revenue'">
<view v-for="(item, index) in recordsList" :key="index" class="record-item">
<view class="record-main-row">
<view class="record-title-wrap">
<text class="record-name">{{ item.sourceType || '-' }}</text>
<view
class="record-badge"
:class="{'badge-acquisition': item.type === 'acquisition', 'badge-friend': item.type === 'friend'}"
>
{{ item.typeLabel || '' }}
</view>
</view>
<text class="record-amount" :class="{'amount-positive': item.amount > 0}">
{{ item.amount > 0 ? '+' : '' }}¥{{ item.amount.toFixed(2) }}
</text>
</view>
<view class="record-meta-row">
<view class="record-time-wrap">
<uni-icons type="time" size="16" color="#9ca3af"></uni-icons>
<text class="record-time">{{ item.createTime }}</text>
</view>
<text class="record-meta-type">收益</text>
</view>
<view v-if="item.remark" class="record-remark">
<text class="remark-label">备注</text>
<text class="remark-value">{{ item.remark }}</text>
</view>
</view>
</view>
<!-- 提现明细样式 -->
<view v-else>
<view v-for="(item, index) in recordsList" :key="index" class="record-item withdraw-record-item">
<view class="withdraw-main-row">
<view class="withdraw-main-left">
<text class="withdraw-title">
<text v-if="item.status === 'approved' && item.payTypeLabel">提现到 {{ item.payTypeLabel }}</text>
<text v-else>提现申请</text>
</text>
</view>
<text class="withdraw-amount">
¥{{ Number(item.amount || 0).toFixed(2) }}
</text>
</view>
<view class="withdraw-tags-row">
<view
class="withdraw-tag status-tag"
:class="'status-' + (item.status || '')"
>
{{ item.statusLabel || '状态未知' }}
</view>
<view v-if="item.payTypeLabel && item.status === 'approved'" class="withdraw-tag">
{{ item.payTypeLabel }}
</view>
<view v-if="item.reviewer" class="withdraw-tag">
审核{{ item.reviewer }}
</view>
</view>
<view class="withdraw-meta-row">
<view class="withdraw-meta-item">
<text class="meta-label">申请时间</text>
<text class="meta-value">{{ item.applyTime || '-' }}</text>
</view>
<view class="withdraw-meta-item">
<text class="meta-label">审核时间</text>
<text class="meta-value">{{ item.reviewTime || '-' }}</text>
</view>
</view>
<view v-if="item.remark" class="withdraw-remark">
<text class="meta-label">备注</text>
<text class="meta-value">{{ item.remark }}</text>
</view>
</view>
</view>
<!-- 加载更多 -->
<view v-if="hasMore && recordsList.length > 0" class="load-more" @click="loadMore">
<text v-if="loading" class="load-more-text">加载中...</text>
<text v-else class="load-more-text">加载更多记录...</text>
</view>
<view v-else-if="!hasMore && recordsList.length > 0" class="load-more">
<text class="load-more-text no-more">没有更多了</text>
</view>
</view>
</view>
</view>
<!-- 修改密码弹框 -->
<uni-popup ref="changePasswordPopup" type="center" :mask-click="false">
<view class="password-popup">
<view class="password-popup-header">
<text class="password-popup-title">修改密码</text>
<text class="password-popup-subtitle">
请设置新密码建议使用字母数字组合长度不少于6位
</text>
</view>
<!-- 表单区域 -->
<view class="password-popup-form">
<view class="password-form-item">
<view class="password-form-label">
<uni-icons type="locked" size="16" color="#6366f1"></uni-icons>
<text class="label-text">原密码</text>
</view>
<view class="password-input-wrapper">
<input
class="password-input"
type="password"
v-model="passwordForm.oldPassword"
placeholder="请输入原密码"
placeholder-class="password-placeholder"
maxlength="50"
/>
</view>
</view>
<view class="password-form-item">
<view class="password-form-label">
<uni-icons type="locked" size="16" color="#6366f1"></uni-icons>
<text class="label-text">新密码</text>
</view>
<view class="password-input-wrapper">
<input
class="password-input"
type="password"
v-model="passwordForm.newPassword"
placeholder="请输入新密码至少6位"
placeholder-class="password-placeholder"
maxlength="50"
/>
</view>
</view>
<view class="password-form-item">
<view class="password-form-label">
<uni-icons type="locked" size="16" color="#6366f1"></uni-icons>
<text class="label-text">确认新密码</text>
</view>
<view class="password-input-wrapper">
<input
class="password-input"
type="password"
v-model="passwordForm.confirmPassword"
placeholder="请再次输入新密码"
placeholder-class="password-placeholder"
maxlength="50"
/>
</view>
</view>
</view>
<!-- 提示信息 -->
<view class="password-popup-info">
<view class="password-info-row">
<view class="password-info-dot"></view>
<text class="password-info-text">
密码长度至少6位建议使用字母数字组合
</text>
</view>
<view class="password-info-row">
<view class="password-info-dot"></view>
<text class="password-info-text">
修改密码后需要重新登录
</text>
</view>
</view>
<view class="password-popup-footer">
<button class="password-popup-btn cancel" @click="closeChangePasswordPopup">取消</button>
<button class="password-popup-btn confirm" @click="confirmChangePassword" :disabled="passwordLoading">
{{ passwordLoading ? '修改中...' : '确认修改' }}
</button>
</view>
</view>
</uni-popup>
<!-- 提现申请弹框 -->
<uni-popup ref="withdrawPopup" type="center" :mask-click="false">
<view class="withdraw-popup">
<view class="withdraw-popup-header">
<text class="withdraw-popup-title">提交提现申请</text>
<text class="withdraw-popup-subtitle">
将提交提现申请金额为可提现的全部余额可根据需要调整金额
</text>
</view>
<!-- 金额卡片 -->
<view class="withdraw-popup-card">
<view class="withdraw-popup-card-top">
<view class="withdraw-popup-card-left">
<text class="card-main-label">可提现余额</text>
<text class="card-sub-label" @click="setFullWithdraw">全部提现</text>
</view>
<view class="withdraw-popup-amount-wrap">
<text class="withdraw-popup-amount-currency"></text>
<input
class="withdraw-popup-amount-input"
type="digit"
v-model="withdrawFormAmount"
placeholder="0.00"
placeholder-class="withdraw-popup-placeholder"
/>
</view>
</view>
</view>
<!-- 提示信息 -->
<view class="withdraw-popup-info">
<view class="withdraw-info-row">
<view class="withdraw-info-dot"></view>
<text class="withdraw-info-text">
申请提现金额¥{{ Number(withdrawFormAmount || statistics.withdrawableAmount || 0).toFixed(2) }}
</text>
</view>
<view class="withdraw-info-row">
<view class="withdraw-info-dot"></view>
<text class="withdraw-info-text">
提现申请提交后等待管理员审核
</text>
</view>
<view class="withdraw-info-row">
<view class="withdraw-info-dot"></view>
<text class="withdraw-info-text">
审核通过后将尽快打款
</text>
</view>
</view>
<view class="withdraw-popup-footer">
<button class="withdraw-popup-btn cancel" @click="closeWithdrawPopup">取消</button>
<button class="withdraw-popup-btn confirm" @click="confirmWithdraw" :disabled="statisticsLoading">
{{ statisticsLoading ? '处理中...' : '提交申请' }}
</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import config from '@/config';
import uniPopup from '@/uni_modules/uni-popup/components/uni-popup/uni-popup.vue';
export default {
components: {
uniPopup
},
data() {
return {
token: '',
channelInfo: {
name: '',
code: ''
},
statistics: {
withdrawableAmount: 0,
totalRevenue: 0,
pendingReview: 0,
withdrawn: 0,
totalFriends: 0,
todayFriends: 0,
totalCustomers: 0,
todayCustomers: 0
},
currentTab: 'revenue', // revenue | withdraw
showFilter: false,
// 收益明细筛选
typeOptions: ['全部', '获客', '加好友'],
selectedTypeIndex: 0,
selectedDate: '',
// 提现明细筛选
statusOptions: ['全部', '审核中', '已通过', '已拒绝'],
selectedStatusIndex: 0,
payTypeOptions: ['全部', '微信', '支付宝', '银行卡'],
selectedPayTypeIndex: 0,
// 提现弹框
withdrawFormAmount: '',
// 修改密码弹框
passwordForm: {
oldPassword: '',
newPassword: '',
confirmPassword: ''
},
passwordLoading: false,
recordsList: [],
totalRecords: 0,
currentPage: 1,
pageSize: 10,
hasMore: true,
loading: false,
statisticsLoading: false
}
},
onLoad(options) {
// 令牌校验
this.token = uni.getStorageSync('channelToken');
if (!this.token) {
uni.showToast({ title: '请先登录', icon: 'none', duration: 2000 });
setTimeout(() => {
uni.redirectTo({ url: '/pages/channel/login' });
}, 1500);
return;
}
// 从本地存储或URL参数获取渠道信息
let storedCode = uni.getStorageSync('channelCode');
let storedName = uni.getStorageSync('channelName');
console.log('页面加载 - 从本地存储获取:', { storedCode, storedName });
// 如果单独保存的channelCode为空尝试从完整登录数据中恢复
if (!storedCode) {
try {
const loginDataStr = uni.getStorageSync('channelLoginData');
if (loginDataStr) {
const loginData = JSON.parse(loginDataStr);
console.log('从完整登录数据恢复:', loginData);
const channelInfo = loginData.channelInfo || {};
if (channelInfo.channelCode) {
storedCode = channelInfo.channelCode;
uni.setStorageSync('channelCode', storedCode);
console.log('从完整登录数据恢复channelCode:', storedCode);
}
if (channelInfo.channelName) {
storedName = channelInfo.channelName;
uni.setStorageSync('channelName', storedName);
console.log('从完整登录数据恢复channelName:', storedName);
}
}
} catch (e) {
console.error('解析完整登录数据失败:', e);
}
}
if (storedCode) {
this.channelInfo.code = storedCode;
} else if (options.code) {
this.channelInfo.code = options.code;
}
if (storedName) {
this.channelInfo.name = storedName;
} else if (options.name) {
this.channelInfo.name = decodeURIComponent(options.name);
}
console.log('页面加载 - 当前channelInfo:', this.channelInfo);
uni.setNavigationBarTitle({
title: '分销获客统计'
});
this.loadData();
},
onPullDownRefresh() {
this.refreshData();
},
methods: {
/**
* 统一的渠道API请求方法
* @param {Object} options - 请求配置
* @returns {Promise} 请求Promise
*/
channelRequest(options) {
return new Promise((resolve, reject) => {
// 检查token
if (!this.token) {
reject(new Error('未登录'));
return;
}
// 检查channelCode
if (options.needChannelCode && !this.channelInfo.code) {
const storedCode = uni.getStorageSync('channelCode');
if (storedCode) {
this.channelInfo.code = storedCode;
} else {
reject(new Error('缺少渠道编码'));
return;
}
}
uni.request({
method: options.method || 'GET',
url: config.apiUrl2 + options.url,
data: options.data || {},
header: {
'content-type': 'application/x-www-form-urlencoded',
Authorization: `Bearer ${this.token}`
},
success: (response) => {
// 统一处理响应
if (response.data.code === 10000 || response.data.code === 200) {
resolve(response.data);
} else {
// 处理业务错误
const errorMsg = response.data.message || response.data.msg || '请求失败';
// 如果是token失效跳转登录
if (response.data.code === 401 || response.data.code === 10030) {
uni.showToast({
title: '登录已过期,请重新登录',
icon: 'none',
duration: 2000
});
setTimeout(() => {
uni.redirectTo({ url: '/pages/channel/login' });
}, 1500);
reject(new Error('登录已过期'));
} else {
reject(new Error(errorMsg));
}
}
},
fail: (error) => {
console.error('请求失败:', error);
reject(error);
}
});
});
},
/**
* 统一错误处理
* @param {Error} error - 错误对象
* @param {String} defaultMsg - 默认错误消息
*/
handleError(error, defaultMsg = '操作失败,请重试') {
const errorMsg = error.message || error.errMsg || defaultMsg;
uni.showToast({
title: errorMsg,
icon: 'none',
duration: 2000
});
},
/**
* 获取渠道编码(带容错处理)
*/
getChannelCode() {
if (this.channelInfo.code) {
return this.channelInfo.code;
}
const storedCode = uni.getStorageSync('channelCode');
if (storedCode) {
this.channelInfo.code = storedCode;
return storedCode;
}
return null;
},
// 加载数据
async loadData() {
// 并行加载统计数据和记录列表
await Promise.all([
this.loadStatistics(),
this.loadRecords()
]);
},
// 加载统计数据
async loadStatistics() {
const channelCode = this.getChannelCode();
console.log('loadStatistics - 获取到的channelCode:', channelCode);
if (!channelCode) {
console.error('缺少channelCode无法加载统计数据');
// 尝试从本地存储重新获取
const storedCode = uni.getStorageSync('channelCode');
console.log('loadStatistics - 从本地存储重新获取:', storedCode);
if (storedCode) {
this.channelInfo.code = storedCode;
// 递归调用一次
return this.loadStatistics();
}
this.handleError(new Error('缺少渠道编码,请重新登录'), '无法加载统计数据');
uni.stopPullDownRefresh();
return;
}
this.statisticsLoading = true;
console.log('loadStatistics - 开始请求接口channelCode:', channelCode);
try {
const response = await this.channelRequest({
url: '/v1/frontend/distribution/user/home',
method: 'GET',
data: {
channelCode: channelCode
},
needChannelCode: false // 已经检查过了,不需要再次检查
});
const data = response.data || {};
const channelInfo = data.channelInfo || {};
const financialStats = data.financialStats || {};
const customerStats = data.customerStats || {};
console.log('loadStatistics - 接口返回数据:', {
data,
channelInfo,
financialStats,
customerStats
});
// 更新渠道信息 - 优先从channelInfo获取兼容直接返回在data中的情况
const updatedChannelCode = channelInfo.channelCode || data.code || this.channelInfo.code;
const updatedChannelName = channelInfo.channelName || data.name || this.channelInfo.name;
console.log('loadStatistics - 更新后的渠道信息:', { updatedChannelCode, updatedChannelName });
this.channelInfo = {
name: updatedChannelName,
code: updatedChannelCode
};
// 更新本地存储
if (updatedChannelCode) {
uni.setStorageSync('channelCode', updatedChannelCode);
console.log('loadStatistics - 已保存channelCode到本地存储:', updatedChannelCode);
}
if (updatedChannelName) {
uni.setStorageSync('channelName', updatedChannelName);
console.log('loadStatistics - 已保存channelName到本地存储:', updatedChannelName);
}
// 更新统计数据 - 从financialStats和customerStats中获取
// 兼容旧的数据结构直接返回在data中
this.statistics = {
withdrawableAmount: parseFloat(financialStats.withdrawableAmount || data.withdrawableAmount || 0),
totalRevenue: parseFloat(financialStats.totalRevenue || data.totalRevenue || 0),
pendingReview: parseFloat(financialStats.pendingReview || data.pendingReview || 0),
withdrawn: parseFloat(financialStats.withdrawn || data.withdrawn || 0),
totalFriends: parseInt(customerStats.totalFriends || data.totalFriends || 0),
todayFriends: parseInt(customerStats.todayFriends || data.todayFriends || 0),
totalCustomers: parseInt(customerStats.totalCustomers || data.totalCustomers || 0),
todayCustomers: parseInt(customerStats.todayCustomers || data.todayCustomers || 0)
};
console.log('loadStatistics - 更新后的统计数据:', this.statistics);
} catch (error) {
console.error('加载统计数据失败:', error);
this.handleError(error, '加载统计数据失败');
} finally {
this.statisticsLoading = false;
// 如果是在下拉刷新时且loadRecords还没完成这里不停止刷新
// 让loadRecords完成后统一停止
}
},
// 加载记录列表
async loadRecords() {
if (this.loading) return;
const channelCode = this.getChannelCode();
if (!channelCode) {
console.error('缺少channelCode');
return;
}
this.loading = true;
try {
// 根据当前标签页选择不同的接口与筛选参数
const url = this.currentTab === 'revenue'
? '/v1/frontend/distribution/user/revenue-records'
: '/v1/frontend/distribution/user/withdrawal-records';
const requestData = {
channelCode: channelCode,
page: this.currentPage,
limit: this.pageSize
};
if (this.currentTab === 'revenue') {
requestData.filterType = this.selectedTypeIndex === 0 ? '' : this.typeOptions[this.selectedTypeIndex];
requestData.date = this.selectedDate;
} else {
// 状态映射:全部 / 审核中 / 已通过 / 已拒绝
const statusMap = ['all', 'pending', 'approved', 'rejected'];
const payTypeMap = ['all', 'wechat', 'alipay','bankcard'];
requestData.status = statusMap[this.selectedStatusIndex] || '';
requestData.payType = payTypeMap[this.selectedPayTypeIndex] || '';
}
const response = await this.channelRequest({
url,
method: 'GET',
data: requestData,
needChannelCode: true
});
const data = response.data || {};
const list = data.list || data.records || [];
if (this.currentPage === 1) {
this.recordsList = list;
} else {
this.recordsList = [...this.recordsList, ...list];
}
this.totalRecords = data.total || 0;
this.hasMore = this.recordsList.length < this.totalRecords;
} catch (error) {
this.handleError(error, '加载记录失败');
} finally {
this.loading = false;
}
},
// 刷新数据
async refreshData() {
try {
// 重置状态
this.currentPage = 1;
this.hasMore = true;
this.recordsList = [];
this.loading = false;
this.statisticsLoading = false;
// 确保有channelCode
if (!this.channelInfo.code) {
const storedCode = uni.getStorageSync('channelCode');
if (storedCode) {
this.channelInfo.code = storedCode;
}
}
// 重新加载数据
await this.loadData();
} catch (error) {
console.error('刷新数据失败:', error);
} finally {
// 确保下拉刷新状态被停止
uni.stopPullDownRefresh();
}
},
// 切换标签页
switchTab(tab) {
if (this.currentTab === tab) return;
this.currentTab = tab;
this.currentPage = 1;
this.recordsList = [];
this.loadRecords();
},
// 切换筛选条件显示
toggleFilter() {
this.showFilter = !this.showFilter;
},
// 类型选择变化
onTypeChange(e) {
this.selectedTypeIndex = e.detail.value;
this.currentPage = 1;
this.recordsList = [];
this.loadRecords();
},
// 日期选择变化(收益明细)
onDateChange(e) {
this.selectedDate = e.detail.value;
this.currentPage = 1;
this.recordsList = [];
this.loadRecords();
},
// 状态选择变化(提现明细)
onStatusChange(e) {
this.selectedStatusIndex = e.detail.value;
this.currentPage = 1;
this.recordsList = [];
this.loadRecords();
},
// 到账方式选择变化(提现明细)
onPayTypeChange(e) {
this.selectedPayTypeIndex = e.detail.value;
this.currentPage = 1;
this.recordsList = [];
this.loadRecords();
},
// 加载更多
loadMore() {
if (this.hasMore && !this.loading) {
this.currentPage++;
this.loadRecords();
}
},
// 一键提现 - 打开弹框
handleWithdraw() {
if (this.statistics.withdrawableAmount <= 0) {
uni.showToast({
title: '暂无可提现金额',
icon: 'none',
duration: 2000
});
return;
}
this.withdrawFormAmount = (this.statistics.withdrawableAmount || 0).toFixed(2);
this.$refs.withdrawPopup && this.$refs.withdrawPopup.open();
},
// 设置为全部提现
setFullWithdraw() {
this.withdrawFormAmount = (this.statistics.withdrawableAmount || 0).toFixed(2);
},
// 关闭提现弹框
closeWithdrawPopup() {
this.$refs.withdrawPopup && this.$refs.withdrawPopup.close();
},
// 确认提现
async confirmWithdraw() {
const maxAmount = Number(this.statistics.withdrawableAmount || 0);
let amount = Number(this.withdrawFormAmount);
if (isNaN(amount) || amount <= 0) {
uni.showToast({
title: '请输入正确的提现金额',
icon: 'none',
duration: 2000
});
return;
}
if (amount > maxAmount) {
uni.showToast({
title: `最多可提现 ¥${maxAmount.toFixed(2)}`,
icon: 'none',
duration: 2000
});
return;
}
const channelCode = this.getChannelCode();
if (!channelCode) {
uni.showToast({
title: '缺少渠道编码',
icon: 'none',
duration: 2000
});
return;
}
try {
this.statisticsLoading = true;
await this.channelRequest({
url: '/v1/distribution/withdrawals',
method: 'POST',
data: {
channelCode,
amount
},
needChannelCode: true
});
uni.showToast({
title: '提现申请已提交',
icon: 'success',
duration: 2000
});
this.closeWithdrawPopup();
// 刷新统计与记录
setTimeout(() => {
this.refreshData();
}, 1200);
} catch (error) {
this.handleError(error, '提现失败,请重试');
} finally {
this.statisticsLoading = false;
}
},
// 打开修改密码弹框
openChangePasswordPopup() {
// 重置表单
this.passwordForm = {
oldPassword: '',
newPassword: '',
confirmPassword: ''
};
this.$refs.changePasswordPopup && this.$refs.changePasswordPopup.open();
},
// 关闭修改密码弹框
closeChangePasswordPopup() {
this.$refs.changePasswordPopup && this.$refs.changePasswordPopup.close();
// 清空表单
this.passwordForm = {
oldPassword: '',
newPassword: '',
confirmPassword: ''
};
},
// 验证密码表单
validatePasswordForm() {
if (!this.passwordForm.oldPassword || !this.passwordForm.oldPassword.trim()) {
uni.showToast({
title: '请输入原密码',
icon: 'none',
duration: 2000
});
return false;
}
if (!this.passwordForm.newPassword || !this.passwordForm.newPassword.trim()) {
uni.showToast({
title: '请输入新密码',
icon: 'none',
duration: 2000
});
return false;
}
if (this.passwordForm.newPassword.length < 6) {
uni.showToast({
title: '新密码长度至少6位',
icon: 'none',
duration: 2000
});
return false;
}
if (this.passwordForm.newPassword !== this.passwordForm.confirmPassword) {
uni.showToast({
title: '两次输入的新密码不一致',
icon: 'none',
duration: 2000
});
return false;
}
if (this.passwordForm.oldPassword === this.passwordForm.newPassword) {
uni.showToast({
title: '新密码不能与原密码相同',
icon: 'none',
duration: 2000
});
return false;
}
return true;
},
// 确认修改密码
async confirmChangePassword() {
if (this.passwordLoading) return;
if (!this.validatePasswordForm()) {
return;
}
const channelCode = this.getChannelCode();
if (!channelCode) {
uni.showToast({
title: '缺少渠道编码',
icon: 'none',
duration: 2000
});
return;
}
try {
this.passwordLoading = true;
// 准备请求参数
const requestData = {
channelCode: channelCode,
oldPassword: this.passwordForm.oldPassword.trim(),
newPassword: this.passwordForm.newPassword.trim()
};
console.log('修改密码请求参数:', {
url: '/v1/frontend/distribution/user/change-password',
data: {
...requestData,
oldPassword: '***', // 隐藏密码
newPassword: '***' // 隐藏密码
}
});
const response = await this.channelRequest({
url: '/v1/frontend/distribution/user/change-password',
method: 'POST',
data: requestData,
needChannelCode: true
});
console.log('修改密码接口响应:', response);
uni.showToast({
title: '密码修改成功',
icon: 'success',
duration: 2000
});
this.closeChangePasswordPopup();
// 提示重新登录
setTimeout(() => {
uni.showModal({
title: '提示',
content: '密码已修改,请重新登录',
showCancel: false,
confirmText: '确定',
success: (res) => {
if (res.confirm) {
// 获取companyId在清除之前获取
const companyId = uni.getStorageSync('channelCompanyId') || '';
// 清除登录信息
uni.removeStorageSync('channelToken');
uni.removeStorageSync('channelCode');
uni.removeStorageSync('channelName');
uni.removeStorageSync('channelLoginData');
// 注意不清除channelCompanyId因为退出登录时需要用到
// 跳转到登录页带上companyId
const loginUrl = companyId
? `/pages/channel/login?companyId=${companyId}`
: '/pages/channel/login';
uni.redirectTo({
url: loginUrl
});
}
}
});
}, 1500);
} catch (error) {
console.error('修改密码失败:', error);
this.handleError(error, '修改密码失败,请重试');
} finally {
this.passwordLoading = false;
}
}
}
}
</script>
<style lang="scss" scoped>
.page-container {
min-height: 100vh;
background-color: #f5f5f5;
}
/* 顶部蓝色头部 */
.header-section {
background: linear-gradient(135deg, #2563eb 0%, #1d4ed8 60%, #1e40af 100%);
padding: 56rpx 30rpx 120rpx;
color: #fff;
border-bottom-left-radius: 40rpx;
border-bottom-right-radius: 40rpx;
}
.header-content {
position: relative;
}
.header-title-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 40rpx;
}
.header-title-group {
flex: 1;
}
.header-title {
display: block;
font-size: 44rpx;
font-weight: 600;
margin-bottom: 12rpx;
}
.header-subtitle {
display: block;
font-size: 24rpx;
opacity: 0.9;
}
.header-actions {
display: flex;
align-items: center;
}
.settings-btn {
display: flex;
flex-direction: column;
align-items: center;
gap: 10rpx;
padding: 0;
}
.settings-text {
font-size: 22rpx;
color: #fff;
}
.settings-circle {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
background-color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 8rpx 20rpx rgba(15, 23, 42, 0.25);
}
.channel-info {
display: none;
}
.channel-row {
margin-top: 40rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.channel-left {
flex: 1;
}
.channel-label {
font-size: 24rpx;
opacity: 0.85;
}
.channel-name {
display: block;
margin-top: 8rpx;
font-size: 32rpx;
font-weight: 600;
}
.channel-code-pill {
margin-left: 16rpx;
padding: 0;
display: flex;
flex-direction: column;
align-items: flex-end;
max-width: 360rpx;
}
.channel-code-label {
font-size: 22rpx;
opacity: 0.8;
margin-bottom: 4rpx;
}
.channel-code-text {
font-size: 22rpx;
font-weight: 500;
letter-spacing: 2rpx;
}
/* 统计卡片区域(贴近效果图) */
.stats-section {
padding: 0 30rpx 30rpx;
margin-top: -60rpx; /* 白卡片稍微压在蓝色圆角上 */
display: flex;
flex-direction: column;
gap: 24rpx;
}
/* 顶部大统计卡片 */
.stats-main-card {
background: #ffffff;
border-radius: 32rpx;
padding: 32rpx 30rpx 28rpx;
box-shadow: 0 20rpx 40rpx rgba(15, 23, 42, 0.16);
}
.withdraw-header-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
}
.withdraw-title-wrap {
display: flex;
align-items: center;
gap: 12rpx;
}
.withdraw-icon-wrap {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
background: rgba(79, 70, 229, 0.1);
display: flex;
align-items: center;
justify-content: center;
}
.withdraw-label {
font-size: 24rpx;
color: #9ca3af;
}
.withdraw-amount-row {
display: flex;
align-items: flex-end;
justify-content: flex-start;
margin: 24rpx 0 32rpx;
}
.withdraw-currency {
font-size: 60rpx;
color: #111827;
font-weight: 700;
margin-right: 4rpx;
}
.withdraw-amount-text {
font-size: 60rpx;
font-weight: 700;
color: #111827;
}
.withdraw-button-row {
display: flex;
justify-content: center;
margin-bottom: 32rpx;
}
.withdraw-button {
width: 100%;
height: 96rpx;
background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
border: none;
border-radius: 30rpx;
color: #fff;
font-size: 30rpx;
font-weight: 600;
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
&:disabled {
opacity: 0.7;
}
}
.withdraw-btn-text {
color: #fff;
}
.revenue-divider {
height: 1rpx;
background: #e5e7eb;
margin: 16rpx 0 22rpx;
}
.revenue-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.revenue-item {
flex: 1;
align-items: center;
text-align: center;
border-right: 1rpx solid #e5e7eb;
}
.revenue-label {
font-size: 22rpx;
color: #9ca3af;
margin-bottom: 6rpx;
display: block;
}
.revenue-value {
font-size: 30rpx;
font-weight: 600;
color: #111827;
}
.revenue-item:last-child {
border-right: none;
}
/* 底部两张统计卡片(总加好友数 / 总获客数) */
.acquisition-row {
display: flex;
gap: 20rpx;
}
.acquisition-card {
flex: 1;
background: #ffffff;
border-radius: 24rpx;
padding: 24rpx 22rpx 20rpx;
box-shadow: 0 12rpx 30rpx rgba(15, 23, 42, 0.08);
position: relative;
overflow: hidden;
}
.acquisition-main-number {
font-size: 40rpx;
font-weight: 700;
color: #111827;
}
.acquisition-main-sub {
font-size: 22rpx;
color: #9ca3af;
margin-left: 12rpx;
}
.acquisition-header-row {
display: flex;
align-items: center;
justify-content: flex-start;
margin-bottom: 26rpx;
}
.acquisition-icon {
width: 72rpx;
height: 72rpx;
border-radius: 24rpx;
display: flex;
align-items: center;
justify-content: center;
}
.friends-icon {
background: #e5edff;
}
.customer-icon {
background: #f5e5ff;
}
.acquisition-title-text {
margin-left: 24rpx;
font-size: 24rpx;
color: #9ca3af;
}
.acquisition-bottom-row {
display: flex;
align-items: baseline;
margin-top: 4rpx;
}
.acquisition-bg-circle {
position: absolute;
right: -40rpx;
bottom: -40rpx;
width: 160rpx;
height: 160rpx;
border-radius: 50%;
}
.friends-circle {
background: #eef3ff;
}
.customer-circle {
background: #f8edff;
}
/* 明细记录区域 */
.records-section {
background: transparent;
margin-top: 20rpx;
min-height: 60vh;
}
.records-section > view {
background-color: #ffffff;
border-radius: 24rpx;
padding: 26rpx 24rpx 30rpx;
box-shadow: 0 18rpx 36rpx rgba(15, 23, 42, 0.06);
}
.records-header {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 24rpx;
}
.records-title {
font-size: 32rpx;
font-weight: 600;
color: #111827;
}
/* 标签页 - 胶囊 */
.tabs-container {
margin-bottom: 24rpx;
}
.tabs-pill {
display: flex;
background-color: #eef2ff;
border-radius: 999rpx;
padding: 6rpx;
}
.tab-item {
flex: 1;
text-align: center;
padding: 18rpx 0;
font-size: 26rpx;
color: #6b7280;
border-radius: 999rpx;
&.active {
background-color: #ffffff;
color: #2563eb;
font-weight: 600;
box-shadow: 0 4rpx 12rpx rgba(37, 99, 235, 0.12);
}
}
/* 筛选条件卡片 */
.filter-section {
margin-bottom: 24rpx;
}
.filter-card {
background-color: #f7f9fc;
border-radius: 20rpx;
padding: 22rpx 24rpx 18rpx;
border: 1rpx solid #eef2ff;
}
.filter-header-row {
display: flex;
justify-content: space-between;
align-items: center;
}
.filter-header-left {
display: flex;
align-items: center;
gap: 10rpx;
}
.filter-title {
font-size: 26rpx;
color: #4b5563;
font-weight: 500;
}
.filter-content {
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 24rpx;
margin-top: 22rpx;
}
.filter-item {
flex: 1;
}
.filter-label {
font-size: 26rpx;
color: #9ca3af;
margin-bottom: 10rpx;
}
.filter-picker {
display: flex;
align-items: center;
gap: 8rpx;
font-size: 26rpx;
color: #111827;
padding: 18rpx 22rpx;
background-color: #ffffff;
border-radius: 16rpx;
border: 1rpx solid #eef2ff;
}
/* 记录列表 */
.records-list {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.records-count {
display: flex;
justify-content: space-between;
font-size: 24rpx;
color: #999;
margin-bottom: 20rpx;
}
.records-count-pill {
padding: 6rpx 16rpx;
border-radius: 999rpx;
background-color: #e5e7eb;
}
.current-count {
color: #4b5563;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
gap: 20rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
.record-item {
padding: 24rpx 0;
border-bottom: 1rpx solid #edf0f7;
}
.record-name {
font-size: 28rpx;
color: #111827;
font-weight: 500;
}
.record-main-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.record-title-wrap {
display: flex;
align-items: center;
gap: 12rpx;
flex: 1;
}
.record-badge {
font-size: 20rpx;
padding: 4rpx 12rpx;
border-radius: 999rpx;
color: #4b5563;
background-color: #e5ecff;
}
.badge-friend {
background-color: #e5f7ff;
}
.record-amount {
font-size: 30rpx;
font-weight: 600;
color: #111827;
&.amount-positive {
color: #16a34a;
}
}
.record-meta-row {
margin-top: 12rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.record-time-wrap {
display: flex;
align-items: center;
gap: 6rpx;
}
.record-time {
font-size: 24rpx;
color: #9ca3af;
}
.record-meta-type {
font-size: 24rpx;
color: #9ca3af;
}
.record-remark {
margin-top: 12rpx;
font-size: 22rpx;
color: #9ca3af;
display: flex;
align-items: flex-start;
gap: 8rpx;
}
.remark-label {
color: #9ca3af;
flex-shrink: 0;
}
.remark-value {
color: #6b7280;
flex: 1;
}
/* 提现明细专用样式 */
.withdraw-record-item {
padding: 26rpx 0;
}
.withdraw-main-row {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.withdraw-main-left {
display: flex;
flex-direction: column;
gap: 6rpx;
}
.withdraw-title {
font-size: 28rpx;
color: #111827;
font-weight: 500;
}
.withdraw-id {
font-size: 22rpx;
color: #9ca3af;
}
.withdraw-amount {
font-size: 32rpx;
font-weight: 600;
color: #16a34a;
}
.withdraw-tags-row {
margin-top: 12rpx;
display: flex;
flex-wrap: wrap;
gap: 10rpx;
}
.withdraw-tag {
padding: 4rpx 12rpx;
border-radius: 999rpx;
font-size: 20rpx;
color: #4b5563;
background-color: #e5ecff;
}
.status-tag {
background-color: #dcfce7;
color: #15803d;
}
.status-pending {
background-color: #fef9c3;
color: #ca8a04;
}
.status-rejected {
background-color: #fee2e2;
color: #b91c1c;
}
.withdraw-meta-row {
margin-top: 12rpx;
display: flex;
gap: 32rpx;
}
.withdraw-meta-item {
font-size: 22rpx;
color: #9ca3af;
}
.withdraw-meta-item .meta-label {
color: #9ca3af;
}
.withdraw-meta-item .meta-value {
margin-left: 4rpx;
color: #6b7280;
}
.withdraw-remark {
margin-top: 10rpx;
font-size: 22rpx;
color: #9ca3af;
}
/* 提现弹框 */
.withdraw-popup {
width: 600rpx;
background-color: #ffffff;
border-radius: 24rpx;
padding: 32rpx 28rpx 26rpx;
box-sizing: border-box;
}
.withdraw-popup-header {
margin-bottom: 24rpx;
}
.withdraw-popup-title {
font-size: 32rpx;
font-weight: 600;
color: #111827;
}
.withdraw-popup-subtitle {
margin-top: 8rpx;
font-size: 24rpx;
color: #9ca3af;
display: block;
}
.withdraw-popup-placeholder {
color: #d1d5db;
font-size: 28rpx;
}
/* 金额卡片 */
.withdraw-popup-card {
margin-top: 20rpx;
padding: 24rpx 24rpx 22rpx;
border-radius: 20rpx;
background-color: #fff7ed;
border: 1rpx solid #fed7aa;
}
.withdraw-popup-card-top {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.withdraw-popup-card-left {
display: flex;
flex-direction: column;
gap: 8rpx;
}
.card-main-label {
font-size: 26rpx;
color: #4b5563;
white-space: nowrap;
}
.card-sub-label {
font-size: 22rpx;
color: #f97316;
}
.withdraw-popup-amount-wrap {
display: flex;
align-items: baseline;
justify-content: flex-end;
flex: 1;
}
.withdraw-popup-amount-currency {
font-size: 40rpx;
color: #f97316;
font-weight: 700;
margin-right: 0;
}
.withdraw-popup-amount-input {
min-width: 160rpx;
font-size: 40rpx;
font-weight: 700;
color: #f97316;
text-align: right;
margin-left: 4rpx;
}
/* 信息块 */
.withdraw-popup-info {
margin-top: 20rpx;
padding: 18rpx 20rpx;
border-radius: 16rpx;
background-color: #eef2ff;
}
.withdraw-info-row {
display: flex;
align-items: center;
gap: 10rpx;
margin-bottom: 10rpx;
}
.withdraw-info-row:last-child {
margin-bottom: 0;
}
.withdraw-info-dot {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background-color: #3b82f6;
}
.withdraw-info-text {
font-size: 24rpx;
color: #4b5563;
}
.withdraw-popup-footer {
margin-top: 26rpx;
display: flex;
justify-content: flex-end;
gap: 16rpx;
}
.withdraw-popup-btn {
min-width: 180rpx;
height: 72rpx;
line-height: 72rpx;
border-radius: 999rpx;
font-size: 28rpx;
}
.withdraw-popup-btn.cancel {
background-color: #e5e7eb;
color: #374151;
}
.withdraw-popup-btn.confirm {
background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
color: #ffffff;
}
.load-more {
text-align: center;
padding: 30rpx 0;
color: #6366f1;
font-size: 28rpx;
}
.load-more-text {
color: #6366f1;
&.no-more {
color: #999;
}
}
.loading-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 0;
gap: 20rpx;
}
.loading-text {
font-size: 28rpx;
color: #999;
}
/* 修改密码弹框 */
.password-popup {
width: 600rpx;
background-color: #ffffff;
border-radius: 24rpx;
padding: 32rpx 28rpx 26rpx;
box-sizing: border-box;
}
.password-popup-header {
margin-bottom: 24rpx;
}
.password-popup-title {
font-size: 32rpx;
font-weight: 600;
color: #111827;
}
.password-popup-subtitle {
margin-top: 8rpx;
font-size: 24rpx;
color: #9ca3af;
display: block;
line-height: 1.6;
}
/* 表单区域 */
.password-popup-form {
margin-top: 20rpx;
display: flex;
flex-direction: column;
gap: 24rpx;
}
.password-form-item {
display: flex;
flex-direction: column;
gap: 12rpx;
}
.password-form-label {
display: flex;
align-items: center;
gap: 8rpx;
}
.password-form-label .label-text {
font-size: 26rpx;
color: #4b5563;
font-weight: 500;
}
.password-input-wrapper {
position: relative;
}
.password-input {
width: 100%;
height: 88rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #111827;
background-color: #f9fafb;
border: 2rpx solid #e5e7eb;
border-radius: 12rpx;
box-sizing: border-box;
transition: all 0.3s ease;
}
.password-input:focus {
border-color: #6366f1;
background-color: #fff;
box-shadow: 0 0 0 4rpx rgba(99, 102, 241, 0.1);
}
.password-placeholder {
color: #d1d5db;
font-size: 28rpx;
}
/* 提示信息 */
.password-popup-info {
margin-top: 20rpx;
padding: 18rpx 20rpx;
border-radius: 16rpx;
background-color: #eef2ff;
}
.password-info-row {
display: flex;
align-items: center;
gap: 10rpx;
margin-bottom: 10rpx;
}
.password-info-row:last-child {
margin-bottom: 0;
}
.password-info-dot {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background-color: #3b82f6;
flex-shrink: 0;
}
.password-info-text {
font-size: 24rpx;
color: #4b5563;
line-height: 1.5;
}
.password-popup-footer {
margin-top: 26rpx;
display: flex;
justify-content: flex-end;
gap: 16rpx;
}
.password-popup-btn {
min-width: 180rpx;
height: 72rpx;
line-height: 72rpx;
border-radius: 999rpx;
font-size: 28rpx;
border: none;
}
.password-popup-btn.cancel {
background-color: #e5e7eb;
color: #374151;
}
.password-popup-btn.confirm {
background: linear-gradient(135deg, #2563eb 0%, #3b82f6 100%);
color: #ffffff;
}
.password-popup-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
}
/* H5适配 */
/* #ifdef H5 */
.withdraw-button,
.settings-btn {
cursor: pointer;
transition: all 0.3s ease;
&:hover {
opacity: 0.9;
transform: translateY(-2rpx);
}
&:active {
transform: translateY(0);
}
}
.password-popup-btn {
cursor: pointer;
transition: all 0.3s ease;
&:hover:not(:disabled) {
opacity: 0.9;
transform: translateY(-2rpx);
}
&:active:not(:disabled) {
transform: translateY(0);
}
}
/* #endif */
</style>