文件
shanghaipeiwan/pwuniapp/pages/user/settings.vue

771 行
21 KiB
Vue

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

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

<template>
<view class="settings-page" :class="['theme-' + currentThemeKey]" :style="navStyle">
<!-- 顶部沉浸式自定义导航栏 -->
<view class="custom-nav-bar">
<view class="nav-content">
<view class="btn-nav-back btn-active" @click="handleBack">
<image class="nav-back-icon" :src="ICONS.chevronLeft" mode="aspectFit" />
</view>
<view class="nav-title-wrap">
<text class="nav-title">系统与隐私设置</text>
</view>
<!-- 胶囊右侧对称避让占位 -->
<view class="nav-capsule-placeholder"></view>
</view>
</view>
<!-- 设置主体滚动视口 -->
<scroll-view scroll-y class="settings-scroll-view">
<view class="settings-content-wrap">
<!-- 1. 隐私安全保护分组 -->
<view class="setting-group-box">
<view class="group-title-row">
<text class="group-title-txt">隐私安全保护</text>
<text class="group-badge-txt">数据受端到端加密保护</text>
</view>
<view class="setting-card">
<!-- 手机号隐藏与脱敏 -->
<view class="setting-item-row">
<view class="item-left-col">
<view class="item-icon-box bg-indigo">
<image class="item-svg" :src="ICONS.shield" mode="aspectFit" />
</view>
<view class="item-info-meta">
<text class="item-primary-label">隐藏手机号与联系方式</text>
<text class="item-secondary-desc">开启后个人名片及组局联络等公开场景,手机中间4位自动脱敏</text>
</view>
</view>
<view class="item-action-col">
<switch
class="custom-switch"
:checked="privacyHidePhone"
:color="switchActiveColor"
@change="onToggleHidePhone"
/>
</view>
</view>
</view>
</view>
<!-- 2. 通知与动态订阅分组 -->
<view class="setting-group-box">
<view class="group-title-row">
<text class="group-title-txt">通知与订阅</text>
<text class="group-badge-txt">即时接收关键动态</text>
</view>
<view class="setting-card">
<!-- 订单与组局动态提醒 -->
<view class="setting-item-row">
<view class="item-left-col">
<view class="item-icon-box bg-gold">
<image class="item-svg" :src="ICONS.bell" mode="aspectFit" />
</view>
<view class="item-info-meta">
<text class="item-primary-label">订单与组局动态提醒</text>
<text class="item-secondary-desc">接收陪伴师接单、服务验收与退款仲裁即时通知</text>
</view>
</view>
<view class="item-action-col">
<switch
class="custom-switch"
:checked="noticeSubscribe"
:color="switchActiveColor"
@change="onToggleNotice"
/>
</view>
</view>
</view>
</view>
<!-- 3. 本地数据与存储分组 -->
<view class="setting-group-box">
<view class="group-title-row">
<text class="group-title-txt">本地数据与存储</text>
<text class="group-badge-txt">释放设备闲置空间</text>
</view>
<view class="setting-card">
<!-- 清除本地缓存 -->
<view class="setting-item-row">
<view class="item-left-col">
<view class="item-icon-box bg-red">
<image class="item-svg" :src="ICONS.trash" mode="aspectFit" />
</view>
<view class="item-info-meta">
<text class="item-primary-label">清除本地缓存数据</text>
<text class="item-secondary-desc">清理临时图片与历史交互记录,当前占用:{{ cacheSizeText }}</text>
</view>
</view>
<view class="item-action-col">
<button class="btn-clear-cache btn-active" @click="clearLocalCache">
一键清理
</button>
</view>
</view>
</view>
</view>
<!-- 4. 关于系统与合规政策分组 -->
<view class="setting-group-box">
<view class="group-title-row">
<text class="group-title-txt">关于系统与合规</text>
<text class="group-badge-txt">资质公示与协议条款</text>
</view>
<view class="setting-card list-card">
<!-- 软件版本 -->
<view class="setting-item-row border-bottom">
<view class="item-left-col">
<view class="item-icon-box bg-blue">
<image class="item-svg" :src="ICONS.settings" mode="aspectFit" />
</view>
<view class="item-info-meta">
<text class="item-primary-label">软件版本</text>
<text class="item-secondary-desc">平台稳定运行环境</text>
</view>
</view>
<view class="item-action-col version-tag-col">
<text class="version-label">v2.6.0 正式版</text>
<view class="badge-latest">
<text class="badge-txt">已是最新</text>
</view>
</view>
</view>
<!-- 服务协议与隐私政策长文入口 -->
<view class="setting-item-row clickable btn-active" @click="goToProtocol">
<view class="item-left-col">
<view class="item-icon-box bg-emerald">
<image class="item-svg" :src="ICONS.fileText" mode="aspectFit" />
</view>
<view class="item-info-meta">
<text class="item-primary-label">服务协议与用户隐私政策</text>
<text class="item-secondary-desc">阅读完整法律条款与第三方信息共享清单</text>
</view>
</view>
<view class="item-action-col">
<image class="item-arrow-svg" :src="ICONS.chevronRight" mode="aspectFit" />
</view>
</view>
</view>
</view>
<!-- 5. 账号安全与登录会话管理 (登录态下可见) -->
<view class="setting-group-box account-session-box" v-if="isLoggedIn">
<view class="group-title-row">
<text class="group-title-txt">账号会话管理</text>
</view>
<view class="account-actions-card">
<button class="btn-account-switch btn-active" @click="handleSwitchAccount">
切换登录账号
</button>
<button class="btn-account-logout btn-active" @click="handleLogout">
退出当前登录
</button>
</view>
</view>
<!-- 页面底部平台版权合规声明 -->
<view class="settings-footer-info">
<text class="footer-p">电竞陪练陪玩官方正品保障平台</text>
<text class="footer-sub">倡导绿色健康竞技 · 抵制不良私下交易</text>
</view>
</view>
</scroll-view>
</view>
</template>
<script setup>
import { ref, computed } from 'vue';
import { onShow } from '@dcloudio/uni-app';
import { ICONS } from '@/common/icons.js';
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
import { getNavBarInfo } from '@/common/nav.js';
const currentThemeKey = ref(getCurrentThemeKey());
const navInfo = ref(getNavBarInfo());
// 本地设置状态
const privacyHidePhone = ref(uni.getStorageSync('privacy_hide_phone') === '1');
const noticeSubscribe = ref(uni.getStorageSync('notice_subscribe') !== '0');
const cacheSizeText = ref('1.25 MB');
const isLoggedIn = ref(!!uni.getStorageSync('peiwan_token'));
// 顶部自定义导航栏适配
const navStyle = computed(() => {
return {
'--safe-header-gap': `${navInfo.value.totalHeaderHeight}px`,
'--capsule-right-space': `${navInfo.value.capsuleRightSpace}px`,
'--capsule-height': `${navInfo.value.capsuleHeight}px`
};
});
// 开关的主题适配激活高亮色
const switchActiveColor = computed(() => {
return currentThemeKey.value === 'warm' ? '#EA580C' : '#6366F1';
});
// 计算本地缓存大小
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';
}
};
// 切换手机号脱敏隐藏
const onToggleHidePhone = (e) => {
const val = e.detail.value;
privacyHidePhone.value = val;
uni.setStorageSync('privacy_hide_phone', val ? '1' : '0');
uni.showToast({
title: val ? '已开启手机号隐藏' : '已关闭手机号隐藏',
icon: 'none'
});
};
// 切换通知订阅
const onToggleNotice = (e) => {
const val = e.detail.value;
noticeSubscribe.value = val;
uni.setStorageSync('notice_subscribe', val ? '1' : '0');
uni.showToast({
title: val ? '已开启服务提醒' : '已关闭服务提醒',
icon: 'none'
});
};
// 一键清理本地缓存
const clearLocalCache = () => {
uni.showModal({
title: '清除缓存',
content: '清理将释放临时数据,保留登录账号与必要配置。确定继续?',
confirmText: '确定清理',
cancelText: '取消',
confirmColor: '#EF4444',
success: (res) => {
if (res.confirm) {
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');
const noticeSub = uni.getStorageSync('notice_subscribe');
const userId = uni.getStorageSync('userId');
const userInfo = uni.getStorageSync('userInfo');
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);
if (noticeSub) uni.setStorageSync('notice_subscribe', noticeSub);
if (userId) uni.setStorageSync('userId', userId);
if (userInfo) uni.setStorageSync('userInfo', userInfo);
cacheSizeText.value = '0 KB';
uni.showToast({
title: '缓存清理完毕',
icon: 'none'
});
} catch (_) {
uni.showToast({
title: '清理成功',
icon: 'none'
});
}
}
}
});
};
// 跳转协议长文页面
const goToProtocol = () => {
uni.navigateTo({
url: '/pages/common/protocol'
});
};
// 切换账号
const handleSwitchAccount = () => {
uni.navigateTo({
url: '/pages/auth/login'
});
};
// 退出登录
const handleLogout = () => {
uni.showModal({
title: '退出登录',
content: '确定退出当前账号登录吗?',
confirmText: '确认退出',
cancelText: '取消',
confirmColor: '#EF4444',
success: (res) => {
if (res.confirm) {
uni.removeStorageSync('peiwan_token');
uni.removeStorageSync('peiwan_current_role');
uni.removeStorageSync('userInfo');
isLoggedIn.value = false;
uni.showToast({
title: '已退出登录',
icon: 'none'
});
setTimeout(() => {
uni.switchTab({
url: '/pages/user/index'
});
}, 600);
}
}
});
};
// 导航栏返回
const handleBack = () => {
const pages = getCurrentPages();
if (pages.length > 1) {
uni.navigateBack();
} else {
uni.switchTab({
url: '/pages/user/index'
});
}
};
onShow(() => {
currentThemeKey.value = getCurrentThemeKey();
applyThemeToNativeUI();
navInfo.value = getNavBarInfo();
privacyHidePhone.value = uni.getStorageSync('privacy_hide_phone') === '1';
noticeSubscribe.value = uni.getStorageSync('notice_subscribe') !== '0';
isLoggedIn.value = !!uni.getStorageSync('peiwan_token');
updateCacheSize();
});
</script>
<style lang="scss" scoped>
.settings-page {
width: 100%;
min-height: 100vh;
box-sizing: border-box;
background-color: #0A0F1D;
display: flex;
flex-direction: column;
/* 顶部沉浸式自定义导航栏 */
.custom-nav-bar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
height: var(--safe-header-gap);
background: rgba(10, 15, 29, 0.88);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
.nav-content {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: var(--capsule-height);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
.btn-nav-back {
width: 64rpx;
height: 64rpx;
border-radius: 32rpx;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.08);
.nav-back-icon {
width: 38rpx;
height: 38rpx;
}
}
.nav-title-wrap {
position: absolute;
left: 50%;
transform: translateX(-50%);
text-align: center;
.nav-title {
font-size: 32rpx;
font-weight: 700;
color: #F8FAFC;
letter-spacing: 0.5rpx;
}
}
.nav-capsule-placeholder {
width: var(--capsule-right-space);
}
}
}
/* 滚动内容区 */
.settings-scroll-view {
flex: 1;
margin-top: var(--safe-header-gap);
box-sizing: border-box;
}
.settings-content-wrap {
padding: 30rpx 28rpx 80rpx;
}
/* 分组盒子 */
.setting-group-box {
margin-bottom: 36rpx;
.group-title-row {
display: flex;
align-items: baseline;
justify-content: space-between;
padding: 0 12rpx 16rpx;
.group-title-txt {
font-size: 26rpx;
font-weight: 700;
color: #94A3B8;
letter-spacing: 0.5rpx;
}
.group-badge-txt {
font-size: 20rpx;
color: #64748B;
}
}
.setting-card {
background: #0F172A;
border: 1px solid rgba(255, 255, 255, 0.07);
border-radius: 24rpx;
padding: 24rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.25);
&.list-card {
padding: 8rpx 24rpx;
}
}
}
/* 单行项 */
.setting-item-row {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16rpx 0;
&.border-bottom {
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
&.clickable {
padding: 20rpx 0;
}
.item-left-col {
flex: 1;
display: flex;
align-items: center;
gap: 20rpx;
margin-right: 20rpx;
.item-icon-box {
width: 68rpx;
height: 68rpx;
border-radius: 18rpx;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
&.bg-indigo {
background: rgba(99, 102, 241, 0.15);
}
&.bg-gold {
background: rgba(245, 158, 11, 0.15);
}
&.bg-red {
background: rgba(239, 68, 68, 0.15);
}
&.bg-blue {
background: rgba(59, 130, 246, 0.15);
}
&.bg-emerald {
background: rgba(16, 185, 129, 0.15);
}
.item-svg {
width: 36rpx;
height: 36rpx;
}
}
.item-info-meta {
flex: 1;
display: flex;
flex-direction: column;
gap: 6rpx;
.item-primary-label {
font-size: 28rpx;
font-weight: 600;
color: #F8FAFC;
}
.item-secondary-desc {
font-size: 22rpx;
color: #64748B;
line-height: 1.4;
}
}
}
.item-action-col {
flex-shrink: 0;
display: flex;
align-items: center;
.item-arrow-svg {
width: 32rpx;
height: 32rpx;
opacity: 0.6;
}
.btn-clear-cache {
height: 56rpx;
line-height: 54rpx;
font-size: 22rpx;
font-weight: 600;
color: #EF4444;
background: rgba(239, 68, 68, 0.12);
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 28rpx;
padding: 0 24rpx;
margin: 0;
}
&.version-tag-col {
display: flex;
align-items: center;
gap: 12rpx;
.version-label {
font-size: 24rpx;
color: #94A3B8;
font-family: monospace;
}
.badge-latest {
background: rgba(16, 185, 129, 0.15);
border: 1px solid rgba(16, 185, 129, 0.3);
border-radius: 12rpx;
padding: 2rpx 10rpx;
.badge-txt {
font-size: 18rpx;
color: #10B981;
font-weight: 600;
}
}
}
}
}
/* 账号会话操作卡片 */
.account-session-box {
margin-top: 48rpx;
.account-actions-card {
display: flex;
flex-direction: column;
gap: 20rpx;
.btn-account-switch {
height: 84rpx;
line-height: 82rpx;
font-size: 28rpx;
font-weight: 600;
color: #818CF8;
background: rgba(99, 102, 241, 0.12);
border: 1px solid rgba(99, 102, 241, 0.25);
border-radius: 42rpx;
margin: 0;
}
.btn-account-logout {
height: 84rpx;
line-height: 82rpx;
font-size: 28rpx;
font-weight: 600;
color: #EF4444;
background: rgba(239, 68, 68, 0.1);
border: 1px solid rgba(239, 68, 68, 0.2);
border-radius: 42rpx;
margin: 0;
}
}
}
/* 页脚声明 */
.settings-footer-info {
text-align: center;
padding-top: 40rpx;
padding-bottom: 30rpx;
.footer-p {
font-size: 22rpx;
color: #64748B;
display: block;
margin-bottom: 8rpx;
}
.footer-sub {
font-size: 20rpx;
color: #475569;
display: block;
}
}
/* 暖阳浅色模式适配 (theme-warm) */
&.theme-warm {
background-color: #FFFDF9;
.custom-nav-bar {
background: rgba(255, 253, 249, 0.92);
border-bottom-color: rgba(234, 88, 12, 0.1);
.nav-content {
.btn-nav-back {
background: #FFF7ED;
border: 1px solid #FED7AA;
}
.nav-title-wrap .nav-title {
color: #1C1917;
}
}
}
.setting-group-box {
.group-title-row {
.group-title-txt {
color: #9A3412;
}
.group-badge-txt {
color: #A8A29E;
}
}
.setting-card {
background: #FFFFFF;
border: 1px solid #FED7AA;
box-shadow: 0 4rpx 20rpx rgba(234, 88, 12, 0.06);
}
}
.setting-item-row {
&.border-bottom {
border-bottom-color: #F5F5F4;
}
.item-left-col {
.item-icon-box {
&.bg-indigo { background: #FFF7ED; }
&.bg-gold { background: #FEF3C7; }
&.bg-red { background: #FEE2E2; }
&.bg-blue { background: #EFF6FF; }
&.bg-emerald { background: #ECFDF5; }
}
.item-info-meta {
.item-primary-label {
color: #1C1917;
}
.item-secondary-desc {
color: #78716C;
}
}
}
.item-action-col {
.btn-clear-cache {
background: #FEF2F2;
border-color: #FECACA;
color: #DC2626;
}
&.version-tag-col {
.version-label {
color: #78716C;
}
.badge-latest {
background: #ECFDF5;
border-color: #A7F3D0;
.badge-txt {
color: #059669;
}
}
}
}
}
.account-session-box {
.account-actions-card {
.btn-account-switch {
color: #EA580C;
background: #FFF7ED;
border-color: #FDBA74;
}
.btn-account-logout {
color: #DC2626;
background: #FEF2F2;
border-color: #FECACA;
}
}
}
.settings-footer-info {
.footer-p {
color: #A8A29E;
}
.footer-sub {
color: #D6D3D1;
}
}
}
}
.btn-active {
transition: opacity 0.15s ease, transform 0.15s ease;
&:active {
opacity: 0.8;
transform: scale(0.98);
}
}
</style>