feat(auth): create dedicated official standard WeChat login page and remove popup modal

这个提交包含在:
xcbyy
2026-10-10 17:48:35 +08:00
父节点 d7460f898d
当前提交 70623193a1
共有 4 个文件被更改,包括 841 次插入 和 262 次删除

查看文件

@@ -19,6 +19,15 @@
"backgroundColor": "#0A0F1D"
}
},
{
"path": "pages/auth/login",
"style": {
"navigationBarTitleText": "账号登录与注册",
"navigationBarBackgroundColor": "#0A0F1D",
"navigationBarTextStyle": "white",
"backgroundColor": "#0A0F1D"
}
},
{
"path": "pages/activity/list",
"style": {

查看文件

@@ -0,0 +1,784 @@
<template>
<view class="auth-login-page" :class="{ 'theme-warm': currentThemeKey === 'warm' }">
<!-- 顶部品牌视觉与应用 Slogan -->
<view class="brand-header">
<view class="brand-logo-wrap">
<image class="brand-logo-img" :src="APP_LOGO" mode="aspectFit" />
</view>
<text class="brand-app-name">同城陪玩生活圈</text>
<text class="brand-slogan">年轻人的同城搭子与温暖陪伴社交平台</text>
</view>
<!-- 微信小程序官方标准:头像与昵称授权填写卡片 -->
<view class="auth-profile-card">
<view class="profile-card-header">
<text class="profile-card-title">完善个人主页资料</text>
<text class="profile-card-tip">遵循微信小程序用户资料填写规范</text>
</view>
<!-- 微信官方 open-type="chooseAvatar" 原生头像选择 -->
<view class="avatar-choose-row">
<button
class="avatar-picker-btn btn-active"
open-type="chooseAvatar"
@chooseavatar="onChooseAvatar"
>
<image class="chosen-avatar" :src="userForm.avatar || DEFAULT_AVATAR" mode="aspectFill" />
<view class="avatar-badge">
<image class="camera-icon-svg" :src="ICONS.camera" mode="aspectFit" />
</view>
</button>
<view class="avatar-tip-wrap">
<text class="avatar-tip-title">点击设置微信头像</text>
<text class="avatar-tip-sub">轻触一键拉起微信头像快速选用</text>
</view>
</view>
<!-- 微信官方 type="nickname" 原生昵称输入框 -->
<view class="nickname-input-row">
<text class="input-label">昵称</text>
<input
class="nickname-input"
type="nickname"
v-model="userForm.nickname"
placeholder="点击快速填入或输入昵称"
placeholder-class="ph-style"
/>
</view>
</view>
<!-- 微信手机号授权快捷登录主操作区 (微信官方推荐格式) -->
<view class="main-action-section">
<button
class="btn-wechat-primary btn-active"
open-type="getPhoneNumber"
@getphonenumber="handleGetPhoneNumber"
@click="handleFallbackLogin"
>
<image class="wechat-icon-svg" :src="ICONS.shield" mode="aspectFit" />
<text class="btn-text">一键授权快捷登录</text>
</button>
<text class="auth-guarantee-tip">微信官方安全风控 · 个人信息严格加密存储</text>
</view>
<!-- 多角色体验账号矩阵 (局长/买家/金牌大神) -->
<view class="demo-accounts-card">
<view class="demo-card-head">
<text class="demo-title">多角色体验账号直登</text>
<text class="demo-sub">评审与体验专用 · 一键切换角色</text>
</view>
<view class="demo-list">
<view
v-for="acc in DEMO_ACCOUNTS"
:key="acc.id"
class="demo-item btn-active"
@click="loginWithDemo(acc)"
>
<image class="demo-avatar" :src="acc.avatar" mode="aspectFill" />
<view class="demo-info">
<view class="demo-name-row">
<text class="demo-name">{{ acc.nickname }}</text>
<text class="demo-badge" :class="acc.roleTag">{{ acc.roleDesc }}</text>
</view>
<text class="demo-feature">{{ acc.desc }}</text>
</view>
<button class="btn-switch-account btn-active">一键体验</button>
</view>
</view>
</view>
<!-- 底部合规声明与服务协议勾选 -->
<view class="protocol-section" @click="agreedProtocol = !agreedProtocol">
<view class="checkbox" :class="{ checked: agreedProtocol }">
<view class="checkbox-inner" v-if="agreedProtocol"></view>
</view>
<view class="protocol-text">
<text>登录注册即代表您已阅读并同意</text>
<text class="protocol-link" @click.stop="openUserAgreement">《用户服务协议》</text>
<text>与</text>
<text class="protocol-link" @click.stop="openPrivacyAgreement">《隐私保护指引》</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { ICONS } from '@/common/icons.js';
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
import { uploadImage } from '@/common/api.js';
const APP_LOGO = 'https://images.unsplash.com/photo-1618005182384-a83a8bd57fbe?w=200';
const DEFAULT_AVATAR = 'https://images.unsplash.com/photo-1535713875002-d1d0cf377fde?w=200';
const currentThemeKey = ref(getCurrentThemeKey());
const agreedProtocol = ref(true);
const redirectUrl = ref('');
const userForm = ref({
avatar: DEFAULT_AVATAR,
nickname: '微信用户'
});
const DEMO_ACCOUNTS = [
{
id: 1001,
nickname: '晨曦微光局长',
roleTag: 'host',
roleDesc: '房主/局长',
desc: '余额充足 · 发起项目制/AA组局',
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: 101,
nickname: '糖心小糯米',
roleTag: 'expert',
roleDesc: '金牌陪伴师',
desc: '工作台接单 · 雷达抢单 · 现场核销',
avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=200'
}
];
onLoad((options) => {
if (options && options.redirect) {
try {
redirectUrl.value = decodeURIComponent(options.redirect);
} catch (_) {
redirectUrl.value = options.redirect;
}
}
});
onMounted(() => {
currentThemeKey.value = getCurrentThemeKey();
applyThemeToNativeUI(currentThemeKey.value);
});
onShow(() => {
currentThemeKey.value = getCurrentThemeKey();
applyThemeToNativeUI(currentThemeKey.value);
});
const onChooseAvatar = async (e) => {
const avatarUrl = e?.detail?.avatarUrl;
if (!avatarUrl) return;
userForm.value.avatar = avatarUrl;
try {
const onlineUrl = await uploadImage(avatarUrl);
if (onlineUrl) {
userForm.value.avatar = onlineUrl;
}
} catch (_) {}
};
const completeLogin = (userId, customData = {}) => {
uni.showLoading({ title: '正在登录...' });
setTimeout(() => {
uni.hideLoading();
uni.removeStorageSync('user_has_logged_out');
uni.setStorageSync('userId', userId);
if (customData.nickname || userForm.value.nickname) {
uni.setStorageSync('userInfo', {
id: userId,
nickname: customData.nickname || userForm.value.nickname,
avatar: customData.avatar || userForm.value.avatar
});
}
uni.$emit('login-success', { userId });
uni.showToast({ title: '登录成功', icon: 'success', duration: 1500 });
setTimeout(() => {
if (redirectUrl.value) {
if (redirectUrl.value.startsWith('/pages/index') ||
redirectUrl.value.startsWith('/pages/activity/list') ||
redirectUrl.value.startsWith('/pages/order/list') ||
redirectUrl.value.startsWith('/pages/user/index')) {
uni.switchTab({ url: redirectUrl.value });
} else {
uni.redirectTo({ url: redirectUrl.value });
}
} else {
uni.navigateBack({
fail: () => {
uni.switchTab({ url: '/pages/user/index' });
}
});
}
}, 400);
}, 350);
};
const handleGetPhoneNumber = (e) => {
if (!agreedProtocol.value) {
uni.showToast({ title: '请先阅读并勾选服务协议', icon: 'none' });
return;
}
// #ifdef MP-WEIXIN
if (e && e.detail && (e.detail.code || e.detail.encryptedData)) {
completeLogin(1001, {
nickname: userForm.value.nickname || '微信用户',
avatar: userForm.value.avatar
});
} else {
console.warn('[WeChat Login] 未授权手机号或环境受限:', e?.detail?.errMsg);
uni.showModal({
title: '登录提示',
content: '未获得微信手机号授权(需非个人主体认证小程序支持)。是否使用体验账号直接登录?',
confirmText: '快捷登录',
cancelText: '取消',
confirmColor: '#10B981',
success: (res) => {
if (res.confirm) {
completeLogin(1001);
}
}
});
}
// #endif
// #ifndef MP-WEIXIN
completeLogin(1001);
// #endif
};
const handleFallbackLogin = () => {
// #ifndef MP-WEIXIN
if (!agreedProtocol.value) {
uni.showToast({ title: '请先阅读并勾选服务协议', icon: 'none' });
return;
}
completeLogin(1001);
// #endif
};
const loginWithDemo = (acc) => {
if (!agreedProtocol.value) {
uni.showToast({ title: '请先阅读并勾选服务协议', icon: 'none' });
return;
}
completeLogin(acc.id, {
nickname: acc.nickname,
avatar: acc.avatar
});
};
const openUserAgreement = () => {
uni.showModal({
title: '用户服务协议',
content: '欢迎使用同城生活陪伴服务平台。平台遵循合法合规与安全原则,所有同城活动履约均须在公开透明街区展开,严禁发布违规涉黄及私下交易导流信息。',
showCancel: false,
confirmText: '我知道了'
});
};
const openPrivacyAgreement = () => {
uni.showModal({
title: '隐私保护指引',
content: '平台高度重视用户个人信息安全,全面遵守国家网信办与微信小程序开发者隐私规范要求。您的手机号与身份信息仅用于平台核销和交易安全保障,未经授权绝不对外公开。',
showCancel: false,
confirmText: '我知道了'
});
};
</script>
<style lang="scss" scoped>
.auth-login-page {
min-height: 100vh;
background-color: #0A0F1D;
box-sizing: border-box;
padding: 40rpx 36rpx calc(60rpx + env(safe-area-inset-bottom));
display: flex;
flex-direction: column;
}
/* 顶部品牌区 */
.brand-header {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 24rpx;
margin-bottom: 44rpx;
.brand-logo-wrap {
width: 140rpx;
height: 140rpx;
border-radius: 40rpx;
background: linear-gradient(135deg, #6366F1, #8B5CF6);
padding: 6rpx;
box-shadow: 0 12rpx 32rpx rgba(99, 102, 241, 0.4);
margin-bottom: 24rpx;
.brand-logo-img {
width: 100%;
height: 100%;
border-radius: 36rpx;
}
}
.brand-app-name {
font-size: 38rpx;
font-weight: 800;
color: #F8FAFC;
letter-spacing: 2rpx;
margin-bottom: 8rpx;
}
.brand-slogan {
font-size: 24rpx;
color: #94A3B8;
text-align: center;
}
}
/* 微信官方头像昵称卡片 */
.auth-profile-card {
background: #151D30;
border-radius: 28rpx;
border: 1px solid rgba(255, 255, 255, 0.08);
padding: 32rpx;
margin-bottom: 36rpx;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.3);
.profile-card-header {
margin-bottom: 24rpx;
.profile-card-title {
font-size: 28rpx;
font-weight: 700;
color: #F8FAFC;
display: block;
margin-bottom: 4rpx;
}
.profile-card-tip {
font-size: 20rpx;
color: #64748B;
display: block;
}
}
.avatar-choose-row {
display: flex;
align-items: center;
gap: 24rpx;
padding-bottom: 24rpx;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
.avatar-picker-btn {
width: 110rpx;
height: 110rpx;
border-radius: 55rpx;
padding: 0;
margin: 0;
position: relative;
background: transparent;
border: none;
&::after {
border: none;
}
.chosen-avatar {
width: 100%;
height: 100%;
border-radius: 55rpx;
border: 4rpx solid #6366F1;
}
.avatar-badge {
position: absolute;
bottom: 0;
right: 0;
width: 36rpx;
height: 36rpx;
border-radius: 50%;
background: #6366F1;
display: flex;
align-items: center;
justify-content: center;
border: 2rpx solid #151D30;
.camera-icon-svg {
width: 22rpx;
height: 22rpx;
}
}
}
.avatar-tip-wrap {
flex: 1;
.avatar-tip-title {
font-size: 26rpx;
font-weight: 600;
color: #F8FAFC;
display: block;
margin-bottom: 4rpx;
}
.avatar-tip-sub {
font-size: 20rpx;
color: #94A3B8;
display: block;
}
}
}
.nickname-input-row {
display: flex;
align-items: center;
padding-top: 24rpx;
.input-label {
width: 100rpx;
font-size: 26rpx;
color: #94A3B8;
font-weight: 500;
}
.nickname-input {
flex: 1;
height: 72rpx;
font-size: 26rpx;
color: #F8FAFC;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 14rpx;
padding: 0 20rpx;
}
.ph-style {
color: #64748B;
font-size: 24rpx;
}
}
}
/* 主操作按钮区 */
.main-action-section {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 40rpx;
.btn-wechat-primary {
width: 100%;
height: 92rpx;
border-radius: 46rpx;
background: #07C160;
color: #FFFFFF;
font-size: 30rpx;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
box-shadow: 0 8rpx 24rpx rgba(7, 193, 96, 0.35);
border: none;
margin: 0;
&::after {
border: none;
}
.wechat-icon-svg {
width: 38rpx;
height: 38rpx;
}
.btn-text {
letter-spacing: 1rpx;
}
}
.auth-guarantee-tip {
font-size: 20rpx;
color: #64748B;
margin-top: 14rpx;
}
}
/* 体验账号卡片 */
.demo-accounts-card {
background: #151D30;
border-radius: 28rpx;
border: 1px solid rgba(255, 255, 255, 0.06);
padding: 28rpx 28rpx 16rpx;
margin-bottom: 40rpx;
.demo-card-head {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
.demo-title {
font-size: 26rpx;
font-weight: 700;
color: #F8FAFC;
}
.demo-sub {
font-size: 20rpx;
color: #64748B;
}
}
.demo-list {
display: flex;
flex-direction: column;
gap: 16rpx;
.demo-item {
display: flex;
align-items: center;
gap: 18rpx;
padding: 16rpx 20rpx;
border-radius: 20rpx;
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.06);
.demo-avatar {
width: 72rpx;
height: 72rpx;
border-radius: 36rpx;
flex-shrink: 0;
}
.demo-info {
flex: 1;
overflow: hidden;
.demo-name-row {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 4rpx;
.demo-name {
font-size: 26rpx;
font-weight: 700;
color: #F8FAFC;
}
.demo-badge {
font-size: 18rpx;
padding: 2rpx 10rpx;
border-radius: 6rpx;
font-weight: 600;
&.host {
background: rgba(245, 158, 11, 0.2);
color: #F59E0B;
}
&.buyer {
background: rgba(99, 102, 241, 0.2);
color: #818CF8;
}
&.expert {
background: rgba(16, 185, 129, 0.2);
color: #10B981;
}
}
}
.demo-feature {
font-size: 20rpx;
color: #94A3B8;
display: block;
}
}
.btn-switch-account {
font-size: 22rpx;
color: #6366F1;
font-weight: 600;
padding: 8rpx 18rpx;
border-radius: 12rpx;
background: rgba(99, 102, 241, 0.15);
border: none;
margin: 0;
line-height: 1.4;
&::after {
border: none;
}
}
}
}
}
/* 协议勾选 */
.protocol-section {
display: flex;
align-items: center;
justify-content: center;
gap: 12rpx;
margin-top: auto;
padding: 16rpx 0;
.checkbox {
width: 32rpx;
height: 32rpx;
border-radius: 8rpx;
border: 2px solid #64748B;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
&.checked {
background: #07C160;
border-color: #07C160;
.checkbox-inner {
width: 12rpx;
height: 12rpx;
background: #FFFFFF;
border-radius: 3rpx;
}
}
}
.protocol-text {
font-size: 22rpx;
color: #94A3B8;
line-height: 1.5;
.protocol-link {
color: #07C160;
font-weight: 600;
}
}
}
/* 浅色暖阳模式适配 */
.theme-warm {
background-color: #FAF8F5;
.brand-header {
.brand-app-name {
color: #1C1917;
}
.brand-slogan {
color: #78716C;
}
}
.auth-profile-card {
background: #FFFFFF;
border-color: #E7E5E4;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.06);
.profile-card-header {
.profile-card-title {
color: #1C1917;
}
.profile-card-tip {
color: #A8A29E;
}
}
.avatar-choose-row {
border-bottom-color: #F5F5F4;
.avatar-picker-btn .chosen-avatar {
border-color: #EA580C;
}
.avatar-picker-btn .avatar-badge {
background: #EA580C;
border-color: #FFFFFF;
}
.avatar-tip-wrap {
.avatar-tip-title {
color: #1C1917;
}
.avatar-tip-sub {
color: #78716C;
}
}
}
.nickname-input-row {
.input-label {
color: #78716C;
}
.nickname-input {
background: #FDFBF7;
border-color: #E7E5E4;
color: #1C1917;
}
.ph-style {
color: #A8A29E;
}
}
}
.main-action-section {
.auth-guarantee-tip {
color: #A8A29E;
}
}
.demo-accounts-card {
background: #FFFFFF;
border-color: #E7E5E4;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.06);
.demo-card-head {
.demo-title {
color: #1C1917;
}
.demo-sub {
color: #A8A29E;
}
}
.demo-list .demo-item {
background: #FDFBF7;
border-color: #E7E5E4;
.demo-info .demo-name-row .demo-name {
color: #1C1917;
}
.demo-info .demo-feature {
color: #78716C;
}
.btn-switch-account {
background: #FFF7ED;
color: #EA580C;
}
}
}
.protocol-section {
.checkbox {
border-color: #D6D3D1;
}
.protocol-text {
color: #78716C;
.protocol-link {
color: #07C160;
}
}
}
}
</style>

查看文件

@@ -153,49 +153,6 @@
<button class="btn-primary-login btn-active" @click="openLoginModal">立即登录 / 注册</button>
</view>
<!-- 登录与账号切换快捷弹窗 -->
<view class="login-modal-mask" v-if="showLoginModal" @click="showLoginModal = false">
<view class="login-modal" @click.stop>
<view class="modal-header">
<text class="modal-title">账号登录与快捷切换</text>
<view class="btn-close btn-active" @click="showLoginModal = false">
<image class="close-svg" :src="ICONS.close" mode="aspectFit" />
</view>
</view>
<view class="modal-body">
<button
class="btn-wechat-auth btn-active"
open-type="getPhoneNumber"
@getphonenumber="handleGetPhoneNumber"
@click="handleFallbackLogin"
>
一键授权快捷登录
</button>
<view class="demo-accounts-wrap">
<text class="demo-tips">支持一键切换指定身份体验账号:</text>
<view
v-for="acc in DEMO_ACCOUNTS"
:key="acc.id"
class="demo-account-item btn-active"
:class="{ current: Number(user.id) === acc.id && isLoggedIn }"
@click="switchDemoAccount(acc)"
>
<image class="demo-avatar" :src="acc.avatar" mode="aspectFill" />
<view class="demo-info">
<view class="demo-title-row">
<text class="demo-name">{{ acc.nickname }}</text>
<text class="demo-tag" :class="acc.roleTag">{{ acc.roleDesc }}</text>
</view>
<text class="demo-desc">UID: {{ acc.id }} · {{ acc.desc }}</text>
</view>
<text class="demo-action-btn">{{ Number(user.id) === acc.id && isLoggedIn ? '当前登录' : '切换至此号' }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 个人资料编辑设置弹窗 -->
<view class="profile-edit-modal-mask" v-if="showEditModal" @click="showEditModal = false">
<view class="profile-edit-modal" @click.stop>
@@ -377,78 +334,20 @@ const onRoleChanged = (role) => {
currentRole.value = role;
};
// 登录/注册已全面重构升级为独立专属页面 /pages/auth/login
// 保持向下兼容: switchDemoAccount, login-modal-mask, 一键授权快捷登录
const showLoginModal = ref(false);
const openLoginModal = () => {
showLoginModal.value = true;
};
const executeQuickLogin = (targetUid = 1001, phone = '') => {
uni.showLoading({ title: '正在登录...' });
setTimeout(() => {
uni.hideLoading();
showLoginModal.value = false;
isLoggedIn.value = true;
uni.removeStorageSync('user_has_logged_out');
uni.setStorageSync('userId', targetUid);
loadUserProfile(targetUid);
if (phone) {
user.value.phone = phone;
}
uni.showToast({ title: '登录成功', icon: 'success' });
}, 400);
};
const handleGetPhoneNumber = (e) => {
// #ifdef MP-WEIXIN
if (e && e.detail && (e.detail.code || e.detail.encryptedData)) {
executeQuickLogin(1001, '138****8888');
} else {
console.warn('[WeChat Auth] 未获得手机号权限或用户拒绝:', e && e.detail ? e.detail.errMsg : '');
uni.showModal({
title: '登录提示',
content: '未获取到微信手机号授权(需非个人主体认证小程序支持)。是否使用体验账号直接登录?',
confirmText: '快捷登录',
cancelText: '取消',
confirmColor: '#10B981',
success: (res) => {
if (res.confirm) {
executeQuickLogin(1001);
}
}
});
}
// #endif
// #ifndef MP-WEIXIN
executeQuickLogin(1001);
// #endif
};
const handleFallbackLogin = () => {
// #ifndef MP-WEIXIN
executeQuickLogin(1001);
// #endif
};
const switchDemoAccount = async (acc) => {
showLoginModal.value = false;
uni.showLoading({ title: '正在切换账号...' });
isLoggedIn.value = true;
uni.removeStorageSync('user_has_logged_out');
uni.setStorageSync('userId', acc.id);
user.value = {
...user.value,
id: acc.id,
nickname: acc.nickname,
avatar: acc.avatar
};
await loadUserProfile(acc.id);
uni.hideLoading();
uni.showToast({
title: `已切换至【${acc.nickname}】`,
icon: 'success'
uni.navigateTo({
url: '/pages/auth/login'
});
};
const onLoginSuccess = (payload) => {
loadUserProfile(payload?.userId);
};
const handleLogout = () => {
uni.showModal({
title: '确认退出登录?',
@@ -523,6 +422,7 @@ onMounted(() => {
applyThemeToNativeUI(currentThemeKey.value);
uni.$on('theme-change', onThemeChanged);
uni.$on('role-change', onRoleChanged);
uni.$on('login-success', onLoginSuccess);
loadUserProfile();
loadPlatformConfigs();
});
@@ -540,6 +440,7 @@ onShow(() => {
onUnmounted(() => {
uni.$off('theme-change', onThemeChanged);
uni.$off('role-change', onRoleChanged);
uni.$off('login-success', onLoginSuccess);
});
const switchThemeTo = (targetKey) => {
@@ -1743,150 +1644,6 @@ const navTo = (url) => {
}
}
.login-modal-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.75);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
padding: 40rpx;
backdrop-filter: blur(6px);
}
.login-modal {
width: 100%;
max-width: 640rpx;
background: #151D30;
border-radius: 32rpx;
border: 1px solid rgba(255, 255, 255, 0.1);
padding: 36rpx;
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.6);
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
.modal-title {
font-size: 30rpx;
font-weight: 700;
color: #F8FAFC;
}
.btn-close .close-svg {
width: 32rpx;
height: 32rpx;
}
}
.btn-wechat-auth {
background: #07C160;
color: #FFFFFF;
font-size: 28rpx;
font-weight: 700;
height: 80rpx;
line-height: 80rpx;
border-radius: 20rpx;
margin-bottom: 28rpx;
box-shadow: 0 4rpx 16rpx rgba(7, 193, 96, 0.35);
border: none;
&::after {
border: none;
}
}
.demo-accounts-wrap {
.demo-tips {
font-size: 22rpx;
color: #94A3B8;
display: block;
margin-bottom: 16rpx;
}
.demo-account-item {
display: flex;
align-items: center;
gap: 16rpx;
padding: 16rpx;
border-radius: 18rpx;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.06);
margin-bottom: 12rpx;
&.current {
border-color: #6366F1;
background: rgba(99, 102, 241, 0.12);
}
.demo-avatar {
width: 68rpx;
height: 68rpx;
border-radius: 50%;
flex-shrink: 0;
}
.demo-info {
flex: 1;
overflow: hidden;
.demo-title-row {
display: flex;
align-items: center;
gap: 12rpx;
.demo-name {
font-size: 24rpx;
font-weight: 700;
color: #F8FAFC;
}
.demo-tag {
font-size: 18rpx;
padding: 2rpx 8rpx;
border-radius: 6rpx;
&.host {
background: rgba(245, 158, 11, 0.2);
color: #F59E0B;
}
&.buyer {
background: rgba(99, 102, 241, 0.2);
color: #818CF8;
}
&.expert {
background: rgba(16, 185, 129, 0.2);
color: #10B981;
}
}
}
.demo-desc {
font-size: 20rpx;
color: #94A3B8;
margin-top: 4rpx;
display: block;
}
}
.demo-action-btn {
font-size: 20rpx;
color: #6366F1;
font-weight: 600;
padding: 6rpx 14rpx;
border-radius: 10rpx;
background: rgba(99, 102, 241, 0.15);
}
}
}
}
.theme-warm {
.guest-badge {
color: #78716C;