feat(mini): 平台规范与服务协议页面化(页内切换,替代弹窗)
- 个人中心'平台规范与服务协议'点击直接进入 /pages/common/protocol(不再 showActionSheet 选择) - 协议页新增页内切换:用户服务协议 / 隐私保护指引(含暖阳主题适配) - 新增回归护栏 protocol-page.spec.ts(76 套件/601 用例全绿)
这个提交包含在:
@@ -7,6 +7,24 @@
|
||||
<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">
|
||||
@@ -139,6 +157,15 @@ onLoad((options) => {
|
||||
});
|
||||
});
|
||||
|
||||
// 页内切换协议类型(无需弹窗选择)
|
||||
const switchType = (t) => {
|
||||
if (protocolType.value === t) return;
|
||||
protocolType.value = t;
|
||||
uni.setNavigationBarTitle({
|
||||
title: t === 'privacy' ? '隐私保护指引' : '用户服务协议'
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
currentThemeKey.value = getCurrentThemeKey();
|
||||
applyThemeToNativeUI(currentThemeKey.value);
|
||||
@@ -201,6 +228,32 @@ const handleBack = () => {
|
||||
}
|
||||
}
|
||||
|
||||
/* 协议类型切换 */
|
||||
.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;
|
||||
@@ -349,6 +402,22 @@ const handleBack = () => {
|
||||
}
|
||||
}
|
||||
|
||||
.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;
|
||||
|
||||
@@ -1189,23 +1189,15 @@ const openFaq = () => {
|
||||
};
|
||||
|
||||
const openAbout = () => {
|
||||
uni.showActionSheet({
|
||||
itemList: ['用户服务协议', '隐私保护指引'],
|
||||
success: (res) => {
|
||||
const type = res.tapIndex === 1 ? 'privacy' : 'service';
|
||||
uni.navigateTo({
|
||||
url: `/pages/common/protocol?type=${type}`,
|
||||
fail: () => {
|
||||
const proto = platformConfigs.value.platform_protocol || {};
|
||||
const fullText = type === 'privacy'
|
||||
? (proto.privacyPolicyContent || '平台全面遵守微信小程序开发者隐私规范要求,对用户数据实施高强度加密保护。')
|
||||
: (proto.userAgreementContent || '平台遵循合法合规与安全原则,所有同城活动履约均须在公开透明街区展开。');
|
||||
uni.showModal({
|
||||
title: type === 'privacy' ? (proto.privacyPolicyTitle || '隐私保护指引') : (proto.userAgreementTitle || '用户服务协议'),
|
||||
content: fullText,
|
||||
showCancel: false
|
||||
});
|
||||
}
|
||||
// 进入独立协议页面(页内可切换"用户服务协议 / 隐私保护指引"),不再使用弹窗选择
|
||||
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
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// 已读取AGENTS.md
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
* 第六十批回归闸门:平台规范与服务协议页面化(页内切换,非弹窗)
|
||||
*/
|
||||
describe('第六十批服务协议页面化闸门', () => {
|
||||
const rootDir = path.resolve(__dirname, '../../');
|
||||
const protocol = fs.readFileSync(path.join(rootDir, 'pwuniapp/pages/common/protocol.vue'), 'utf-8');
|
||||
const userIndex = fs.readFileSync(path.join(rootDir, 'pwuniapp/pages/user/index.vue'), 'utf-8');
|
||||
|
||||
it('协议页支持页内切换服务协议/隐私政策', () => {
|
||||
expect(protocol).toContain('protocol-tabs');
|
||||
expect(protocol).toContain('const switchType =');
|
||||
expect(protocol).toContain("switchType('privacy')");
|
||||
expect(protocol).toContain("switchType('service')");
|
||||
});
|
||||
|
||||
it('个人中心直接进入协议页,不再弹窗选择', () => {
|
||||
const start = userIndex.indexOf('const openAbout');
|
||||
expect(start).toBeGreaterThan(-1);
|
||||
const end = userIndex.indexOf('};', start);
|
||||
const block = userIndex.slice(start, end + 2);
|
||||
expect(block).toContain("url: '/pages/common/protocol?type=service'");
|
||||
expect(block).not.toContain('showActionSheet');
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户