文件
shanghaipeiwan/pwuniapp/pages/user/index.vue
xcbyy cacc478d71 fix(subscribe): 订阅消息未下发原因可见 + 小程序真实授权
- 后台测试推送:未就绪返回 mode=SIMULATED 明确原因 + 配置自检(模板ID/openid/appId/appSecret/总开关),不再把模拟显示为成功

- 占位符 tmpl_xxx 视为未配置(测试推送与订阅模板接口均过滤),微信错误码中文化(43101/47003/40037/40001 等)

- 小程序「平台消息与通知」点击时真实调用 wx.requestSubscribeMessage 并回显授权状态,标签不再恒为已开启

- 管理端拦截器错误提示改用 message;文档补订阅消息排查顺序;新增回归护栏(86 套件/631 用例全绿)
2026-10-19 10:02:57 +08:00

2977 行
80 KiB
Vue

此文件含有模棱两可的 Unicode 字符

此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。

<template>
<view class="user-container" :class="{ 'theme-warm': currentThemeKey === 'warm' }" :style="navStyle">
<!-- 用户头部个人资料卡 -->
<view class="profile-card" @click="!isLoggedIn && openLoginModal()">
<image
class="user-avatar btn-active"
:src="isLoggedIn && user.avatar ? user.avatar : DEFAULT_GUEST_AVATAR"
mode="aspectFill"
@click.stop="handleAvatarOrNameClick"
@error="onAvatarError"
/>
<view class="user-info">
<!-- 顶层水平对齐行:昵称/VIP 与 月亮太阳切换/设置 在同一水平线 -->
<view class="user-top-row">
<view class="name-row btn-active" @click.stop="handleAvatarOrNameClick">
<text class="user-name">{{ isLoggedIn ? user.nickname : '点击登录 / 注册' }}</text>
<text class="vip-badge" v-if="isLoggedIn">VIP 黄金玩家</text>
<text class="guest-badge" v-else>未登录</text>
</view>
<view class="header-actions">
<!-- 核心优化:月亮与太阳快捷切换胶囊 (与左侧昵称在同一水平线上) -->
<view class="theme-quick-switch btn-active" @click.stop="toggleThemeDirectly" title="切换界面风格">
<view
class="switch-icon-btn moon-btn"
:class="{ active: currentThemeKey === 'cool' }"
@click.stop="switchThemeTo('cool')"
>
<image class="theme-icon-svg" :src="ICONS.moon" mode="aspectFit" />
</view>
<view
class="switch-icon-btn sun-btn"
:class="{ active: currentThemeKey === 'warm' }"
@click.stop="switchThemeTo('warm')"
>
<image class="theme-icon-svg" :src="ICONS.sun" mode="aspectFit" />
</view>
</view>
<view class="edit-btn btn-active" v-if="isLoggedIn" @click.stop="editProfile" title="设置资料">
<image class="edit-svg" :src="ICONS.settings" mode="aspectFit" />
</view>
</view>
</view>
<view class="uid-phone-row" @click.stop="handleAvatarOrNameClick">
<text class="user-uid">{{ isLoggedIn ? `UID: ${user.id}` : '登录后享受完整陪伴服务' }}</text>
<text class="user-phone-tag" v-if="isLoggedIn && displayPhone">{{ displayPhone }}</text>
</view>
<text class="user-signature-text" v-if="isLoggedIn && user.signature" @click.stop="handleAvatarOrNameClick">{{ user.signature }}</text>
</view>
</view>
<!-- 核心亮点:双身份流光切换卡 (纯矢量与流光动效) -->
<view class="role-switch-card identity-banner card-active" @click="toggleRole">
<view class="role-glow-border"></view>
<view class="role-content">
<view class="role-left">
<view class="role-title-row">
<view class="role-dot" :class="{ expert: currentRole === 'EXPERT' }"></view>
<text class="current-role-tag">
{{ currentRole === 'PLAYER' ? '当前身份:普通玩家' : '当前身份:接单大神' }}
</text>
</view>
<text class="role-sub">
{{ currentRole === 'PLAYER' ? '一键切换至大神接单工作台,开启派单收益' : '一键切换回玩家大厅,自由寻找开黑车队' }}
</text>
</view>
<button class="btn-switch-role btn-active">
{{ currentRole === 'PLAYER' ? '切换为大神' : '切回玩家端' }}
</button>
</view>
</view>
<!-- 钱包与资产看板 -->
<view class="wallet-card">
<view class="wallet-head">
<text class="wallet-title">我的资产</text>
<text class="wallet-detail" @click="viewWalletLog">账单明细 ›</text>
</view>
<view class="asset-grid">
<view class="asset-col">
<text class="asset-label">可用余额 (元)</text>
<text class="asset-val green-val">{{ isLoggedIn ? `¥${user.balance}` : '--' }}</text>
<button class="asset-btn recharge btn-active" @click="handleRecharge">充值</button>
</view>
<view class="asset-divider"></view>
<view class="asset-col">
<text class="asset-label">分销佣金收益 (元)</text>
<text class="asset-val gold-val">{{ isLoggedIn ? `¥${user.commission}` : '--' }}</text>
<view class="asset-btn-group">
<button class="asset-btn withdraw btn-active" @click="openWithdrawModal">提现</button>
<button class="asset-btn records btn-active" @click="openWithdrawRecordsModal">记录</button>
</view>
</view>
</view>
</view>
<!-- 核心功能金刚区 (纯矢量SVG图标) -->
<view class="menu-grid-card">
<view class="menu-item btn-active" @click="navTo('/pages/activity/list?tab=MINE')">
<view class="menu-icon bg-indigo">
<image class="menu-svg" :src="ICONS.gameCrown" mode="aspectFit" />
</view>
<text class="menu-title">我的组局</text>
<text class="menu-desc">发单记录与管理</text>
</view>
<view class="menu-item btn-active" @click="navTo('/pages/activity/my-ticket')">
<view class="menu-icon bg-green">
<image class="menu-svg" :src="ICONS.ticket" mode="aspectFit" />
</view>
<text class="menu-title">我的门票</text>
<text class="menu-desc">4位核销码</text>
</view>
<view class="menu-item btn-active" @click="navTo('/pages/order/list')">
<view class="menu-icon bg-blue">
<image class="menu-svg" :src="ICONS.orderList" mode="aspectFit" />
</view>
<text class="menu-title">所有订单</text>
<text class="menu-desc">对局与退款</text>
</view>
<view class="menu-item btn-active" @click="navTo('/pages/user/promote')">
<view class="menu-icon bg-purple">
<image class="menu-svg" :src="ICONS.share" mode="aspectFit" />
</view>
<text class="menu-title">推广赚钱</text>
<text class="menu-desc">二级返佣</text>
</view>
</view>
<!-- 列表式功能菜单 (纯矢量SVG图标) -->
<view class="list-menu-card">
<view class="list-row btn-active" @click="openFavoritesModal">
<image class="row-svg" :src="ICONS.starFilled" mode="aspectFit" />
<text class="row-label">我的收藏</text>
<view class="row-badge" v-if="favoriteList.length > 0">{{ favoriteList.length }}</view>
<image class="row-arrow-svg" :src="ICONS.chevronRight" mode="aspectFit" />
</view>
<view class="list-row btn-active" @click="applyExpert">
<image class="row-svg" :src="ICONS.expertBadge" mode="aspectFit" />
<text class="row-label">大神入驻认证</text>
<image class="row-arrow-svg" :src="ICONS.chevronRight" mode="aspectFit" />
</view>
<view class="list-row btn-active" @click="openSettingsModal">
<image class="row-svg" :src="ICONS.settings" mode="aspectFit" />
<text class="row-label">系统与隐私设置</text>
<image class="row-arrow-svg" :src="ICONS.chevronRight" mode="aspectFit" />
</view>
<view class="list-row btn-active" @click="contactService">
<image class="row-svg" :src="ICONS.headphones" mode="aspectFit" />
<text class="row-label">官方在线客服</text>
<image class="row-arrow-svg" :src="ICONS.chevronRight" mode="aspectFit" />
</view>
<view class="list-row btn-active" @click="openNotice">
<image class="row-svg" :src="ICONS.bell" mode="aspectFit" />
<text class="row-label">平台消息与通知</text>
<text class="row-sub-tag">{{ noticeSubscribe ? '已开启提醒' : '点击开启' }}</text>
<image class="row-arrow-svg" :src="ICONS.chevronRight" mode="aspectFit" />
</view>
<view class="list-row btn-active" @click="openMyReportsModal">
<image class="row-svg" :src="ICONS.alert" mode="aspectFit" />
<text class="row-label">我的举报与维权反馈</text>
<text class="row-sub-tag" v-if="myReportsList.length > 0">{{ myReportsList.length }}条记录</text>
<image class="row-arrow-svg" :src="ICONS.chevronRight" mode="aspectFit" />
</view>
<view class="list-row btn-active" @click="openFaq">
<image class="row-svg" :src="ICONS.messageSquare" mode="aspectFit" />
<text class="row-label">帮助中心与常见问题</text>
<image class="row-arrow-svg" :src="ICONS.chevronRight" mode="aspectFit" />
</view>
<view class="list-row btn-active" @click="openAbout">
<image class="row-svg" :src="ICONS.shield" mode="aspectFit" />
<text class="row-label">平台规范与服务协议</text>
<image class="row-arrow-svg" :src="ICONS.chevronRight" mode="aspectFit" />
</view>
</view>
<!-- 退出登录与账号切换操作卡片 -->
<view class="account-actions-card" v-if="isLoggedIn">
<view class="account-btn-group">
<button class="btn-switch-account btn-active" @click="openLoginModal">切换账号</button>
<button class="btn-logout btn-active" @click="handleLogout">退出当前登录</button>
</view>
</view>
<view class="account-actions-card not-logged" v-else>
<button class="btn-primary-login btn-active" @click="openLoginModal">立即登录 / 注册</button>
</view>
<!-- 个人资料编辑设置弹窗 -->
<view class="profile-edit-modal-mask" v-if="showEditModal" @click="showEditModal = false">
<view class="profile-edit-modal" @click.stop>
<view class="modal-header">
<text class="modal-title">个人信息设置</text>
<view class="btn-close btn-active" @click="showEditModal = false">
<image class="close-svg" :src="ICONS.close" mode="aspectFit" />
</view>
</view>
<view class="modal-body">
<!-- 预设头像切换与真实上传 (支持微信官方头像与相册上传) -->
<view class="edit-avatar-section">
<image class="avatar-preview btn-active" :src="editForm.avatar" mode="aspectFill" @click="chooseCustomAvatar" />
<view class="avatar-meta">
<view class="avatar-label-row">
<text class="avatar-label">点击更换推荐头像</text>
<view class="avatar-action-links">
<!-- #ifdef MP-WEIXIN -->
<button class="btn-wechat-choose btn-active" open-type="chooseAvatar" @chooseavatar="onWechatChooseAvatar">
微信头像
</button>
<!-- #endif -->
<text class="btn-custom-upload btn-active" @click="chooseCustomAvatar">相册上传</text>
</view>
</view>
<view class="preset-avatars-row">
<image
v-for="(av, idx) in PRESET_AVATARS"
:key="idx"
class="preset-avatar-item btn-active"
:class="{ selected: editForm.avatar === av }"
:src="av"
mode="aspectFill"
@click="editForm.avatar = av"
/>
</view>
</view>
</view>
<!-- 昵称输入 (支持微信官方 type="nickname" 规范,采用 type="text" 避免游客模式 reviewNickname:fail 渲染层报错与失焦清空) -->
<view class="edit-field">
<text class="field-label">用户昵称</text>
<input
class="field-input"
type="text"
v-model="editForm.nickname"
@input="onNicknameInput"
maxlength="15"
placeholder="请输入您的新昵称"
placeholder-class="field-placeholder"
/>
</view>
<!-- 联系方式 -->
<view class="edit-field">
<view class="field-label-row">
<text class="field-label">联系电话 / 微信号</text>
<text class="field-tip-text">支持11位手机号或微信号</text>
</view>
<input
class="field-input"
type="text"
v-model="editForm.phone"
@input="onPhoneInput"
maxlength="20"
placeholder="请输入11位手机号或微信号"
placeholder-class="field-placeholder"
/>
</view>
<!-- 性别选择 (男 / 女 / 保密 胶囊单选) -->
<view class="edit-field">
<text class="field-label">用户性别</text>
<view class="gender-pill-group">
<view
v-for="g in ['男', '女', '保密']"
:key="g"
class="gender-pill btn-active"
:class="{ active: editForm.gender === g }"
@click="editForm.gender = g"
>
{{ g }}
</view>
</view>
</view>
<!-- 个性签名 -->
<view class="edit-field">
<text class="field-label">个性签名</text>
<input
class="field-input"
v-model="editForm.signature"
maxlength="60"
placeholder="分享您的常玩段位或搭子宣言(如:常驻朝阳,王者荣耀星耀)"
placeholder-class="field-placeholder"
/>
</view>
</view>
<view class="modal-footer">
<button class="btn-modal btn-cancel btn-active" @click="showEditModal = false">取消</button>
<button class="btn-modal btn-save btn-active" @click="saveProfile">保存修改</button>
</view>
</view>
</view>
<!-- 提现历史与审批记录跟踪弹窗 -->
<view class="profile-edit-modal-mask" v-if="showWithdrawRecordsModal" @click="showWithdrawRecordsModal = false">
<view class="profile-edit-modal withdraw-records-modal-box" @click.stop>
<view class="modal-header">
<text class="modal-title">提现审批记录</text>
<view class="btn-close btn-active" @click="showWithdrawRecordsModal = false">
<image class="close-svg" :src="ICONS.close" mode="aspectFit" />
</view>
</view>
<scroll-view scroll-y class="records-modal-scroll" v-if="userWithdrawalsList.length > 0">
<view v-for="rec in userWithdrawalsList" :key="rec.id" class="wd-card-row">
<view class="wd-row-top">
<text class="wd-no">{{ rec.withdrawNo }}</text>
<text
class="wd-badge"
:class="{
pending: rec.status === '待审核',
success: rec.status === '已打款',
rejected: rec.status === '已驳回'
}"
>
{{ rec.status }}
</text>
</view>
<view class="wd-row-center">
<text class="wd-val">¥{{ rec.amount }}</text>
<text class="wd-ch">{{ rec.channel }}</text>
</view>
<view class="wd-row-bot">
<text class="wd-time">{{ rec.applyTime }}</text>
<text class="wd-reason" v-if="rec.reason">驳回理由:{{ rec.reason }}</text>
</view>
</view>
</scroll-view>
<view class="empty-records-box" v-else>
<image class="empty-icon-svg" :src="ICONS.fileText" mode="aspectFit" />
<text class="empty-txt">暂无提现申请记录</text>
</view>
</view>
</view>
<!-- 底部自定义导航栏 (动态自适应发单人4项 / 接单人3项) -->
<AppTabBar current="user" />
<!-- 微信小程序用户隐私保护指引弹窗 (微信合规) -->
<privacy-modal ref="privacyModalRef" />
</view>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import AppTabBar from '@/components/CustomTabBar.vue';
import PrivacyModal from '@/components/PrivacyModal.vue';
import { ICONS } from '@/common/icons.js';
import { getCurrentThemeKey, setTheme, THEME_KEYS, applyThemeToNativeUI } from '@/common/theme.js';
import { getCurrentRole, setCurrentRole, ROLE_TYPES, toggleRole as toggleUserRole, isExpertCertified, getExpertCertStatus, setExpertCertStatus, CERT_STATUS } from '@/common/role.js';
import { getNavBarInfo } from '@/common/nav.js';
import { getUserProfile, rechargeBalance, withdrawCommission, getUserFinanceRecords, updateUserProfile, uploadImage, getRechargeTiers, getPlatformConfigs, applyExpertCert, getUserWithdrawals, getFavorites, removeFavorite, getDistributionTeam, getDistributionRecords, getMyReports, bindInviteCode } from '@/common/api.js';
import { preloadSubscribeTemplates, requestSubscribeAll } from '@/common/subscribe.js';
const DEFAULT_GUEST_AVATAR = 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=200';
const initialUserId = typeof uni !== 'undefined' ? (uni.getStorageSync('userId') || null) : null;
const isLoggedIn = ref(Boolean(initialUserId));
const showLoginModal = ref(false);
// 我的收藏与我的举报反馈
const favoriteList = ref([]);
const loadingFavorites = ref(false);
const myReportsList = ref([]);
const loadMyReports = async () => {
const uid = user.value.id || uni.getStorageSync('userId') || 1001;
try {
const list = await getMyReports(uid);
if (Array.isArray(list)) {
myReportsList.value = list;
}
} catch (_) {}
};
const openMyReportsModal = () => {
if (!ensureLoggedIn()) return;
uni.navigateTo({
url: '/pages/user/reports'
});
};
// 系统与隐私设置
const privacyHidePhone = ref(uni.getStorageSync('privacy_hide_phone') === '1');
const noticeSubscribe = ref(uni.getStorageSync('notice_subscribe') === '1');
const cacheSizeText = ref('1.25 MB');
// 分销推广管理
const showDistributionModal = ref(false);
const distActiveTab = ref('poster');
const teamLevelTab = ref(1);
const distributionTeam = ref({
directCount: 0,
indirectCount: 0,
totalTeamCount: 0,
directList: [],
indirectList: []
});
const distributionRecords = ref([]);
const distWithdrawAmount = ref('');
const submittingDistWithdraw = ref(false);
const DEMO_ACCOUNTS = [
{
id: 1001,
nickname: '同城局长',
roleTag: 'host',
roleDesc: '房主/局长',
desc: '余额充足 · 组局发单',
avatar: 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=200'
},
{
id: 2001,
nickname: '超能电竞玩家',
roleTag: 'buyer',
roleDesc: '普通买家',
desc: '搭子报名 · 预约下单',
avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=200'
},
{
id: 2006,
nickname: '苏苏学姐',
roleTag: 'expert',
roleDesc: '金牌陪伴师',
desc: '接单工作台 · 4位核销',
avatar: 'https://images.unsplash.com/photo-1524504388940-b1c1722653e1?w=200'
}
];
const user = ref({
id: initialUserId || '',
nickname: initialUserId ? '用户' : '点击登录 / 注册',
avatar: DEFAULT_GUEST_AVATAR,
gender: '保密',
role: 'PLAYER',
balance: '0.00',
commission: '0.00',
orderCount: 0,
invitedCount: 0,
phone: '',
signature: initialUserId ? '同城常驻 · 寻找靠谱搭子' : ''
});
const currentRole = ref(getCurrentRole());
const currentThemeKey = ref(getCurrentThemeKey());
const navInfo = ref(getNavBarInfo());
const privacyModalRef = ref(null);
const platformConfigs = ref({
customer_service: {
hotline: '400-888-6666',
hotlineDesc: '7x24h 官方客服服务热线',
wechat: 'peiwan_vip_kefu',
wechatDesc: '官方 VIP 客服微信号'
},
safety_notice: {
title: '平台官方公告与指引',
points: [
'【安全履约须知】为保障搭子与陪伴师人身与财产安全,线下约局须在合规公开商业街区进行。',
'【现场核销】现场碰面后请出示 4 位数字核销码进行签到确认。',
'【平台兜底】平台提供 7x24 小时争议仲裁与资金托管保障服务。'
]
},
platform_protocol: {
title: '用户服务协议与隐私规范',
summary: '严禁发布任何违规言论及低俗诈骗行为,平台全面遵循微信内容安全风控与用户隐私保护标准。'
}
});
const loadPlatformConfigs = async () => {
try {
const res = await getPlatformConfigs();
if (res && typeof res === 'object') {
platformConfigs.value = {
...platformConfigs.value,
...res
};
}
} catch (e) {
console.warn('[User] 加载系统配置失败降级:', e);
}
};
const navStyle = computed(() => {
const gap = (navInfo.value && navInfo.value.totalHeaderHeight) || 88;
return `--safe-header-gap: ${gap}px; padding-top: ${gap}px;`;
});
const onThemeChanged = (key) => {
currentThemeKey.value = key;
applyThemeToNativeUI(key);
};
const onRoleChanged = (role) => {
currentRole.value = role;
};
// 登录/注册已全面重构升级为独立专属页面 /pages/auth/login
// 保持向下兼容: switchDemoAccount, login-modal-mask, 一键授权快捷登录
const openLoginModal = () => {
uni.navigateTo({
url: '/pages/auth/login'
});
};
const onLoginSuccess = (payload) => {
loadUserProfile(payload?.userId);
};
const handleLogout = () => {
uni.showModal({
title: '确认退出登录?',
content: '退出登录后将清除本地会话,切换为未登录游客态。是否确认退出?',
confirmText: '退出登录',
confirmColor: '#EF4444',
cancelText: '取消',
success: (res) => {
if (res.confirm) {
uni.removeStorageSync('userInfo');
uni.removeStorageSync('userId');
uni.removeStorageSync('PW_USER_INFO');
uni.removeStorageSync('userToken');
uni.setStorageSync('user_has_logged_out', '1');
isLoggedIn.value = false;
user.value = {
id: '',
nickname: '点击登录 / 注册',
avatar: DEFAULT_GUEST_AVATAR,
role: 'PLAYER',
balance: '0.00',
commission: '0.00',
orderCount: 0,
invitedCount: 0,
phone: ''
};
uni.showToast({
title: '已退出登录',
icon: 'none',
duration: 1500
});
}
}
});
};
const loadUserProfile = async (targetId) => {
const storedUid = targetId || (typeof uni !== 'undefined' ? uni.getStorageSync('userId') : null);
const hasLoggedOut = typeof uni !== 'undefined' ? uni.getStorageSync('user_has_logged_out') : null;
if ((hasLoggedOut || !storedUid) && !targetId) {
isLoggedIn.value = false;
user.value = {
id: '',
nickname: '点击登录 / 注册',
avatar: DEFAULT_GUEST_AVATAR,
role: 'PLAYER',
balance: '0.00',
commission: '0.00',
orderCount: 0,
invitedCount: 0,
phone: '',
signature: ''
};
return;
}
isLoggedIn.value = true;
let uid = storedUid;
if (uid == 101) {
uid = 2006;
uni.setStorageSync('userId', 2006);
}
try {
const profile = await getUserProfile(uid);
if (profile) {
let safeAvatar = profile.avatar;
if (!safeAvatar || safeAvatar.startsWith('http://tmp') || safeAvatar.includes('__tmp__')) {
safeAvatar = DEFAULT_GUEST_AVATAR;
}
user.value = {
...user.value,
...profile,
avatar: safeAvatar
};
// 实时同步服务端大神认证审核状态至本地 Storage,确保后台审核通过/驳回立即生效
if (profile.certStatus !== undefined) {
setExpertCertStatus(Number(profile.certStatus));
} else if (profile.isExpert || (profile.role && profile.role.includes('大神'))) {
setExpertCertStatus(CERT_STATUS.APPROVED);
}
const syncedProfile = {
...(uni.getStorageSync('PW_USER_INFO') || {}),
...(uni.getStorageSync('userInfo') || {}),
...user.value
};
uni.setStorageSync('PW_USER_INFO', syncedProfile);
uni.setStorageSync('userInfo', syncedProfile);
// 若通过小程序太阳码海报进入带有待绑定的推荐人标识且当前尚未绑定上级,首次登录自动建立父子关联
const pendingInviter = uni.getStorageSync('PENDING_INVITER_CODE');
if (pendingInviter && !profile.inviterId) {
bindInviteCode(uid, pendingInviter)
.then((res) => {
uni.removeStorageSync('PENDING_INVITER_CODE');
if (res && res.inviterId) {
user.value.inviterId = res.inviterId;
}
})
.catch((err) => {
// 绑定失败保留待绑定码以便下次登录重试,避免静默丢失邀请关系
console.warn('[User] 邀请码绑定失败,将于下次登录重试:', err && err.message);
});
}
}
} catch (err) {
console.warn('[User] 加载用户信息异常:', err.message);
}
};
const onAvatarError = () => {
user.value.avatar = DEFAULT_GUEST_AVATAR;
};
onMounted(() => {
navInfo.value = getNavBarInfo();
currentRole.value = getCurrentRole();
currentThemeKey.value = getCurrentThemeKey();
applyThemeToNativeUI(currentThemeKey.value);
uni.$on('theme-change', onThemeChanged);
uni.$on('role-change', onRoleChanged);
uni.$on('login-success', onLoginSuccess);
loadUserProfile();
loadPlatformConfigs();
loadMyReports();
// 预加载订阅消息模板ID,确保点击授权时无需等待网络(保留点击手势)
preloadSubscribeTemplates();
});
onShow(() => {
navInfo.value = getNavBarInfo();
currentRole.value = getCurrentRole();
currentThemeKey.value = getCurrentThemeKey();
applyThemeToNativeUI(currentThemeKey.value);
uni.hideTabBar({ animation: false, fail: () => {} });
loadUserProfile();
loadPlatformConfigs();
privacyHidePhone.value = uni.getStorageSync('privacy_hide_phone') === '1';
noticeSubscribe.value = uni.getStorageSync('notice_subscribe') === '1';
if (isLoggedIn.value) {
loadFavorites();
loadMyReports();
}
});
onUnmounted(() => {
uni.$off('theme-change', onThemeChanged);
uni.$off('role-change', onRoleChanged);
uni.$off('login-success', onLoginSuccess);
});
const switchThemeTo = (targetKey) => {
if (currentThemeKey.value === targetKey) return;
currentThemeKey.value = targetKey;
setTheme(targetKey);
uni.showToast({
title: targetKey === THEME_KEYS.WARM ? '已切换至【浅色暖阳】主题' : '已切换至【冷光暗夜】经典款',
icon: 'none',
duration: 1500
});
};
const toggleThemeDirectly = () => {
const targetKey = currentThemeKey.value === THEME_KEYS.WARM ? THEME_KEYS.COOL : THEME_KEYS.WARM;
switchThemeTo(targetKey);
};
const handleSwitchTheme = () => {
toggleThemeDirectly();
};
const toggleRole = () => {
if (!ensureLoggedIn()) return;
if (!isExpertCertified()) {
const curCert = getExpertCertStatus();
const isPending = curCert === CERT_STATUS.PENDING;
const isRejected = curCert === CERT_STATUS.REJECTED;
uni.showModal({
title: isPending ? '入驻资质审核中' : (isRejected ? '入驻审核未通过' : '大神实名认证提醒'),
content: isPending
? '您的大神实名入驻申请正在由平台运营人工核验中,审核通过后即可切换至接单模式。是否查看审核进度?'
: isRejected
? `上次申请未通过:${user.value.rejectReason || '请核对身份与资质信息'}。是否立即修改并重新提交?`
: '当前账号尚未完成大神实名入驻认证,无法切换至接单模式。是否立即申请认证?',
confirmText: isPending ? '查看进度' : (isRejected ? '重新提交' : '立即认证'),
cancelText: '稍后再说',
confirmColor: '#10B981',
success: (res) => {
if (res.confirm) {
applyExpert();
}
}
});
return;
}
const result = toggleUserRole();
const newRole = typeof result === 'object' ? result.currentRole : result;
currentRole.value = newRole;
if (newRole === ROLE_TYPES.EXPERT) {
uni.showToast({
title: '已进入【大神接单端】',
icon: 'success',
duration: 1200
});
setTimeout(() => {
uni.reLaunch({
url: '/pages/expert/hall'
});
}, 500);
} else {
uni.showToast({
title: '已切回【发单人端】',
icon: 'none',
duration: 1200
});
}
};
const showEditModal = ref(false);
const PRESET_AVATARS = [
'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=200',
'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=200',
'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=200',
'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200'
];
const editForm = ref({
nickname: '',
avatar: '',
phone: '',
gender: '保密',
signature: ''
});
const editProfile = () => {
if (!ensureLoggedIn()) return;
const initialNick = (user.value.nickname && user.value.nickname !== '点击登录 / 注册') ? user.value.nickname : '';
editForm.value = {
nickname: initialNick,
avatar: user.value.avatar || PRESET_AVATARS[0],
phone: user.value.phone || '',
gender: user.value.gender || '保密',
signature: user.value.signature || ''
};
showEditModal.value = true;
};
const onNicknameInput = (e) => {
if (e && e.detail && typeof e.detail.value === 'string') {
editForm.value.nickname = e.detail.value;
}
};
const onPhoneInput = (e) => {
if (e && e.detail && typeof e.detail.value === 'string') {
editForm.value.phone = e.detail.value.replace(/[\s、,,。;;!!??]/g, '');
}
};
const validateContact = (val) => {
if (!val) return { valid: true };
const str = String(val).trim();
// 1. 中国大陆11位手机号 (以1开头的11位纯数字,第二位为3-9)
const isMobile = /^1[3-9]\d{9}$/.test(str);
if (isMobile) return { valid: true, type: 'phone' };
// 2. 微信标准微信号 (6-20位,以字母开头,仅包含字母、数字、下划线、减号)
const isWechat = /^[a-zA-Z][-_a-zA-Z0-9]{5,19}$/.test(str);
if (isWechat) return { valid: true, type: 'wechat' };
// 3. 历史未修改的脱敏展示掩码 (形如 138****8888)
const isMaskedMobile = /^1[3-9]\d\*{4}\d{4}$/.test(str);
if (isMaskedMobile) return { valid: true, type: 'masked' };
// 如果包含中文标点符号(如顿号、逗号)
if (/[\u3001\u3002\uff0c\uff1b\uff1f\uff01\s]/.test(str)) {
return { valid: false, message: '联系方式中不能包含标点符号或空格' };
}
// 如果是纯数字但不是11位
if (/^\d+$/.test(str) && str.length !== 11) {
return { valid: false, message: '手机号码必须为11位纯数字' };
}
return { valid: false, message: '请输入有效的11位手机号或微信号' };
};
// 点击头像或名称行:已登录时直接打开个人资料设置弹窗,未登录时引导登录
const handleAvatarOrNameClick = () => {
if (isLoggedIn.value) {
editProfile();
} else {
openLoginModal();
}
};
// 微信官方快捷选取头像回调
const onWechatChooseAvatar = async (e) => {
const avatarUrl = e?.detail?.avatarUrl;
if (!avatarUrl) return;
uni.showLoading({ title: '正在同步微信头像...' });
try {
const onlineUrl = await uploadImage(avatarUrl);
editForm.value.avatar = onlineUrl;
uni.hideLoading();
uni.showToast({ title: '微信头像获取成功', icon: 'success' });
} catch (err) {
uni.hideLoading();
// 上传失败时保留原头像,切勿将本地临时路径 http://tmp/... 赋值给 avatar,避免触发渲染层 CORS 拦截
uni.showToast({ title: err.message || '微信头像上传失败,请重试', icon: 'none' });
}
};
const chooseCustomAvatar = () => {
uni.chooseImage({
count: 1,
sizeType: ['compressed'],
sourceType: ['album', 'camera'],
success: async (res) => {
const tempPath = res.tempFilePaths && res.tempFilePaths[0];
if (!tempPath) return;
uni.showLoading({ title: '正在上传头像...' });
try {
const onlineUrl = await uploadImage(tempPath);
editForm.value.avatar = onlineUrl;
uni.hideLoading();
uni.showToast({ title: '头像上传成功', icon: 'success' });
} catch (e) {
uni.hideLoading();
uni.showToast({ title: e.message || '上传头像失败', icon: 'none' });
}
}
});
};
const saveProfile = async () => {
const finalNickname = editForm.value.nickname ? editForm.value.nickname.trim() : '';
if (!finalNickname) {
uni.showToast({ title: '昵称不能为空', icon: 'none' });
return;
}
editForm.value.nickname = finalNickname;
const finalPhone = editForm.value.phone ? editForm.value.phone.trim() : '';
if (finalPhone) {
const contactCheck = validateContact(finalPhone);
if (!contactCheck.valid) {
uni.showToast({
title: contactCheck.message || '请输入有效的11位手机号或微信号',
icon: 'none',
duration: 2000
});
return;
}
}
editForm.value.phone = finalPhone;
const currentAvatar = editForm.value.avatar || '';
if (
currentAvatar.startsWith('http://tmp/') ||
currentAvatar.startsWith('http://usr/') ||
currentAvatar.startsWith('wxfile://') ||
currentAvatar.startsWith('blob:')
) {
uni.showToast({ title: '头像正在同步或上传异常,请重新选取', icon: 'none' });
return;
}
uni.showLoading({ title: '正在保存资料...' });
try {
const updated = await updateUserProfile(user.value.id || 1001, {
nickname: finalNickname,
avatar: editForm.value.avatar,
phone: finalPhone,
gender: editForm.value.gender || '保密',
signature: editForm.value.signature ? editForm.value.signature.trim() : ''
});
uni.hideLoading();
if (updated) {
user.value = {
...user.value,
...updated
};
} else {
user.value.nickname = finalNickname;
user.value.avatar = editForm.value.avatar;
user.value.phone = finalPhone;
user.value.gender = editForm.value.gender || '保密';
user.value.signature = editForm.value.signature ? editForm.value.signature.trim() : '';
}
const syncedProfile = {
...(uni.getStorageSync('PW_USER_INFO') || {}),
...(uni.getStorageSync('userInfo') || {}),
...user.value
};
uni.setStorageSync('PW_USER_INFO', syncedProfile);
uni.setStorageSync('userInfo', syncedProfile);
showEditModal.value = false;
uni.showToast({
title: '个人信息修改成功',
icon: 'success'
});
} catch (err) {
uni.hideLoading();
uni.showToast({
title: err.message || '保存失败,请稍后重试',
icon: 'none'
});
}
};
const ensureLoggedIn = () => {
if (!isLoggedIn.value) {
uni.showToast({ title: '请先登录账号', icon: 'none' });
openLoginModal();
return false;
}
return true;
};
const viewWalletLog = () => {
if (!ensureLoggedIn()) return;
uni.navigateTo({
url: '/pages/user/bill-records'
});
};
const handleRecharge = () => {
if (!ensureLoggedIn()) return;
uni.navigateTo({
url: '/pages/user/recharge'
});
};
const showWithdrawRecordsModal = ref(false);
const userWithdrawalsList = ref([]);
const financeRules = computed(() => {
return platformConfigs.value.finance_rules || {};
});
const minWithdrawAmount = computed(() => {
return Number(financeRules.value.minWithdrawAmount) || 50;
});
const openWithdrawModal = () => {
if (!ensureLoggedIn()) return;
uni.navigateTo({
url: '/pages/user/withdraw'
});
};
const handleWithdraw = () => {
openWithdrawModal();
};
const navToWithdraw = () => {
openWithdrawModal();
};
const openWithdrawRecordsModal = async () => {
if (!ensureLoggedIn()) return;
uni.navigateTo({
url: '/pages/user/withdraw-records'
});
};
// 手机号脱敏展示
const displayPhone = computed(() => {
const phone = user.value.phone;
if (!phone) return '';
if (privacyHidePhone.value) {
if (phone.length >= 11) {
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
}
return phone.slice(0, 3) + '****';
}
return phone;
});
// 1. 我的收藏业务逻辑(跳转独立页面)
const openFavoritesModal = () => {
if (!ensureLoggedIn()) return;
uni.navigateTo({
url: '/pages/user/favorites'
});
};
const loadFavorites = async () => {
loadingFavorites.value = true;
try {
const list = await getFavorites(user.value.id || 1001);
favoriteList.value = Array.isArray(list) ? list : [];
} catch (_) {
favoriteList.value = [];
} finally {
loadingFavorites.value = false;
}
};
// 2. 系统与隐私设置业务逻辑
const updateCacheSize = () => {
try {
const info = uni.getStorageInfoSync();
const kb = info.currentSize || 0;
if (kb > 1024) {
cacheSizeText.value = `${(kb / 1024).toFixed(2)} MB`;
} else {
cacheSizeText.value = `${kb} KB`;
}
} catch (_) {
cacheSizeText.value = '1.25 MB';
}
};
// 2. 系统与隐私设置(跳转独立设置页面)
const openSettingsModal = () => {
if (!ensureLoggedIn()) return;
uni.navigateTo({
url: '/pages/user/settings'
});
};
const clearLocalCache = () => {
try {
const token = uni.getStorageSync('peiwan_token');
const userRole = uni.getStorageSync('peiwan_current_role');
const themeKey = uni.getStorageSync('app_theme_key');
const hidePhone = uni.getStorageSync('privacy_hide_phone');
uni.clearStorageSync();
if (token) uni.setStorageSync('peiwan_token', token);
if (userRole) uni.setStorageSync('peiwan_current_role', userRole);
if (themeKey) uni.setStorageSync('app_theme_key', themeKey);
if (hidePhone) uni.setStorageSync('privacy_hide_phone', hidePhone);
cacheSizeText.value = '0 KB';
uni.showToast({ title: '缓存清理完毕', icon: 'success' });
} catch (_) {
uni.showToast({ title: '清理成功', icon: 'success' });
}
};
// 3. 分销推广管理业务逻辑 (跳转独立页面)
const openDistributionModal = () => {
if (!ensureLoggedIn()) return;
uni.navigateTo({
url: '/pages/user/promote'
});
};
const showInvitePoster = () => {
openDistributionModal();
};
const loadDistributionData = async () => {
const uid = user.value.id || 1001;
try {
const [teamData, records] = await Promise.all([
getDistributionTeam(uid),
getDistributionRecords(uid)
]);
if (teamData) distributionTeam.value = teamData;
if (records) distributionRecords.value = records;
} catch (_) {}
};
const copyInviteCode = () => {
const code = `PW${user.value.id || 1001}`;
uni.setClipboardData({
data: code,
success: () => {
uni.showToast({ title: '邀请码已复制', icon: 'success' });
}
});
};
const copyInviteLink = () => {
const link = `https://peiww.gynhc.com/invite?code=PW${user.value.id || 1001}`;
uni.setClipboardData({
data: link,
success: () => {
uni.showToast({ title: '邀请链接已复制', icon: 'success' });
}
});
};
const savePosterImage = () => {
uni.showToast({ title: '海报已保存至相册', icon: 'success' });
};
const submitDistWithdraw = async () => {
const amount = Number(distWithdrawAmount.value);
if (!amount || amount <= 0) {
uni.showToast({ title: '请输入有效提现金额', icon: 'none' });
return;
}
const currentComm = Number(user.value.commission || 0);
if (amount > currentComm) {
uni.showToast({ title: `提现金额超出可提现佣金`, icon: 'none' });
return;
}
submittingDistWithdraw.value = true;
uni.showLoading({ title: '正在提交申请...' });
try {
await withdrawCommission(user.value.id || 1001, amount, { channel: 'WECHAT' });
user.value.commission = (currentComm - amount).toFixed(2);
distWithdrawAmount.value = '';
uni.hideLoading();
uni.showToast({ title: '提现申请已提交', icon: 'success' });
await loadDistributionData();
} catch (err) {
uni.hideLoading();
uni.showToast({ title: err.message || '提现提交失败', icon: 'none' });
} finally {
submittingDistWithdraw.value = false;
}
};
// 大神实名入驻认证已全面升级重构为独立专享页面 /pages/expert/apply
const showExpertCertModal = ref(false);
const applyExpert = () => {
if (!ensureLoggedIn()) return;
uni.navigateTo({
url: '/pages/expert/apply'
});
};
const contactService = () => {
const cs = platformConfigs.value.customer_service || {};
const hotline = cs.hotline || '400-888-6666';
const wechat = cs.wechat || 'peiwan_vip_kefu';
const cleanPhone = hotline.replace(/[^\d]/g, '');
uni.showActionSheet({
itemList: [
`拨打官方服务热线 (${hotline})`,
`复制平台 VIP 客服微信号 (${wechat})`,
'查看平台官方安全指引'
],
success: (res) => {
if (res.tapIndex === 0) {
uni.makePhoneCall({
phoneNumber: cleanPhone,
fail: () => {
uni.showToast({ title: `服务热线: ${hotline}`, icon: 'none' });
}
});
} else if (res.tapIndex === 1) {
uni.setClipboardData({
data: wechat,
success: () => {
uni.showToast({ title: '官方客服微信号已复制', icon: 'success' });
}
});
} else {
openNotice();
}
}
});
};
const openNotice = () => {
// 同步触发微信订阅授权(必须保留点击手势,不能先 await 网络);再展示平台须知。
const subResult = typeof uni.requestSubscribeMessage === 'function' ? requestSubscribeAll() : null;
const notice = platformConfigs.value.safety_notice || {};
const title = notice.title || '平台官方公告与指引';
let content = '【安全履约须知】\n1. 为保障搭子与陪伴师人身与财产安全,线下约局须在合规公开商业街区进行。\n2. 现场碰面后请出示 4 位数字核销码进行签到确认。\n3. 平台提供 7x24 小时争议仲裁与资金托管保障服务。';
if (Array.isArray(notice.points) && notice.points.length > 0) {
content = notice.points.map((p, idx) => `${idx + 1}. ${p}`).join('\n');
}
uni.showModal({
title,
content,
showCancel: false,
confirmText: '我知道了',
confirmColor: '#6366F1'
});
if (subResult) {
subResult.then((r) => {
if (!r || !r.supported) return;
if (r.noTemplates || !r.tmplIds || r.tmplIds.length === 0) {
uni.showToast({ title: '后台未配置订阅消息模板', icon: 'none' });
return;
}
const accepted = (r.accepted || []).length > 0;
noticeSubscribe.value = accepted;
uni.setStorageSync('notice_subscribe', accepted ? '1' : '0');
uni.showToast({ title: accepted ? '已开启消息提醒' : '未获得提醒授权', icon: 'none' });
});
}
};
const openFaq = () => {
uni.navigateTo({
url: '/pages/user/help-faq',
fail: () => {
uni.showToast({ title: '页面打开失败,请稍后重试', icon: 'none' });
}
});
};
const openAbout = () => {
// 进入独立协议页面(页内可切换"用户服务协议 / 隐私保护指引"),不再使用弹窗选择
uni.navigateTo({
url: '/pages/common/protocol?type=service',
fail: () => {
const proto = platformConfigs.value.platform_protocol || {};
uni.showModal({
title: proto.userAgreementTitle || '用户服务协议',
content: proto.userAgreementContent || '平台遵循合法合规与安全原则,所有同城活动履约均须在公开透明街区展开。',
showCancel: false
});
}
});
};
const navTo = (url) => {
if (!ensureLoggedIn()) return;
if (url.startsWith('/pages/activity/list')) {
if (url.includes('tab=')) {
const tab = url.split('tab=')[1].split('&')[0];
uni.setStorageSync('ACTIVITY_ACTIVE_TAB', tab);
}
uni.switchTab({ url: '/pages/activity/list' });
} else if (url === '/pages/order/list') {
uni.setStorageSync('ORDER_PAGE_FROM', '/pages/user/index');
uni.switchTab({ url });
} else {
uni.navigateTo({ url });
}
};
</script>
<style lang="scss">
.user-container {
min-height: 100vh;
background-color: #0A0F1D;
padding: var(--safe-header-gap, 36rpx) 32rpx calc(160rpx + env(safe-area-inset-bottom));
}
.profile-card {
display: flex;
align-items: center;
margin-bottom: 28rpx;
.user-avatar {
width: 120rpx;
height: 120rpx;
border-radius: 60rpx;
border: 4rpx solid #6366F1;
margin-right: 24rpx;
flex-shrink: 0;
cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.15s ease;
&:active {
transform: scale(0.95);
box-shadow: 0 0 16rpx rgba(99, 102, 241, 0.4);
}
}
.user-info {
flex: 1;
min-width: 0;
.user-top-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12rpx;
margin-bottom: 10rpx;
.name-row {
display: flex;
align-items: center;
gap: 12rpx;
min-width: 0;
flex: 1;
cursor: pointer;
transition: opacity 0.15s ease;
&:active {
opacity: 0.75;
}
.user-name {
font-size: 32rpx;
font-weight: 700;
color: #F8FAFC;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.vip-badge {
font-size: 18rpx;
background: linear-gradient(135deg, #F59E0B, #D97706);
color: #FFF;
padding: 2rpx 10rpx;
border-radius: 8rpx;
font-weight: 600;
white-space: nowrap;
flex-shrink: 0;
}
}
.header-actions {
display: flex;
align-items: center;
gap: 12rpx;
flex-shrink: 0;
.theme-quick-switch {
height: 56rpx;
padding: 4rpx 6rpx;
background: #151D30;
border-radius: 28rpx;
display: flex;
align-items: center;
gap: 6rpx;
border: 1px solid rgba(255, 255, 255, 0.1);
box-sizing: border-box;
.switch-icon-btn {
width: 46rpx;
height: 46rpx;
border-radius: 23rpx;
display: flex;
align-items: center;
justify-content: center;
opacity: 0.35;
transition: all 0.25s ease;
.theme-icon-svg {
width: 26rpx;
height: 26rpx;
}
&.active {
opacity: 1;
}
&.moon-btn.active {
background: rgba(99, 102, 241, 0.25);
border: 1px solid rgba(129, 140, 248, 0.5);
box-shadow: 0 0 10rpx rgba(99, 102, 241, 0.4);
}
&.sun-btn.active {
background: rgba(245, 158, 11, 0.25);
border: 1px solid rgba(245, 158, 11, 0.5);
box-shadow: 0 0 10rpx rgba(245, 158, 11, 0.4);
}
}
}
.edit-btn {
width: 56rpx;
height: 56rpx;
background: #151D30;
border-radius: 28rpx;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid rgba(255, 255, 255, 0.08);
.edit-svg {
width: 28rpx;
height: 28rpx;
opacity: 0.8;
}
}
}
}
.user-uid {
font-size: 22rpx;
color: #64748B;
font-family: monospace;
cursor: pointer;
display: inline-block;
&:active {
opacity: 0.7;
}
}
}
}
.role-switch-card {
position: relative;
border-radius: 24rpx;
padding: 28rpx;
margin-bottom: 28rpx;
overflow: hidden;
box-shadow: 0 8rpx 28rpx rgba(99, 102, 241, 0.35);
&::before {
content: '';
position: absolute;
inset: -50%;
background: conic-gradient(from 0deg, transparent 0%, #6366F1 25%, #10B981 50%, #6366F1 75%, transparent 100%);
animation: glowSpin 5s linear infinite;
z-index: 0;
}
&::after {
content: '';
position: absolute;
inset: 2rpx;
background: linear-gradient(135deg, #1E1B4B 0%, #0F172A 100%);
border-radius: 22rpx;
z-index: 1;
}
.role-content {
position: relative;
z-index: 2;
display: flex;
justify-content: space-between;
align-items: center;
.role-left {
flex: 1;
margin-right: 20rpx;
.role-title-row {
display: flex;
align-items: center;
gap: 10rpx;
margin-bottom: 6rpx;
.role-dot {
width: 12rpx;
height: 12rpx;
border-radius: 50%;
background: #6366F1;
box-shadow: 0 0 8rpx #6366F1;
&.expert {
background: #10B981;
box-shadow: 0 0 8rpx #10B981;
}
}
.current-role-tag {
font-size: 28rpx;
font-weight: 700;
color: #FFFFFF;
}
}
.role-sub {
font-size: 20rpx;
color: #94A3B8;
line-height: 1.4;
}
}
.btn-switch-role {
background: linear-gradient(135deg, #6366F1 0%, #8B5CF6 100%);
color: #FFF;
font-size: 22rpx;
font-weight: 700;
border-radius: 32rpx;
padding: 0 24rpx;
height: 64rpx;
line-height: 64rpx;
margin: 0;
box-shadow: 0 4rpx 16rpx rgba(99, 102, 241, 0.4);
}
}
}
.wallet-card {
background-color: #151D30;
border-radius: 24rpx;
padding: 28rpx;
margin-bottom: 24rpx;
border: 1px solid rgba(255, 255, 255, 0.06);
.wallet-head {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.wallet-title {
font-size: 28rpx;
font-weight: 700;
color: #F8FAFC;
}
.wallet-detail {
font-size: 22rpx;
color: #64748B;
}
}
.asset-grid {
display: flex;
align-items: center;
justify-content: space-around;
.asset-col {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
.asset-label {
font-size: 22rpx;
color: #94A3B8;
margin-bottom: 8rpx;
}
.asset-val {
font-size: 36rpx;
font-weight: 700;
margin-bottom: 14rpx;
font-variant-numeric: tabular-nums;
&.green-val {
color: #10B981;
}
&.gold-val {
color: #F59E0B;
}
}
.asset-btn-group {
display: flex;
align-items: center;
gap: 12rpx;
}
.asset-btn {
font-size: 20rpx;
padding: 0 20rpx;
height: 48rpx;
line-height: 46rpx;
border-radius: 24rpx;
margin: 0;
&.recharge {
background: rgba(16, 185, 129, 0.15);
color: #10B981;
border: 1px solid rgba(16, 185, 129, 0.3);
}
&.withdraw {
background: rgba(245, 158, 11, 0.15);
color: #F59E0B;
border: 1px solid rgba(245, 158, 11, 0.3);
}
&.records {
background: rgba(99, 102, 241, 0.15);
color: #818CF8;
border: 1px solid rgba(99, 102, 241, 0.3);
}
}
}
.asset-divider {
width: 1px;
height: 80rpx;
background: rgba(255, 255, 255, 0.08);
}
}
}
.menu-grid-card {
display: flex;
justify-content: space-between;
background-color: #151D30;
border-radius: 24rpx;
padding: 24rpx 16rpx;
margin-bottom: 24rpx;
border: 1px solid rgba(255, 255, 255, 0.06);
.menu-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
.menu-icon {
width: 76rpx;
height: 76rpx;
border-radius: 22rpx;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 10rpx;
.menu-svg {
width: 38rpx;
height: 38rpx;
}
&.bg-green { background: rgba(16, 185, 129, 0.15); border: 1px solid rgba(16, 185, 129, 0.3); }
&.bg-purple { background: rgba(139, 92, 246, 0.15); border: 1px solid rgba(139, 92, 246, 0.3); }
&.bg-blue { background: rgba(99, 102, 241, 0.15); border: 1px solid rgba(99, 102, 241, 0.3); }
&.bg-orange { background: rgba(245, 158, 11, 0.15); border: 1px solid rgba(245, 158, 11, 0.3); }
&.bg-indigo { background: rgba(99, 102, 241, 0.2); border: 1px solid rgba(99, 102, 241, 0.4); }
}
.menu-title {
font-size: 24rpx;
color: #F8FAFC;
font-weight: 600;
margin-bottom: 4rpx;
}
.menu-desc {
font-size: 18rpx;
color: #64748B;
}
}
}
.list-menu-card {
background-color: #151D30;
border-radius: 24rpx;
padding: 8rpx 28rpx;
border: 1px solid rgba(255, 255, 255, 0.06);
.list-row {
display: flex;
align-items: center;
padding: 26rpx 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
&:last-child {
border-bottom: none;
}
.row-svg {
width: 32rpx;
height: 32rpx;
margin-right: 20rpx;
opacity: 0.85;
}
.row-label {
flex: 1;
font-size: 26rpx;
color: #E2E8F0;
}
.row-arrow-svg {
width: 28rpx;
height: 28rpx;
opacity: 0.45;
}
}
}
/* 个人资料修改弹窗 */
.profile-edit-modal-mask {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.65);
backdrop-filter: blur(8px);
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
padding: 40rpx;
}
.profile-edit-modal {
width: 100%;
max-width: 620rpx;
background: #151D30;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 32rpx;
overflow: hidden;
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.5);
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 32rpx 36rpx 20rpx;
.modal-title {
font-size: 32rpx;
font-weight: 700;
color: #FFFFFF;
}
.btn-close {
width: 44rpx;
height: 44rpx;
display: flex;
align-items: center;
justify-content: center;
.close-svg {
width: 32rpx;
height: 32rpx;
opacity: 0.6;
}
}
}
.modal-body {
padding: 20rpx 36rpx 32rpx;
.edit-avatar-section {
display: flex;
align-items: center;
gap: 24rpx;
margin-bottom: 32rpx;
padding-bottom: 24rpx;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
.avatar-preview {
width: 110rpx;
height: 110rpx;
border-radius: 50%;
border: 4rpx solid #6366F1;
flex-shrink: 0;
}
.avatar-meta {
flex: 1;
.avatar-label-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
.avatar-label {
font-size: 22rpx;
color: #94A3B8;
display: block;
}
.avatar-action-links {
display: flex;
align-items: center;
gap: 12rpx;
.btn-wechat-choose {
margin: 0;
padding: 4rpx 14rpx;
font-size: 22rpx;
color: #10B981;
font-weight: 600;
background: rgba(16, 185, 129, 0.12);
border: 1px solid rgba(16, 185, 129, 0.3);
border-radius: 8rpx;
line-height: 1.4;
cursor: pointer;
&::after {
display: none;
border: none;
}
}
.btn-custom-upload {
font-size: 22rpx;
color: #6366F1;
font-weight: 600;
padding: 4rpx 14rpx;
background: rgba(99, 102, 241, 0.12);
border: 1px solid rgba(99, 102, 241, 0.3);
border-radius: 8rpx;
cursor: pointer;
line-height: 1.4;
}
}
}
.preset-avatars-row {
display: flex;
gap: 16rpx;
.preset-avatar-item {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
border: 2rpx solid transparent;
opacity: 0.7;
transition: all 0.2s ease;
&.selected {
border-color: #6366F1;
opacity: 1;
transform: scale(1.1);
box-shadow: 0 0 12rpx rgba(99, 102, 241, 0.5);
}
}
}
}
}
.edit-field {
margin-bottom: 24rpx;
.field-label-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
.field-label {
margin-bottom: 0;
}
.field-tip-text {
font-size: 20rpx;
color: #64748B;
}
}
.field-label {
font-size: 24rpx;
color: #94A3B8;
margin-bottom: 10rpx;
display: block;
}
.field-input {
width: 100%;
height: 80rpx;
background: #0A0F1D;
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 16rpx;
padding: 0 24rpx;
font-size: 28rpx;
color: #F8FAFC;
box-sizing: border-box;
}
.field-placeholder {
color: #475569;
font-size: 26rpx;
}
}
}
.modal-footer {
display: flex;
gap: 20rpx;
padding: 0 36rpx 36rpx;
.btn-modal {
flex: 1;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
font-size: 28rpx;
font-weight: 600;
text-align: center;
margin: 0;
&::after { border: none; }
&.btn-cancel {
background: rgba(255, 255, 255, 0.08);
color: #94A3B8;
}
&.btn-save {
background: linear-gradient(135deg, #6366F1, #8B5CF6);
color: #FFFFFF;
box-shadow: 0 6rpx 20rpx rgba(99, 102, 241, 0.4);
}
}
}
}
.user-container.theme-warm {
background-color: #FDFBF7;
.profile-card {
.user-avatar {
border-color: #EA580C;
}
.user-info .name-row .user-name {
color: #1C1917;
}
.user-info .user-uid {
color: #78716C;
}
.header-actions {
.theme-quick-switch {
background: #FFFFFF;
border-color: #E7E2D8;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.04);
.switch-icon-btn {
opacity: 0.35;
&.active {
opacity: 1;
}
&.moon-btn.active {
background: rgba(99, 102, 241, 0.15);
border: 1px solid rgba(99, 102, 241, 0.3);
box-shadow: 0 2rpx 8rpx rgba(99, 102, 241, 0.2);
}
&.sun-btn.active {
background: #FFF7ED;
border: 1px solid rgba(234, 88, 12, 0.35);
box-shadow: 0 2rpx 10rpx rgba(234, 88, 12, 0.25);
}
}
}
.edit-btn {
background: #FFFFFF;
border-color: #E7E2D8;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.04);
.edit-svg {
opacity: 0.75;
}
}
}
}
.role-switch-card, .identity-banner {
background-color: #FFFFFF;
border: 1px solid #F0ECE4;
box-shadow: 0 4rpx 20rpx rgba(234, 88, 12, 0.12);
&::after {
background: linear-gradient(135deg, #FFFFFF 0%, #FDFBF7 100%);
border-radius: 22rpx;
}
&::before {
background: conic-gradient(from 0deg, transparent 0%, #EA580C 25%, #F59E0B 50%, #EA580C 75%, transparent 100%);
}
.role-content .role-left {
.current-role-tag {
color: #1C1917;
}
.role-sub {
color: #78716C;
}
}
.btn-switch-role {
background: linear-gradient(135deg, #F97316, #EA580C);
color: #FFFFFF;
box-shadow: 0 4rpx 16rpx rgba(234, 88, 12, 0.35);
}
}
.wallet-card, .menu-grid-card, .list-menu-card {
background-color: #FFFFFF;
border: 1px solid #F0ECE4;
box-shadow: 0 4rpx 20rpx rgba(28, 25, 23, 0.05);
}
.wallet-card {
.wallet-title { color: #1C1917; }
.asset-label { color: #78716C; }
.asset-val.gold-val { color: #D97706; }
.asset-btn.withdraw {
background: rgba(217, 119, 6, 0.1);
color: #D97706;
border-color: rgba(217, 119, 6, 0.25);
}
}
.menu-grid-card .menu-item {
.menu-title { color: #1C1917; }
.menu-desc { color: #78716C; }
}
.list-menu-card .list-row {
border-bottom-color: #F5F2EC;
.row-label { color: #1C1917; }
}
.profile-edit-modal {
background: #FFFFFF;
border: 1px solid #EAE5DC;
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.1);
.modal-header .modal-title {
color: #1C1917;
}
.modal-body {
.edit-avatar-section {
border-bottom-color: #F5F2EC;
.avatar-preview {
border-color: #EA580C;
}
.avatar-meta {
.avatar-action-links {
.btn-wechat-choose {
color: #059669;
background: #ECFDF5;
border-color: rgba(5, 150, 105, 0.3);
}
.btn-custom-upload {
color: #EA580C;
background: #FFF7ED;
border-color: rgba(234, 88, 12, 0.3);
}
}
.preset-avatars-row .preset-avatar-item.selected {
border-color: #EA580C;
box-shadow: 0 0 12rpx rgba(234, 88, 12, 0.4);
}
}
}
.edit-field {
.field-label-row {
.field-label {
color: #78716C;
}
.field-tip-text {
color: #A8A29E;
}
}
.field-label {
color: #78716C;
}
.field-input {
background: #FDFBF7;
border-color: #E7E2D8;
color: #1C1917;
}
.field-placeholder {
color: #A8A29E;
}
}
}
.modal-footer {
.btn-cancel {
background: #F5F2EC;
color: #78716C;
}
.btn-save {
background: linear-gradient(135deg, #EA580C, #F97316);
color: #FFFFFF;
box-shadow: 0 6rpx 20rpx rgba(234, 88, 12, 0.35);
}
}
}
}
.guest-badge {
font-size: 20rpx;
color: #94A3B8;
background: rgba(148, 163, 184, 0.15);
border: 1px solid rgba(148, 163, 184, 0.3);
padding: 4rpx 14rpx;
border-radius: 20rpx;
font-weight: 500;
}
.account-actions-card {
margin-top: 24rpx;
margin-bottom: 30rpx;
.account-btn-group {
display: flex;
gap: 20rpx;
.btn-switch-account {
flex: 1;
height: 84rpx;
line-height: 84rpx;
background: rgba(99, 102, 241, 0.12);
border: 1px solid rgba(99, 102, 241, 0.3);
color: #818CF8;
font-size: 26rpx;
font-weight: 600;
border-radius: 24rpx;
}
.btn-logout {
flex: 1;
height: 84rpx;
line-height: 84rpx;
background: rgba(239, 68, 68, 0.12);
border: 1px solid rgba(239, 68, 68, 0.3);
color: #F87171;
font-size: 26rpx;
font-weight: 600;
border-radius: 24rpx;
}
}
&.not-logged {
.btn-primary-login {
width: 100%;
height: 88rpx;
line-height: 88rpx;
background: linear-gradient(135deg, #6366F1, #8B5CF6);
color: #FFFFFF;
font-size: 28rpx;
font-weight: 700;
border-radius: 24rpx;
box-shadow: 0 4rpx 20rpx rgba(99, 102, 241, 0.35);
}
}
}
.theme-warm {
.guest-badge {
color: #78716C;
background: #F5F2EC;
border-color: #E7E5E4;
}
.account-actions-card {
.account-btn-group {
.btn-switch-account {
background: rgba(234, 88, 12, 0.08);
border-color: rgba(234, 88, 12, 0.25);
color: #EA580C;
}
.btn-logout {
background: #FEE2E2;
border-color: #FCA5A5;
color: #DC2626;
}
}
&.not-logged {
.btn-primary-login {
background: linear-gradient(135deg, #F97316 0%, #EA580C 100%);
box-shadow: 0 4rpx 20rpx rgba(234, 88, 12, 0.35);
}
}
}
.login-modal {
background: #FFFFFF;
border-color: #F0ECE4;
box-shadow: 0 20rpx 60rpx rgba(28, 25, 23, 0.15);
.modal-header .modal-title {
color: #1C1917;
}
.demo-accounts-wrap {
.demo-tips {
color: #78716C;
}
.demo-account-item {
background: #FAFAF9;
border-color: #E7E5E4;
&.current {
border-color: #EA580C;
background: rgba(234, 88, 12, 0.08);
}
.demo-info {
.demo-title-row .demo-name {
color: #1C1917;
}
.demo-desc {
color: #78716C;
}
}
.demo-action-btn {
color: #EA580C;
background: rgba(234, 88, 12, 0.12);
}
}
}
}
}
.withdraw-modal-box {
max-width: 640rpx;
.channel-tabs-row {
display: flex;
background: #0F172A;
border-radius: 16rpx;
padding: 6rpx;
margin-bottom: 24rpx;
gap: 8rpx;
.channel-pill {
flex: 1;
text-align: center;
padding: 14rpx 0;
font-size: 24rpx;
font-weight: 600;
color: #94A3B8;
border-radius: 12rpx;
transition: all 0.2s ease;
&.active {
background: linear-gradient(135deg, #10B981, #059669);
color: #FFFFFF;
box-shadow: 0 4rpx 12rpx rgba(16, 185, 129, 0.35);
}
}
}
.field-title-row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12rpx;
.field-tip {
font-size: 20rpx;
color: #94A3B8;
}
}
.amount-input-wrap {
display: flex;
align-items: center;
background: #0F172A;
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16rpx;
padding: 0 20rpx;
height: 84rpx;
.currency-symbol {
font-size: 32rpx;
font-weight: 700;
color: #10B981;
margin-right: 12rpx;
}
.amount-val-input {
flex: 1;
font-size: 32rpx;
font-weight: 700;
color: #F8FAFC;
}
.btn-all-in {
font-size: 22rpx;
font-weight: 600;
color: #10B981;
padding: 8rpx 16rpx;
background: rgba(16, 185, 129, 0.12);
border-radius: 10rpx;
}
}
.channel-hint-card {
background: rgba(16, 185, 129, 0.08);
border: 1px dashed rgba(16, 185, 129, 0.3);
border-radius: 14rpx;
padding: 16rpx;
margin-top: 16rpx;
.hint-text {
font-size: 20rpx;
color: #34D399;
line-height: 1.5;
}
}
}
.withdraw-records-modal-box {
max-width: 660rpx;
max-height: 80vh;
.records-modal-scroll {
max-height: 560rpx;
padding-right: 8rpx;
.wd-card-row {
background: #0F172A;
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 16rpx;
padding: 18rpx 20rpx;
margin-bottom: 16rpx;
.wd-row-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10rpx;
.wd-no {
font-size: 20rpx;
color: #64748B;
font-family: monospace;
}
.wd-badge {
font-size: 20rpx;
padding: 2rpx 12rpx;
border-radius: 8rpx;
font-weight: 600;
&.pending {
background: rgba(245, 158, 11, 0.15);
color: #F59E0B;
}
&.success {
background: rgba(16, 185, 129, 0.15);
color: #10B981;
}
&.rejected {
background: rgba(239, 68, 68, 0.15);
color: #EF4444;
}
}
}
.wd-row-center {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 8rpx;
.wd-val {
font-size: 32rpx;
font-weight: 700;
color: #F8FAFC;
}
.wd-ch {
font-size: 22rpx;
color: #94A3B8;
}
}
.wd-row-bot {
display: flex;
justify-content: space-between;
align-items: center;
.wd-time {
font-size: 18rpx;
color: #64748B;
}
.wd-reason {
font-size: 18rpx;
color: #EF4444;
}
}
}
}
.empty-records-box {
padding: 60rpx 20rpx;
text-align: center;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.empty-icon-svg {
width: 64rpx;
height: 64rpx;
margin-bottom: 16rpx;
opacity: 0.45;
}
.empty-txt {
font-size: 24rpx;
color: #64748B;
}
}
}
.user-signature-text {
font-size: 22rpx;
color: #94A3B8;
margin-top: 8rpx;
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 480rpx;
}
.gender-pill-group {
display: flex;
gap: 16rpx;
margin-top: 10rpx;
.gender-pill {
flex: 1;
text-align: center;
padding: 16rpx 0;
font-size: 26rpx;
color: #94A3B8;
background-color: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 14rpx;
transition: all 0.2s ease;
&.active {
color: #FFFFFF;
background: linear-gradient(135deg, rgba(99, 102, 241, 0.3) 0%, rgba(139, 92, 246, 0.4) 100%);
border-color: #6366F1;
font-weight: 600;
}
}
}
.uid-phone-row {
display: flex;
align-items: center;
gap: 12rpx;
margin-top: 4rpx;
.user-phone-tag {
font-size: 20rpx;
color: #6366F1;
background: rgba(99, 102, 241, 0.12);
border: 1px solid rgba(99, 102, 241, 0.25);
padding: 2rpx 10rpx;
border-radius: 8rpx;
}
}
.row-badge {
margin-left: auto;
margin-right: 8rpx;
font-size: 20rpx;
color: #F59E0B;
background: rgba(245, 158, 11, 0.15);
border: 1px solid rgba(245, 158, 11, 0.3);
padding: 2rpx 12rpx;
border-radius: 16rpx;
font-weight: 600;
}
// 3. 分销管理弹窗样式
.dist-modal-box {
max-width: 680rpx;
max-height: 88vh;
.dist-summary-banner {
display: flex;
justify-content: space-around;
align-items: center;
background: linear-gradient(135deg, rgba(99, 102, 241, 0.2), rgba(139, 92, 246, 0.15));
border: 1px solid rgba(99, 102, 241, 0.3);
border-radius: 20rpx;
padding: 20rpx 10rpx;
margin-bottom: 20rpx;
.dist-stat-col {
display: flex;
flex-direction: column;
align-items: center;
gap: 6rpx;
.dist-stat-val {
font-size: 30rpx;
font-weight: 700;
color: #10B981;
}
.dist-stat-lbl {
font-size: 20rpx;
color: #94A3B8;
}
.code-box {
display: flex;
align-items: center;
gap: 6rpx;
background: rgba(99, 102, 241, 0.3);
border-radius: 8rpx;
padding: 2rpx 10rpx;
.code-txt {
font-size: 24rpx;
font-weight: 700;
color: #FFFFFF;
font-family: monospace;
}
.copy-tag {
font-size: 18rpx;
color: #818CF8;
}
}
}
.dist-stat-divider {
width: 1px;
height: 48rpx;
background: rgba(255, 255, 255, 0.1);
}
}
.dist-tabs-row {
display: flex;
background: #0F172A;
border-radius: 16rpx;
padding: 6rpx;
margin-bottom: 16rpx;
gap: 6rpx;
.dist-tab-pill {
flex: 1;
text-align: center;
padding: 12rpx 0;
font-size: 22rpx;
color: #94A3B8;
border-radius: 10rpx;
transition: all 0.2s;
&.active {
background: #6366F1;
color: #FFFFFF;
font-weight: 600;
}
}
}
.dist-modal-body {
padding: 0 0 20rpx;
.tab-pane-poster {
display: flex;
flex-direction: column;
align-items: center;
.poster-preview-card {
width: 100%;
background: linear-gradient(180deg, #1E1B4B 0%, #0F172A 100%);
border: 1px solid rgba(99, 102, 241, 0.3);
border-radius: 20rpx;
padding: 32rpx 24rpx;
box-sizing: border-box;
text-align: center;
margin-bottom: 20rpx;
.poster-badge {
display: inline-block;
font-size: 18rpx;
color: #818CF8;
background: rgba(99, 102, 241, 0.2);
padding: 2rpx 14rpx;
border-radius: 12rpx;
margin-bottom: 12rpx;
}
.poster-hero-title {
font-size: 32rpx;
font-weight: 700;
color: #F8FAFC;
display: block;
margin-bottom: 6rpx;
}
.poster-hero-sub {
font-size: 20rpx;
color: #94A3B8;
display: block;
margin-bottom: 24rpx;
}
.suncode-box {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20rpx;
.suncode-ring {
position: relative;
width: 160rpx;
height: 160rpx;
border-radius: 80rpx;
border: 2px dashed #6366F1;
display: flex;
align-items: center;
justify-content: center;
background: rgba(99, 102, 241, 0.08);
.suncode-center {
width: 100rpx;
height: 100rpx;
border-radius: 50rpx;
overflow: hidden;
border: 2rpx solid #6366F1;
.suncode-avatar {
width: 100%;
height: 100%;
}
}
}
.suncode-hint {
font-size: 18rpx;
color: #64748B;
margin-top: 10rpx;
}
}
.poster-footer-code {
background: rgba(255, 255, 255, 0.04);
border-radius: 12rpx;
padding: 10rpx;
display: inline-flex;
align-items: baseline;
gap: 6rpx;
.lbl {
font-size: 20rpx;
color: #94A3B8;
}
.val {
font-size: 24rpx;
font-weight: 700;
color: #F59E0B;
font-family: monospace;
}
}
}
.poster-actions-row {
width: 100%;
display: flex;
gap: 16rpx;
.btn-poster-action {
flex: 1;
height: 72rpx;
line-height: 70rpx;
font-size: 24rpx;
font-weight: 600;
border-radius: 36rpx;
margin: 0;
&.secondary {
background: rgba(255, 255, 255, 0.08);
color: #94A3B8;
}
&.primary {
background: linear-gradient(135deg, #6366F1, #8B5CF6);
color: #FFFFFF;
}
}
}
}
.tab-pane-team {
.team-subtabs {
display: flex;
gap: 12rpx;
margin-bottom: 16rpx;
.subtab-item {
flex: 1;
font-size: 20rpx;
text-align: center;
padding: 8rpx 0;
border-radius: 8rpx;
color: #94A3B8;
background: rgba(255, 255, 255, 0.04);
&.active {
color: #6366F1;
background: rgba(99, 102, 241, 0.15);
font-weight: 600;
}
}
}
.team-list-scroll {
max-height: 520rpx;
.team-member-row {
display: flex;
align-items: center;
background: #0F172A;
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 14rpx;
padding: 16rpx 20rpx;
margin-bottom: 12rpx;
.m-avatar {
width: 72rpx;
height: 72rpx;
border-radius: 36rpx;
margin-right: 16rpx;
}
.m-info {
flex: 1;
.m-top {
display: flex;
align-items: center;
gap: 8rpx;
margin-bottom: 4rpx;
.m-name {
font-size: 24rpx;
font-weight: 600;
color: #F8FAFC;
}
.m-level-badge {
font-size: 16rpx;
color: #818CF8;
background: rgba(99, 102, 241, 0.15);
padding: 2rpx 8rpx;
border-radius: 6rpx;
}
}
.m-time {
font-size: 18rpx;
color: #64748B;
}
}
.m-contribute {
text-align: right;
.m-val {
font-size: 26rpx;
font-weight: 700;
color: #10B981;
display: block;
}
.m-lbl {
font-size: 18rpx;
color: #64748B;
}
}
}
}
}
.tab-pane-records {
.records-list-scroll {
max-height: 540rpx;
.record-card {
background: #0F172A;
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 14rpx;
padding: 16rpx 20rpx;
margin-bottom: 12rpx;
.rec-top {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8rpx;
.rec-sn {
font-size: 20rpx;
color: #64748B;
font-family: monospace;
}
.rec-status-tag {
font-size: 18rpx;
color: #10B981;
background: rgba(16, 185, 129, 0.12);
padding: 2rpx 8rpx;
border-radius: 6rpx;
}
}
.rec-mid {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 8rpx;
.rec-from {
display: flex;
align-items: baseline;
gap: 8rpx;
.rec-name {
font-size: 24rpx;
font-weight: 600;
color: #F8FAFC;
}
.rec-type {
font-size: 18rpx;
color: #818CF8;
}
}
.rec-amount-box {
text-align: right;
.rec-comm {
font-size: 28rpx;
font-weight: 700;
color: #F59E0B;
display: block;
}
.rec-rate {
font-size: 18rpx;
color: #64748B;
}
}
}
.rec-bot {
display: flex;
justify-content: space-between;
font-size: 18rpx;
color: #64748B;
}
}
}
}
.tab-pane-withdraw {
.dist-wd-box {
background: #0F172A;
border-radius: 16rpx;
padding: 24rpx;
.dist-wd-label {
font-size: 22rpx;
color: #94A3B8;
display: block;
margin-bottom: 12rpx;
}
.dist-input-row {
display: flex;
align-items: center;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12rpx;
padding: 0 16rpx;
height: 80rpx;
margin-bottom: 16rpx;
.symbol {
font-size: 32rpx;
font-weight: 700;
color: #10B981;
margin-right: 8rpx;
}
.dist-amount-input {
flex: 1;
font-size: 30rpx;
color: #F8FAFC;
}
.btn-all {
font-size: 22rpx;
color: #6366F1;
font-weight: 600;
}
}
.dist-wd-tip {
margin-bottom: 24rpx;
.tip-txt {
font-size: 20rpx;
color: #64748B;
line-height: 1.4;
}
}
.btn-submit-dist-wd {
background: linear-gradient(135deg, #10B981, #059669);
color: #FFFFFF;
font-size: 26rpx;
font-weight: 600;
height: 76rpx;
line-height: 76rpx;
border-radius: 38rpx;
margin: 0;
}
}
}
}
}
// 暖色模式下的适配
.theme-warm {
.uid-phone-row {
.user-phone-tag {
color: #EA580C;
background: #FFF7ED;
border-color: #FDBA74;
}
}
.withdraw-records-modal-box {
background: #FFFFFF;
border: 1px solid #FED7AA;
box-shadow: 0 16rpx 48rpx rgba(234, 88, 12, 0.08);
.modal-header .modal-title {
color: #1C1917;
}
.records-modal-scroll .wd-card-row {
background: #FAFAF9;
border-color: #E7E5E4;
.wd-row-center .wd-val { color: #1C1917; }
.wd-row-top .wd-no { color: #78716C; }
}
.empty-records-box {
.empty-icon-svg {
opacity: 0.6;
}
.empty-txt {
color: #78716C;
}
}
}
.dist-modal-box {
.dist-summary-banner {
background: linear-gradient(135deg, #FFF7ED, #FFEDD5);
border-color: #FDBA74;
}
.dist-tabs-row {
background: #F5F2EC;
.dist-tab-pill.active {
background: #EA580C;
}
}
.tab-pane-poster .poster-preview-card {
background: linear-gradient(180deg, #FFF7ED 0%, #FAFAF9 100%);
border-color: #FDBA74;
.poster-hero-title {
color: #1C1917;
}
}
}
}
</style>