xiangyixiangqin/miniapp/pages/agreement/index.vue
2026-01-06 19:00:44 +08:00

327 lines
7.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="agreement-page">
<!-- 页面加载状态 -->
<Loading type="page" :loading="pageLoading" />
<!-- 顶部背景图 -->
<view class="top-bg">
<image src="/static/title_bg.png" mode="aspectFill" class="bg-img" />
</view>
<!-- 自定义导航栏 -->
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="navbar-content">
<view class="navbar-back" @click="handleBack">
<text class="back-icon"></text>
</view>
<text class="navbar-title">{{ pageTitle }}</text>
<view class="navbar-placeholder"></view>
</view>
</view>
<!-- 可滚动内容区域 -->
<scroll-view
class="content-scroll"
scroll-y
:style="{
top: (statusBarHeight + 44) + 'px',
height: 'calc(100vh - ' + (statusBarHeight + 44) + 'px)'
}"
>
<view class="agreement-content">
<view class="content-wrapper">
<rich-text
v-if="agreementContent && agreementContent.trim()"
:nodes="formatContent(agreementContent)"
class="rich-content"
/>
<view v-else-if="!pageLoading" class="empty-content">
<image src="/static/ic_empty.png" mode="aspectFit" class="empty-icon" />
<text class="empty-text">暂无{{ agreementType === 'user' ? '用户协议' : '隐私协议' }}内容</text>
</view>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
import { ref, computed, onMounted } from 'vue'
import { getUserAgreement, getPrivacyPolicy } from '@/api/agreement.js'
import Loading from '@/components/Loading/index.vue'
export default {
name: 'AgreementPage',
components: {
Loading
},
setup() {
// 状态栏高度
const statusBarHeight = ref(20)
// 页面状态
const pageLoading = ref(true)
const agreementType = ref('user') // user: 用户协议, privacy: 隐私协议
const agreementContent = ref('')
// 获取系统信息
const getSystemInfo = () => {
uni.getSystemInfo({
success: (res) => {
statusBarHeight.value = res.statusBarHeight || 20
}
})
}
// 返回上一页
const handleBack = () => {
uni.navigateBack()
}
// 计算属性
const pageTitle = computed(() => {
return agreementType.value === 'user' ? '用户协议' : '隐私协议'
})
/**
* 格式化协议内容
*/
const formatContent = (content) => {
if (!content) return ''
// 如果内容包含HTML标签直接返回
if (content.includes('<')) {
return content
}
// 否则将换行符转换为HTML格式
return content.replace(/\n/g, '<br/>')
}
/**
* 获取协议内容
*/
const getAgreementContent = async () => {
try {
let res
if (agreementType.value === 'user') {
res = await getUserAgreement()
} else {
res = await getPrivacyPolicy()
}
console.log('协议接口返回:', res)
// 兼容两种返回格式
if (res) {
if (res.data && res.data.content) {
// 格式: { code: 0, data: { content: "..." } }
agreementContent.value = res.data.content
} else if (res.content) {
// 格式: { content: "..." }
agreementContent.value = res.content
} else if (typeof res === 'string') {
// 直接返回字符串
agreementContent.value = res
}
}
} catch (error) {
console.error('获取协议内容失败:', error)
uni.showToast({
title: '获取协议内容失败',
icon: 'none'
})
}
}
/**
* 初始化页面
*/
const initPage = async () => {
pageLoading.value = true
try {
getSystemInfo()
// 获取页面参数
const pages = getCurrentPages()
const currentPage = pages[pages.length - 1]
const options = currentPage.options || {}
agreementType.value = options.type || 'user'
await getAgreementContent()
} catch (error) {
console.error('初始化页面失败:', error)
} finally {
pageLoading.value = false
}
}
onMounted(() => {
initPage()
})
return {
statusBarHeight,
pageLoading,
agreementType,
agreementContent,
pageTitle,
handleBack,
formatContent
}
}
}
</script>
<style lang="scss" scoped>
.agreement-page {
height: 100vh;
background-color: #f8f8f8;
overflow: hidden;
}
// 顶部背景图
.top-bg {
position: fixed;
top: 0;
left: 0;
right: 0;
height: 400rpx;
z-index: 0;
.bg-img {
width: 100%;
height: 100%;
}
}
// 自定义导航栏
.custom-navbar {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 200;
.navbar-content {
position: relative;
height: 44px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24rpx;
.navbar-back {
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
.back-icon {
font-size: 56rpx;
color: #333;
font-weight: 300;
}
}
.navbar-title {
font-size: 34rpx;
font-weight: 600;
color: #333;
}
.navbar-placeholder {
width: 80rpx;
}
}
}
// 可滚动内容区域
.content-scroll {
position: fixed;
left: 0;
right: 0;
z-index: 1;
}
// 协议内容
.agreement-content {
padding: 20rpx 30rpx 40rpx;
.content-wrapper {
background: #fff;
border-radius: 16rpx;
padding: 40rpx 30rpx;
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
.rich-content {
line-height: 1.8;
font-size: 28rpx;
color: #333;
:deep(p) {
margin-bottom: 20rpx;
&:last-child {
margin-bottom: 0;
}
}
:deep(h1), :deep(h2), :deep(h3) {
font-weight: 600;
margin: 30rpx 0 20rpx;
color: #333;
}
:deep(h1) {
font-size: 36rpx;
}
:deep(h2) {
font-size: 32rpx;
}
:deep(h3) {
font-size: 30rpx;
}
:deep(ul), :deep(ol) {
padding-left: 40rpx;
margin-bottom: 20rpx;
}
:deep(li) {
margin-bottom: 10rpx;
}
:deep(strong) {
font-weight: 600;
color: #333;
}
:deep(em) {
font-style: italic;
color: #666;
}
}
.empty-content {
text-align: center;
padding: 100rpx 0;
.empty-icon {
width: 200rpx;
height: 200rpx;
margin-bottom: 30rpx;
}
.empty-text {
font-size: 28rpx;
color: #999;
}
}
}
}
</style>