1135 lines
28 KiB
Vue
1135 lines
28 KiB
Vue
<template>
|
||
<view class="profile-screen">
|
||
<view class="profile-bg"></view>
|
||
|
||
<!-- 状态栏占位 -->
|
||
<view class="status-bar-placeholder"></view>
|
||
|
||
<!-- Header -->
|
||
<view class="profile-header">
|
||
<view class="profile-user-row">
|
||
<view class="profile-avatar-wrap">
|
||
<image :src="defaultAvatar" mode="cover" class="profile-avatar-img" />
|
||
<view class="profile-avatar-badge">
|
||
<text class="profile-avatar-badge-text">★</text>
|
||
</view>
|
||
</view>
|
||
<view class="profile-user-info">
|
||
<text class="profile-nickname">{{ user.nickname }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- <view class="profile-stats">
|
||
<view class="profile-stat-item" @click="emitNav('favorites')">
|
||
<text class="profile-stat-num">{{ stats.favoritesCount }}</text>
|
||
<text class="profile-stat-label">我的收藏</text>
|
||
</view>
|
||
<view class="profile-stat-item" @click="emitNav('reports')">
|
||
<text class="profile-stat-num">{{ stats.reportsCount }}</text>
|
||
<text class="profile-stat-label">已解锁报告</text>
|
||
</view>
|
||
<view class="profile-stat-item" @click="showPromoter = true">
|
||
<text class="profile-stat-num">{{ stats.earningsCount }}</text>
|
||
<text class="profile-stat-label"></text>
|
||
</view>
|
||
</view> -->
|
||
</view>
|
||
|
||
<!-- Main cards -->
|
||
<view class="profile-cards">
|
||
<view class="profile-card membership-card">
|
||
<view class="membership-card-inner">
|
||
<view class="membership-card-head">
|
||
<view class="membership-card-icon">会</view>
|
||
<text class="membership-card-title">会员与额度</text>
|
||
</view>
|
||
<view v-if="!isLoggedIn()" class="membership-card-tip">登录后可查看会员等级与剩余额度</view>
|
||
<template v-else>
|
||
<view class="membership-row">
|
||
<text class="membership-label">会员等级</text>
|
||
<text class="membership-value">{{ membership.levelText }}</text>
|
||
</view>
|
||
<view class="membership-row">
|
||
<text class="membership-label">剩余额度</text>
|
||
<text class="membership-value membership-value-strong">
|
||
<template v-if="membership.remainText !== ''">{{ membership.remainText }}</template>
|
||
<template v-else>—</template>
|
||
<text v-if="membership.totalText !== ''" class="membership-total-suffix"> / {{ membership.totalText }}</text>
|
||
</text>
|
||
</view>
|
||
<text v-if="membership.loadFailed" class="membership-card-tip">额度加载失败,请稍后下拉刷新重试</text>
|
||
</template>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="profile-card">
|
||
<view class="profile-card-btn" @click="emitNav('myNamingPlans')">
|
||
<view class="profile-card-left">
|
||
<view class="profile-card-icon profile-card-icon-red">档</view>
|
||
<text class="profile-card-text">我的方案</text>
|
||
</view>
|
||
<text class="profile-card-arrow">›</text>
|
||
</view>
|
||
<!-- <view class="profile-card-btn profile-card-btn-border" @click="emitNav('reports')">
|
||
<view class="profile-card-left">
|
||
<view class="profile-card-icon profile-card-icon-gold">报</view>
|
||
<text class="profile-card-text">财运解析报告</text>
|
||
</view>
|
||
<text class="profile-card-arrow">›</text>
|
||
</view> -->
|
||
<view class="profile-card-btn profile-card-btn-border" @click="emitNav('orders')">
|
||
<view class="profile-card-left">
|
||
<view class="profile-card-icon profile-card-icon-blue">单</view>
|
||
<text class="profile-card-text">我的订单</text>
|
||
</view>
|
||
<text class="profile-card-arrow">›</text>
|
||
</view>
|
||
<view class="profile-card-btn profile-card-btn-border" @click="emitNav('favorites')">
|
||
<view class="profile-card-left">
|
||
<view class="profile-card-icon profile-card-icon-blue">单</view>
|
||
<text class="profile-card-text">我的收藏</text>
|
||
</view>
|
||
<text class="profile-card-arrow">›</text>
|
||
</view>
|
||
<view class="profile-card-btn profile-card-btn-border" @click="emitNav('profile_user_info')">
|
||
<view class="profile-card-left">
|
||
<view class="profile-card-icon profile-card-icon-gold">信</view>
|
||
<text class="profile-card-text">我的信息</text>
|
||
</view>
|
||
<text class="profile-card-arrow">›</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="profile-card">
|
||
<view class="profile-card-btn" @click="showShare = true">
|
||
<view class="profile-card-left">
|
||
<view class="profile-card-icon profile-card-icon-dark">享</view>
|
||
<text class="profile-card-text">分享给好友</text>
|
||
</view>
|
||
<text class="profile-card-arrow">›</text>
|
||
</view>
|
||
<view class="profile-card-btn profile-card-btn-border" @click="showPromoter = true">
|
||
<view class="profile-card-left">
|
||
<view class="profile-card-icon profile-card-icon-green">推</view>
|
||
<view class="profile-card-text-wrap">
|
||
<text class="profile-card-text">申请成为会员</text>
|
||
<text class="profile-card-subtext">自用省钱,分享赚钱</text>
|
||
</view>
|
||
</view>
|
||
<view class="profile-card-right">
|
||
<text class="profile-card-hot">HOT</text>
|
||
<text class="profile-card-arrow">›</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="profile-card">
|
||
<view class="profile-card-btn" @click="emitNav('settings')">
|
||
<view class="profile-card-left">
|
||
<view class="profile-card-icon profile-card-icon-gray">设</view>
|
||
<text class="profile-card-text">设置与反馈</text>
|
||
</view>
|
||
<text class="profile-card-arrow">›</text>
|
||
</view>
|
||
|
||
|
||
|
||
</view>
|
||
</view>
|
||
|
||
<!-- Promoter modal -->
|
||
<view v-if="showPromoter" class="profile-modal" @click="showPromoter = false">
|
||
<view class="profile-modal-content" @click.stop>
|
||
<view class="profile-modal-close" @click="showPromoter = false">×</view>
|
||
<view class="profile-modal-body">
|
||
<view class="profile-modal-header">
|
||
<view class="profile-modal-icon">推</view>
|
||
<text class="profile-modal-title">申请成为推广会员</text>
|
||
<text class="profile-modal-subtitle">开启您的睡后收入之旅</text>
|
||
</view>
|
||
<view class="profile-modal-form">
|
||
<input v-model="promoter.name" type="text" placeholder="真实姓名" class="profile-modal-input" />
|
||
<input v-model="promoter.phone" type="tel" placeholder="手机号码" class="profile-modal-input" />
|
||
<input v-model="promoter.wechat" type="text" placeholder="微信号 (选填)" class="profile-modal-input" />
|
||
<view class="profile-modal-level">
|
||
<text class="profile-modal-level-label">会员类型</text>
|
||
<view class="profile-modal-level-options">
|
||
<view
|
||
class="profile-modal-level-item"
|
||
:class="{ 'profile-modal-level-item-active': promoter.level === 'junior' }"
|
||
@click="promoter.level = 'junior'"
|
||
>
|
||
初级会员
|
||
</view>
|
||
<view
|
||
class="profile-modal-level-item"
|
||
:class="{ 'profile-modal-level-item-active': promoter.level === 'senior' }"
|
||
@click="promoter.level = 'senior'"
|
||
>
|
||
高级会员
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="profile-modal-submit" :disabled="submitting" @click="handlePromoterSubmit">
|
||
{{ submitting ? '提交中...' : '开启旅程' }}
|
||
</view>
|
||
<text class="profile-modal-note">点击支付即代表同意《会员合作协议》</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- Payment Modal -->
|
||
<PaymentModal :visible="showPayment" :product-name="paymentInfo.productName" :product-desc="paymentInfo.productDesc"
|
||
:product-icon="paymentInfo.productIcon" :amount="paymentInfo.amount" :business-type="paymentInfo.businessType"
|
||
:business-id="paymentInfo.businessId" @close="showPayment = false" @success="handlePaymentSuccess"
|
||
@fail="handlePaymentFail" />
|
||
|
||
<!-- Share modal -->
|
||
<view v-if="showShare" class="profile-share-modal" @click="showShare = false">
|
||
<view class="profile-share-content" @click.stop>
|
||
<view class="profile-share-options">
|
||
<view class="profile-share-item" @click="handleShare('poster')">
|
||
<view class="profile-share-icon profile-share-icon-poster">海</view>
|
||
<text class="profile-share-label">生成海报</text>
|
||
</view>
|
||
</view>
|
||
<view class="profile-share-cancel" @click="showShare = false">
|
||
取消
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- Share Poster Modal -->
|
||
<SharePosterModal :visible="showSharePoster" :user-id="user.id" @close="showSharePoster = false" />
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="ts">
|
||
import { reactive, ref, onMounted } from "vue";
|
||
import { logout, getUserInfo, setUserInfo, isLoggedIn, navigateToLogin } from "@/utils/auth";
|
||
import { userApi } from "@/api";
|
||
import SharePosterModal from "../SharePosterModal.vue";
|
||
import PaymentModal from "../PaymentModal.vue";
|
||
|
||
// @ts-ignore - uni is a global object provided by uni-app runtime
|
||
declare const uni: any;
|
||
|
||
const emit = defineEmits<{
|
||
navigate: [screen: string]
|
||
}>();
|
||
|
||
const user = reactive({
|
||
nickname: "玄墨",
|
||
avatar: "",
|
||
id: 1001, // 用户ID,实际应该从登录信息获取
|
||
});
|
||
|
||
const defaultAvatar = new URL("../../style/statics/default-avatar.svg", import.meta.url).href;
|
||
user.avatar = defaultAvatar;
|
||
|
||
const showPromoter = ref(false);
|
||
const showShare = ref(false);
|
||
const showSharePoster = ref(false);
|
||
const showPayment = ref(false);
|
||
const submitting = ref(false);
|
||
const promoter = reactive<{
|
||
name: string;
|
||
phone: string;
|
||
wechat: string;
|
||
level: "junior" | "senior";
|
||
}>({ name: "", phone: "", wechat: "", level: "junior" });
|
||
const partnerApplyId = ref(0); // 保存申请ID,用于支付
|
||
|
||
// 支付信息
|
||
const paymentInfo = reactive({
|
||
productName: '',
|
||
productDesc: '',
|
||
productIcon: '💼',
|
||
amount: 0,
|
||
businessType: '',
|
||
businessId: 0
|
||
});
|
||
|
||
// 统计数据
|
||
const stats = reactive({
|
||
favoritesCount: 0,
|
||
reportsCount: 0,
|
||
earningsCount: 0,
|
||
});
|
||
const membership = reactive({
|
||
levelText: "普通会员",
|
||
remainText: "",
|
||
totalText: "",
|
||
loadFailed: false,
|
||
});
|
||
|
||
const requireLoginThen = (next: () => void) => {
|
||
if (isLoggedIn()) {
|
||
next();
|
||
return;
|
||
}
|
||
|
||
// Web环境使用confirm,uni-app环境使用showModal
|
||
if (typeof uni?.showModal === 'function') {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '登录后可使用该功能,是否前往登录?',
|
||
confirmText: '去登录',
|
||
cancelText: '先逛逛',
|
||
success: (res: any) => {
|
||
if (res.confirm) {
|
||
navigateToLogin();
|
||
}
|
||
},
|
||
});
|
||
} else {
|
||
// Web环境使用原生confirm
|
||
const confirmed = confirm('登录后可使用该功能,是否前往登录?');
|
||
if (confirmed) {
|
||
navigateToLogin();
|
||
}
|
||
}
|
||
};
|
||
|
||
const handleRefreshWxProfile = async () => {
|
||
try {
|
||
if (!uni?.getUserProfile) {
|
||
uni.showToast({ title: '当前环境不支持获取微信信息', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
const profileRes = await new Promise<any>((resolve, reject) => {
|
||
uni.getUserProfile({
|
||
desc: '用于更新头像和昵称',
|
||
success: resolve,
|
||
fail: reject,
|
||
});
|
||
});
|
||
|
||
const nickName = profileRes?.userInfo?.nickName;
|
||
const avatarUrl = profileRes?.userInfo?.avatarUrl;
|
||
|
||
if (!nickName && !avatarUrl) {
|
||
uni.showToast({ title: '未获取到微信头像或昵称', icon: 'none' });
|
||
return;
|
||
}
|
||
|
||
if (nickName) user.nickname = nickName;
|
||
if (avatarUrl) user.avatar = avatarUrl;
|
||
|
||
const old = getUserInfo() || {};
|
||
setUserInfo({
|
||
...old,
|
||
id: old.id || user.id,
|
||
nickname: nickName || old.nickname || user.nickname,
|
||
avatar: avatarUrl || old.avatar || user.avatar,
|
||
});
|
||
|
||
uni.showToast({ title: '已更新', icon: 'success' });
|
||
} catch (e: any) {
|
||
const msg = e?.errMsg && String(e.errMsg).includes('cancel') ? '已取消' : '获取失败';
|
||
uni.showToast({ title: msg, icon: 'none' });
|
||
}
|
||
};
|
||
|
||
// 加载用户信息
|
||
onMounted(async () => {
|
||
const userInfo = getUserInfo();
|
||
if (userInfo) {
|
||
user.nickname = userInfo.username;
|
||
user.avatar = userInfo.avatar;
|
||
user.id = userInfo.id ;
|
||
}
|
||
|
||
if (!isLoggedIn()) {
|
||
membership.levelText = "普通会员";
|
||
membership.remainText = "";
|
||
membership.totalText = "";
|
||
membership.loadFailed = false;
|
||
return;
|
||
}
|
||
|
||
// 统计类接口失败时不执行 clearToken,避免从子页返回「我的」时误清登录态(与修改资料等流程叠加)
|
||
const statsRequestOpts = { clearAuthOnError: false };
|
||
|
||
// 加载收藏数量
|
||
try {
|
||
const res = await userApi.getMyFavorites({ page_no: 1, page_size: 1 }, statsRequestOpts);
|
||
stats.favoritesCount = res?.total || 0;
|
||
} catch (e) {
|
||
console.error('加载收藏数量失败:', e);
|
||
}
|
||
|
||
// 加载方案数量
|
||
try {
|
||
const res = await userApi.getMyReports({ page_no: 1, page_size: 1 }, statsRequestOpts);
|
||
stats.reportsCount = res?.total || 0;
|
||
} catch (e) {
|
||
console.error('加载方案数量失败:', e);
|
||
}
|
||
|
||
// 加载会员等级与额度
|
||
membership.loadFailed = false;
|
||
try {
|
||
const quotaRes: any = await userApi.getMyMembershipQuota(statsRequestOpts);
|
||
const level = String(
|
||
quotaRes?.membership_level ??
|
||
quotaRes?.level_name ??
|
||
quotaRes?.tier_name ??
|
||
quotaRes?.level ??
|
||
""
|
||
).trim();
|
||
const totalRaw = quotaRes?.total_quota ?? quotaRes?.quota;
|
||
const usedRaw = quotaRes?.used_quota;
|
||
const freeRename = Number(quotaRes?.free_rename_quota);
|
||
const remainRaw = quotaRes?.remaining_quota ?? quotaRes?.remain_quota ?? quotaRes?.left_quota;
|
||
const total = Number(totalRaw);
|
||
const used = Number(usedRaw);
|
||
const remainFallback = Number(remainRaw);
|
||
const remain = Number.isFinite(freeRename) ? freeRename : remainFallback;
|
||
|
||
membership.levelText = level || "普通会员";
|
||
membership.remainText = "";
|
||
membership.totalText = "";
|
||
// 剩余额度:优先使用后端字段 free_rename_quota
|
||
if (Number.isFinite(remain)) {
|
||
membership.remainText = String(remain);
|
||
if (Number.isFinite(total)) {
|
||
membership.totalText = String(total);
|
||
}
|
||
} else if (Number.isFinite(used) && Number.isFinite(total)) {
|
||
membership.remainText = String(Math.max(0, total - used));
|
||
membership.totalText = String(total);
|
||
} else if (Number.isFinite(total)) {
|
||
membership.remainText = "—";
|
||
membership.totalText = String(total);
|
||
}
|
||
} catch (e) {
|
||
console.error('加载会员额度失败:', e);
|
||
membership.loadFailed = true;
|
||
membership.remainText = "";
|
||
membership.totalText = "";
|
||
}
|
||
});
|
||
|
||
const emitNav = (screen: string) => {
|
||
const loginRequiredScreens = ['myNamingPlans', 'favorites', 'reports', 'orders', 'profile_user_info'];
|
||
if (loginRequiredScreens.includes(screen)) {
|
||
requireLoginThen(() => emit("navigate", screen));
|
||
return;
|
||
}
|
||
emit("navigate", screen);
|
||
};
|
||
|
||
// 处理分享
|
||
const handleShare = (type: 'poster') => {
|
||
showShare.value = false;
|
||
showSharePoster.value = true;
|
||
};
|
||
|
||
// 验证手机号
|
||
const isValidPhone = (phone: string) => /^1[3-9]\d{9}$/.test(phone);
|
||
|
||
// 处理推广员申请提交(先验证信息,再打开支付弹窗)
|
||
const handlePromoterSubmit = async () => {
|
||
if (!promoter.name.trim()) {
|
||
uni.showToast({ title: "请填写真实姓名", icon: "none" });
|
||
return;
|
||
}
|
||
if (!promoter.phone.trim()) {
|
||
uni.showToast({ title: "请填写手机号码", icon: "none" });
|
||
return;
|
||
}
|
||
if (!isValidPhone(promoter.phone)) {
|
||
uni.showToast({ title: "请输入正确的手机号", icon: "none" });
|
||
return;
|
||
}
|
||
|
||
if (submitting.value) return;
|
||
submitting.value = true;
|
||
|
||
try {
|
||
// 提交申请信息
|
||
const res = await userApi.applyPartner({
|
||
real_name: promoter.name.trim(),
|
||
phone: promoter.phone.trim(),
|
||
wechat_id: promoter.wechat.trim() || undefined,
|
||
member_level: promoter.level,
|
||
});
|
||
|
||
// 假设后端返回申请ID,实际需要根据API返回调整
|
||
partnerApplyId.value = (res as any)?.id || Date.now(); // 优先使用后端返回ID
|
||
|
||
// 关闭申请弹窗
|
||
showPromoter.value = false;
|
||
|
||
// 打开支付弹窗
|
||
paymentInfo.productName = '推广会员权益';
|
||
paymentInfo.productDesc = promoter.level === "senior" ? "高级会员申请" : "初级会员申请";
|
||
paymentInfo.productIcon = '💼';
|
||
paymentInfo.amount = 99;
|
||
paymentInfo.businessType = 'partner_apply';
|
||
paymentInfo.businessId = partnerApplyId.value;
|
||
showPayment.value = true;
|
||
|
||
} catch (e: any) {
|
||
uni.showToast({ title: e.msg || "申请失败,请重试", icon: "none" });
|
||
} finally {
|
||
submitting.value = false;
|
||
}
|
||
};
|
||
|
||
// 支付成功回调
|
||
const handlePaymentSuccess = (outTradeNo: string) => {
|
||
console.log('支付成功,订单号:', outTradeNo);
|
||
|
||
// 重置表单
|
||
promoter.name = "";
|
||
promoter.phone = "";
|
||
promoter.wechat = "";
|
||
promoter.level = "junior";
|
||
|
||
// Web环境使用alert,uni-app环境使用showModal
|
||
if (typeof uni?.showModal === 'function') {
|
||
uni.showModal({
|
||
title: '恭喜您',
|
||
content: '已成功开通推广会员权益!',
|
||
showCancel: false,
|
||
success: () => {
|
||
// 可以跳转到推广页面或刷新数据
|
||
}
|
||
});
|
||
} else {
|
||
// Web环境使用原生alert
|
||
alert('恭喜您,已成功开通推广会员权益!');
|
||
}
|
||
};
|
||
|
||
// 支付失败回调
|
||
const handlePaymentFail = (message: string) => {
|
||
console.log('支付失败:', message);
|
||
};
|
||
// 退出登录
|
||
const handleLogout = async () => {
|
||
// Web环境使用confirm,uni-app环境使用showModal
|
||
if (typeof uni?.showModal === 'function') {
|
||
uni.showModal({
|
||
title: '提示',
|
||
content: '确定要退出登录吗?',
|
||
success: async (res: any) => {
|
||
if (res.confirm) {
|
||
try {
|
||
await logout();
|
||
} catch (e) {
|
||
console.error('退出登录失败:', e);
|
||
}
|
||
}
|
||
},
|
||
});
|
||
} else {
|
||
// Web环境使用原生confirm
|
||
const confirmed = confirm('确定要退出登录吗?');
|
||
if (confirmed) {
|
||
try {
|
||
await logout();
|
||
} catch (e) {
|
||
console.error('退出登录失败:', e);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<style scoped>
|
||
.profile-screen {
|
||
height: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
background-color: #f0efe9;
|
||
position: relative;
|
||
overflow: auto;
|
||
}
|
||
|
||
/* 状态栏占位 */
|
||
.status-bar-placeholder {
|
||
height: var(--status-bar-height, 0);
|
||
width: 100%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.profile-bg {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
pointer-events: none;
|
||
opacity: 0.3;
|
||
background-image: url("https://www.transparenttextures.com/patterns/rice-paper.png");
|
||
}
|
||
|
||
/* Header */
|
||
.profile-header {
|
||
position: relative;
|
||
z-index: 10;
|
||
padding: 80rpx 48rpx 64rpx;
|
||
background-color: #2c2c2c;
|
||
color: #f2e6d8;
|
||
border-bottom-left-radius: 80rpx;
|
||
border-bottom-right-radius: 80rpx;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
.profile-user-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 32rpx;
|
||
}
|
||
|
||
.profile-avatar-wrap {
|
||
width: 128rpx;
|
||
height: 128rpx;
|
||
border-radius: 50%;
|
||
border: 4rpx solid #d4af37;
|
||
padding: 4rpx;
|
||
position: relative;
|
||
overflow: visible;
|
||
}
|
||
|
||
.profile-avatar-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.profile-avatar-badge {
|
||
position: absolute;
|
||
bottom: -4rpx;
|
||
right: -4rpx;
|
||
background-color: #d4af37;
|
||
border-radius: 50%;
|
||
width: 36rpx;
|
||
height: 36rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: 2rpx solid #2c2c2c;
|
||
}
|
||
|
||
.profile-avatar-badge-text {
|
||
font-size: 20rpx;
|
||
color: #2c2c2c;
|
||
}
|
||
|
||
.profile-user-info {
|
||
flex: 1;
|
||
}
|
||
|
||
.profile-nickname {
|
||
font-size: 40rpx;
|
||
font-weight: 700;
|
||
letter-spacing: 0.15em;
|
||
font-family: SimSun, "Songti SC", serif;
|
||
display: block;
|
||
}
|
||
|
||
.profile-user-meta {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
margin-top: 8rpx;
|
||
}
|
||
|
||
.profile-user-level {
|
||
font-size: 24rpx;
|
||
background-color: rgba(212, 175, 55, 0.2);
|
||
color: #d4af37;
|
||
padding: 4rpx 16rpx;
|
||
border-radius: 999rpx;
|
||
border: 1px solid rgba(212, 175, 55, 0.5);
|
||
}
|
||
|
||
.profile-user-quota {
|
||
font-size: 22rpx;
|
||
color: rgba(255, 255, 255, 0.78);
|
||
background-color: rgba(255, 255, 255, 0.08);
|
||
padding: 4rpx 14rpx;
|
||
border-radius: 999rpx;
|
||
border: 1px solid rgba(255, 255, 255, 0.18);
|
||
}
|
||
|
||
.profile-user-id {
|
||
font-size: 24rpx;
|
||
color: rgba(255, 255, 255, 0.5);
|
||
}
|
||
|
||
.profile-stats {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-top: 64rpx;
|
||
padding: 0 32rpx;
|
||
}
|
||
|
||
.profile-stat-item {
|
||
text-align: center;
|
||
}
|
||
|
||
.profile-stat-num {
|
||
font-size: 36rpx;
|
||
font-weight: 700;
|
||
color: #d4af37;
|
||
display: block;
|
||
}
|
||
|
||
.profile-stat-label {
|
||
font-size: 24rpx;
|
||
color: rgba(255, 255, 255, 0.6);
|
||
}
|
||
|
||
/* Cards */
|
||
.profile-cards {
|
||
position: relative;
|
||
z-index: 10;
|
||
padding: 0 24rpx;
|
||
margin-top: -24rpx;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
padding-bottom: 192rpx;
|
||
}
|
||
|
||
.membership-card {
|
||
padding: 28rpx 24rpx;
|
||
background: linear-gradient(145deg, #fffdf9 0%, #f5efe4 100%);
|
||
border: 1px solid rgba(212, 175, 55, 0.35);
|
||
box-shadow: 0 4px 14px rgba(44, 44, 44, 0.08);
|
||
}
|
||
|
||
.membership-card-inner {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 20rpx;
|
||
}
|
||
|
||
.membership-card-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.membership-card-icon {
|
||
width: 56rpx;
|
||
height: 56rpx;
|
||
border-radius: 12rpx;
|
||
background: rgba(212, 175, 55, 0.18);
|
||
color: #8b2323;
|
||
font-size: 28rpx;
|
||
font-weight: 800;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: 1px solid rgba(212, 175, 55, 0.4);
|
||
}
|
||
|
||
.membership-card-title {
|
||
font-size: 30rpx;
|
||
font-weight: 700;
|
||
color: #2c2c2c;
|
||
letter-spacing: 0.08em;
|
||
}
|
||
|
||
.membership-row {
|
||
display: flex;
|
||
align-items: baseline;
|
||
justify-content: space-between;
|
||
gap: 24rpx;
|
||
padding-bottom: 12rpx;
|
||
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
|
||
}
|
||
|
||
.membership-row:last-of-type {
|
||
border-bottom: none;
|
||
padding-bottom: 0;
|
||
}
|
||
|
||
.membership-label {
|
||
font-size: 26rpx;
|
||
color: #6b7280;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.membership-value {
|
||
font-size: 28rpx;
|
||
color: #2c2c2c;
|
||
text-align: right;
|
||
flex: 1;
|
||
}
|
||
|
||
.membership-value-strong {
|
||
font-weight: 800;
|
||
color: #8b2323;
|
||
}
|
||
|
||
.membership-total-suffix {
|
||
font-size: 24rpx;
|
||
font-weight: 500;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.membership-card-tip {
|
||
font-size: 24rpx;
|
||
color: #888;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.profile-card {
|
||
background-color: #fffdf9;
|
||
border-radius: 16rpx;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
||
border: 1px solid #e5e5e5;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.profile-card-btn {
|
||
width: 100%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 24rpx;
|
||
min-height: 96rpx;
|
||
background: transparent;
|
||
border: none;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.profile-card-btn-border {
|
||
border-top: 1px solid #f0f0f0;
|
||
}
|
||
|
||
.profile-card-left {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.profile-card-icon {
|
||
width: 64rpx;
|
||
height: 64rpx;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.profile-card-icon-red {
|
||
background-color: rgba(139, 35, 35, 0.1);
|
||
color: #8b2323;
|
||
}
|
||
|
||
.profile-card-icon-gold {
|
||
background-color: rgba(212, 175, 55, 0.1);
|
||
color: #d4af37;
|
||
}
|
||
|
||
.profile-card-icon-blue {
|
||
background-color: rgba(37, 99, 235, 0.1);
|
||
color: #2563eb;
|
||
}
|
||
|
||
.profile-card-icon-dark {
|
||
background-color: rgba(26, 26, 46, 0.1);
|
||
color: #1a1a2e;
|
||
}
|
||
|
||
.profile-card-icon-green {
|
||
background-color: rgba(21, 128, 61, 0.1);
|
||
color: #15803d;
|
||
}
|
||
|
||
.profile-card-icon-gray {
|
||
background-color: #f3f4f6;
|
||
color: #6b7280;
|
||
}
|
||
|
||
.profile-card-text {
|
||
font-size: 28rpx;
|
||
font-weight: 500;
|
||
color: #2c2c2c;
|
||
}
|
||
|
||
.profile-card-text-wrap {
|
||
text-align: left;
|
||
}
|
||
|
||
.profile-card-subtext {
|
||
font-size: 20rpx;
|
||
color: #999;
|
||
display: block;
|
||
margin-top: 4rpx;
|
||
}
|
||
|
||
.profile-card-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.profile-card-hot {
|
||
font-size: 18rpx;
|
||
background: linear-gradient(135deg, #ff6b6b, #8b2323);
|
||
color: #fff;
|
||
padding: 6rpx 14rpx;
|
||
border-radius: 6rpx;
|
||
font-weight: 600;
|
||
line-height: 1;
|
||
}
|
||
|
||
.profile-card-arrow {
|
||
color: #ccc;
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
/* Promoter Modal */
|
||
.profile-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: 50;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background-color: rgba(0, 0, 0, 0.6);
|
||
padding: 32rpx;
|
||
}
|
||
|
||
.profile-modal-content {
|
||
background-color: #fffdf9;
|
||
width: 100%;
|
||
max-width: 640rpx;
|
||
border-radius: 24rpx;
|
||
overflow: hidden;
|
||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
|
||
position: relative;
|
||
}
|
||
|
||
.profile-modal-close {
|
||
position: absolute;
|
||
top: 24rpx;
|
||
right: 24rpx;
|
||
color: #999;
|
||
font-size: 40rpx;
|
||
background: transparent;
|
||
border: none;
|
||
}
|
||
|
||
.profile-modal-body {
|
||
padding: 48rpx;
|
||
}
|
||
|
||
.profile-modal-header {
|
||
text-align: center;
|
||
margin-bottom: 48rpx;
|
||
}
|
||
|
||
.profile-modal-icon {
|
||
width: 96rpx;
|
||
height: 96rpx;
|
||
background-color: #8b2323;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #d4af37;
|
||
font-size: 40rpx;
|
||
margin: 0 auto 24rpx;
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
.profile-modal-title {
|
||
font-size: 36rpx;
|
||
font-weight: 700;
|
||
color: #2c2c2c;
|
||
display: block;
|
||
}
|
||
|
||
.profile-modal-subtitle {
|
||
font-size: 24rpx;
|
||
color: #5a5a5a;
|
||
display: block;
|
||
margin-top: 8rpx;
|
||
}
|
||
|
||
.profile-modal-form {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 24rpx;
|
||
}
|
||
|
||
.profile-modal-input {
|
||
width: 100%;
|
||
height: 88rpx;
|
||
background-color: #fff;
|
||
border: 1px solid #e5e5e5;
|
||
padding: 0 24rpx;
|
||
border-radius: 8rpx;
|
||
font-size: 28rpx;
|
||
color: #2c2c2c;
|
||
box-sizing: border-box;
|
||
line-height: 88rpx;
|
||
}
|
||
|
||
.profile-modal-input::placeholder {
|
||
color: #999;
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.profile-modal-level {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.profile-modal-level-label {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
}
|
||
|
||
.profile-modal-level-options {
|
||
display: flex;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.profile-modal-level-item {
|
||
flex: 1;
|
||
height: 76rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-radius: 8rpx;
|
||
border: 1px solid #dcdcdc;
|
||
background: #fff;
|
||
color: #555;
|
||
font-size: 26rpx;
|
||
}
|
||
|
||
.profile-modal-level-item-active {
|
||
border-color: #2c2c2c;
|
||
color: #2c2c2c;
|
||
background: #f3efe3;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.profile-modal-submit {
|
||
width: 100%;
|
||
background-color: #2c2c2c;
|
||
color: #d4af37;
|
||
font-weight: 700;
|
||
padding: 24rpx 0;
|
||
border-radius: 8rpx;
|
||
margin-top: 48rpx;
|
||
border: none;
|
||
font-size: 28rpx;
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
.profile-modal-note {
|
||
text-align: center;
|
||
font-size: 20rpx;
|
||
color: #999;
|
||
margin-top: 24rpx;
|
||
display: block;
|
||
}
|
||
|
||
/* Share Modal */
|
||
.profile-share-modal {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
z-index: 50;
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: flex-end;
|
||
background-color: rgba(0, 0, 0, 0.6);
|
||
}
|
||
|
||
.profile-share-content {
|
||
background-color: #fdfbf7;
|
||
border-top-left-radius: 32rpx;
|
||
border-top-right-radius: 32rpx;
|
||
padding: 48rpx;
|
||
}
|
||
|
||
.profile-share-title {
|
||
text-align: center;
|
||
font-weight: 700;
|
||
color: #2c2c2c;
|
||
margin-bottom: 48rpx;
|
||
display: block;
|
||
font-size: 32rpx;
|
||
}
|
||
|
||
.profile-share-options {
|
||
display: flex;
|
||
justify-content: space-around;
|
||
margin-bottom: 64rpx;
|
||
}
|
||
|
||
.profile-share-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 16rpx;
|
||
}
|
||
|
||
.profile-share-icon {
|
||
width: 96rpx;
|
||
height: 96rpx;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 36rpx;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
.profile-share-icon-wechat {
|
||
background-color: #07c160;
|
||
color: #fff;
|
||
}
|
||
|
||
.profile-share-icon-moments {
|
||
background-color: #fff;
|
||
border: 1px solid #e5e5e5;
|
||
color: #2c2c2c;
|
||
}
|
||
|
||
.profile-share-icon-poster {
|
||
background-color: #2c2c2c;
|
||
color: #fff;
|
||
}
|
||
|
||
.profile-share-label {
|
||
font-size: 24rpx;
|
||
color: #5a5a5a;
|
||
}
|
||
|
||
.profile-share-cancel {
|
||
width: 100%;
|
||
padding: 24rpx 0;
|
||
background-color: #f5f5f5;
|
||
color: #5a5a5a;
|
||
border-radius: 16rpx;
|
||
font-size: 28rpx;
|
||
font-weight: 700;
|
||
border: none;
|
||
}
|
||
</style>
|