文件
shanghaipeiwan/pwuniapp/pages/common/protocol.vue

484 行
13 KiB
Vue

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

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

<template>
<view class="protocol-page" :class="{ 'theme-warm': currentThemeKey === 'warm' }">
<!-- 顶部状态栏与标题区 -->
<view class="protocol-header">
<view class="protocol-badge">合规法律条款</view>
<text class="protocol-title">{{ pageTitle }}</text>
<text class="protocol-meta">生效版本:v2.4.0 · 适用全平台所有注册与履约用户</text>
</view>
<!-- 协议切换(用户服务协议 / 隐私保护指引) -->
<view class="protocol-tabs">
<view
class="ptab"
:class="{ active: protocolType === 'service' }"
@click="switchType('service')"
>
用户服务协议
</view>
<view
class="ptab"
:class="{ active: protocolType === 'privacy' }"
@click="switchType('privacy')"
>
隐私保护指引
</view>
</view>
<!-- 协议条款滚动主体区域 -->
<scroll-view class="protocol-scroll-body" scroll-y enable-flex>
<view class="protocol-card">
<!-- 协议概要导言卡片 -->
<view class="intro-box">
<text class="intro-label">重要提示与导言:</text>
<text class="intro-text">{{ pageSummary }}</text>
</view>
<!-- 条款章节列表 -->
<view class="sections-list">
<view
v-for="(sec, idx) in formattedSections"
:key="idx"
class="section-item"
>
<view class="section-head" v-if="sec.title">
<view class="section-indicator"></view>
<text class="section-title">{{ sec.title }}</text>
</view>
<text class="section-body">{{ sec.body }}</text>
</view>
</view>
<!-- 法律声明与签署提示 -->
<view class="legal-notice">
<text class="notice-title">法律合规声明:</text>
<text class="notice-desc">
平台全面遵守国家网信办相关规定及微信小程序平台运营规范。平台依法对同城履约全链路提供合规安全守护、技术加密保障与7x24小时资金争议仲裁。如您对本协议内容有任何异议,请停止使用平台相关服务。
</text>
</view>
</view>
</scroll-view>
<!-- 底部操作与确认栏 -->
<view class="protocol-bottom-bar">
<button class="btn-confirm-read btn-active" @click="handleBack">
我已阅读并知悉
</button>
</view>
</view>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue';
import { onLoad, onShow } from '@dcloudio/uni-app';
import { getCurrentThemeKey, applyThemeToNativeUI } from '@/common/theme.js';
import { getPlatformConfigs } from '@/common/api.js';
import { useShare } from '@/common/share.js';
const currentThemeKey = ref(getCurrentThemeKey());
const protocolType = ref('service'); // 'service' | 'privacy'
const protocolData = ref({
userAgreementTitle: '用户服务协议',
userAgreementContent: '1. 账号使用规范:用户注册与使用同城生活陪伴服务须符合国家法律法规,严禁利用平台从事任何违法违规行为。\n2. 资金与交易保障:平台提供全额担保交易,订单完成前款项由官方账户托管,碰面出示4位核销码确认后自动结算至大神钱包。\n3. 履约安全守则:所有同城活动须在合规公开商业街区进行,严禁私下导流与脱离平台交易。\n4. 争议与售后仲裁:若遇服务不符或搭子违约,可随时在订单中发起申诉,由平台运营仲裁专员裁决。',
privacyPolicyTitle: '隐私保护指引',
privacyPolicyContent: '1. 信息收集范围:为保障同城陪玩交易安全与现场4位核销码核验,平台在获得您授权后会依法收集手机号与必要位置信息。\n2. 数据加密保护:平台全面接入微信小程序官方安全风控规范,所有用户数据均实施高强度加密脱敏存储。\n3. 权限撤回与管理:您可随时在小程序系统设置中撤回位置或通讯授权,平台未经您的明确许可绝不会向任何第三方泄露您的隐私数据。',
summary: '严禁发布任何违规言论及不良欺诈行为,平台全面遵循微信内容安全风控与用户隐私保护标准。'
});
const pageTitle = computed(() => {
if (protocolType.value === 'privacy') {
return protocolData.value.privacyPolicyTitle || '隐私保护指引';
}
return protocolData.value.userAgreementTitle || '用户服务协议';
});
useShare(() => {
const t = pageTitle.value || '用户服务协议与隐私政策';
return {
title: `同城陪伴 · ${t}`,
timelineTitle: `同城陪伴 · ${t}`,
path: '/pages/common/protocol',
params: { type: protocolType.value }
};
});
const pageSummary = computed(() => {
return protocolData.value.summary || '平台全面遵循微信官方内容安全风控与用户隐私保护标准。';
});
const rawContent = computed(() => {
if (protocolType.value === 'privacy') {
return protocolData.value.privacyPolicyContent || '';
}
return protocolData.value.userAgreementContent || '';
});
// 将纯文本条款拆分为结构化章节
const formattedSections = computed(() => {
const content = rawContent.value;
if (!content) return [];
const lines = content.split('\n').map(l => l.trim()).filter(Boolean);
const sections = [];
lines.forEach((line) => {
// 匹配如 1. 2. 或者 【】 格式的标题
const match = line.match(/^(\d+[\.\、]|【.+?】)(.+)/);
if (match) {
sections.push({
title: line.substring(0, line.indexOf(':') > -1 ? line.indexOf(':') + 1 : 12),
body: line.substring(line.indexOf(':') > -1 ? line.indexOf(':') + 1 : 12)
});
} else {
sections.push({
title: '',
body: line
});
}
});
return sections.length > 0 ? sections : [{ title: '条款内容', body: content }];
});
const loadConfig = async () => {
try {
const res = await getPlatformConfigs();
if (res && res.platform_protocol) {
const p = res.platform_protocol;
if (typeof p === 'object') {
if (p.userAgreementTitle) protocolData.value.userAgreementTitle = p.userAgreementTitle;
if (p.userAgreementContent) protocolData.value.userAgreementContent = p.userAgreementContent;
if (p.privacyPolicyTitle) protocolData.value.privacyPolicyTitle = p.privacyPolicyTitle;
if (p.privacyPolicyContent) protocolData.value.privacyPolicyContent = p.privacyPolicyContent;
if (p.summary) protocolData.value.summary = p.summary;
}
}
} catch (e) {
console.warn('[Protocol] 加载系统配置失败,降级展示默认条款:', e);
}
};
onLoad((options) => {
if (options && options.type) {
protocolType.value = options.type;
}
uni.setNavigationBarTitle({
title: protocolType.value === 'privacy' ? '隐私保护指引' : '用户服务协议'
});
});
// 页内切换协议类型(无需弹窗选择)
const switchType = (t) => {
if (protocolType.value === t) return;
protocolType.value = t;
uni.setNavigationBarTitle({
title: t === 'privacy' ? '隐私保护指引' : '用户服务协议'
});
};
onMounted(() => {
currentThemeKey.value = getCurrentThemeKey();
applyThemeToNativeUI(currentThemeKey.value);
loadConfig();
});
onShow(() => {
currentThemeKey.value = getCurrentThemeKey();
applyThemeToNativeUI(currentThemeKey.value);
});
const handleBack = () => {
uni.navigateBack({
fail: () => {
uni.switchTab({ url: '/pages/index/index' });
}
});
};
</script>
<style lang="scss">
.protocol-page {
min-height: 100vh;
background-color: #0A0F1D;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
/* 顶部标题区 */
.protocol-header {
padding: 40rpx 36rpx 24rpx;
background: #10172A;
border-bottom: 1px solid rgba(255, 255, 255, 0.06);
.protocol-badge {
display: inline-block;
font-size: 20rpx;
font-weight: 600;
color: #10B981;
background: rgba(16, 185, 129, 0.15);
padding: 4rpx 16rpx;
border-radius: 8rpx;
margin-bottom: 12rpx;
}
.protocol-title {
display: block;
font-size: 38rpx;
font-weight: 800;
color: #F8FAFC;
letter-spacing: 1rpx;
margin-bottom: 10rpx;
}
.protocol-meta {
display: block;
font-size: 22rpx;
color: #64748B;
}
}
/* 协议类型切换 */
.protocol-tabs {
display: flex;
gap: 12rpx;
padding: 20rpx 32rpx 0;
background: #10172A;
.ptab {
flex: 1;
text-align: center;
padding: 16rpx 0;
font-size: 26rpx;
color: #94A3B8;
background: rgba(255, 255, 255, 0.04);
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 14rpx;
&.active {
color: #0A0F1D;
background: #10B981;
border-color: #10B981;
font-weight: 700;
}
}
}
/* 协议主体滚动区 */
.protocol-scroll-body {
flex: 1;
padding: 28rpx 32rpx calc(140rpx + env(safe-area-inset-bottom));
box-sizing: border-box;
.protocol-card {
background: #151D30;
border-radius: 24rpx;
border: 1px solid rgba(255, 255, 255, 0.06);
padding: 32rpx;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.3);
.intro-box {
background: rgba(99, 102, 241, 0.08);
border-left: 6rpx solid #6366F1;
padding: 20rpx 24rpx;
border-radius: 12rpx;
margin-bottom: 36rpx;
.intro-label {
font-size: 24rpx;
font-weight: 700;
color: #818CF8;
display: block;
margin-bottom: 6rpx;
}
.intro-text {
font-size: 24rpx;
color: #CBD5E1;
line-height: 1.6;
}
}
.sections-list {
display: flex;
flex-direction: column;
gap: 32rpx;
margin-bottom: 36rpx;
.section-item {
padding-bottom: 24rpx;
border-bottom: 1px solid rgba(255, 255, 255, 0.04);
&:last-child {
border-bottom: none;
padding-bottom: 0;
}
.section-head {
display: flex;
align-items: center;
gap: 12rpx;
margin-bottom: 12rpx;
.section-indicator {
width: 8rpx;
height: 24rpx;
border-radius: 4rpx;
background: #10B981;
}
.section-title {
font-size: 28rpx;
font-weight: 700;
color: #F8FAFC;
}
}
.section-body {
font-size: 26rpx;
color: #94A3B8;
line-height: 1.7;
display: block;
}
}
}
.legal-notice {
background: rgba(255, 255, 255, 0.02);
border-radius: 16rpx;
padding: 24rpx;
border: 1px solid rgba(255, 255, 255, 0.05);
.notice-title {
font-size: 22rpx;
font-weight: 700;
color: #64748B;
display: block;
margin-bottom: 8rpx;
}
.notice-desc {
font-size: 22rpx;
color: #64748B;
line-height: 1.6;
}
}
}
}
/* 底部操作栏 */
.protocol-bottom-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20rpx 36rpx calc(24rpx + env(safe-area-inset-bottom));
background: rgba(10, 15, 29, 0.95);
backdrop-filter: blur(20px);
border-top: 1px solid rgba(255, 255, 255, 0.08);
box-sizing: border-box;
z-index: 99;
.btn-confirm-read {
width: 100%;
height: 84rpx;
border-radius: 42rpx;
background: #07C160;
color: #FFFFFF;
font-size: 28rpx;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
border: none;
&::after {
border: none;
}
}
}
/* 浅色暖阳模式适配 */
.theme-warm {
background-color: #FAF8F5;
.protocol-header {
background: #FFFFFF;
border-bottom-color: #E7E5E4;
.protocol-title {
color: #1C1917;
}
.protocol-meta {
color: #78716C;
}
}
.protocol-tabs {
background: #FFFFFF;
.ptab {
color: #78716C;
background: #F5F5F4;
border-color: #E7E5E4;
&.active {
color: #FFFFFF;
background: #EA580C;
border-color: #EA580C;
}
}
}
.protocol-scroll-body .protocol-card {
background: #FFFFFF;
border-color: #E7E5E4;
box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.04);
.intro-box {
background: #FFF7ED;
border-left-color: #EA580C;
.intro-label {
color: #EA580C;
}
.intro-text {
color: #78716C;
}
}
.sections-list .section-item {
border-bottom-color: #F5F5F4;
.section-head {
.section-indicator {
background: #EA580C;
}
.section-title {
color: #1C1917;
}
}
.section-body {
color: #57534E;
}
}
.legal-notice {
background: #FDFBF7;
border-color: #E7E5E4;
.notice-title {
color: #A8A29E;
}
.notice-desc {
color: #A8A29E;
}
}
}
.protocol-bottom-bar {
background: rgba(250, 248, 245, 0.95);
border-top-color: #E7E5E4;
}
}
</style>