123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111 |
- <template>
- <div class="agreement-page">
- <!-- <div class="agreement-header">
- <h2>{{ pageTitle }}</h2>
- </div> -->
- <el-scrollbar class="agreement-content" v-loading="loading">
- <div v-if="error" class="agreement-error">{{ error }}</div>
- <div v-else class="agreement-body" v-html="renderedHtml"></div>
- </el-scrollbar>
- </div>
- </template>
- <script setup lang="ts">
- import { onMounted, ref, computed } from 'vue';
- import { useRoute } from 'vue-router';
- import { GetObjByPath } from './api';
- import { marked } from 'marked';
- import DOMPurify from 'dompurify';
- const route = useRoute();
- const loading = ref(false);
- const error = ref('');
- const htmlContent = ref('');
- // 根据路径名默认映射 ID;也支持通过 ?id= 覆盖
- const defaultIdByPath: Record<string, string> = {
- '/user-agreement': 'user_service_Agreement',
- '/privacy-policy': 'privacy_Policy',
- };
- const currentId = computed(() => {
- const qid = Number(route.query.id);
- if (!Number.isNaN(qid) && qid > 0) return qid;
- return defaultIdByPath[route.path] ?? 3;
- });
- const pageTitle = computed(() => {
- if (route.path === '/privacy-policy') return '隐私协议';
- return '用户服务协议';
- });
- const parseContent = (data: any): string => {
- // 兼容不同字段命名
- return (
- data?.content_html ||
- data?.content ||
- data?.detail ||
- data?.description ||
- ''
- );
- };
- const fetchAgreement = async () => {
- loading.value = true;
- error.value = '';
- htmlContent.value = '';
- try {
- const res: any = await GetObjByPath(currentId.value as any);
- // 兼容 service 里 code=200 / 2000 的返回
- const payload = res?.data ?? res;
- htmlContent.value = parseContent(payload) || '<p>暂无内容</p>';
- } catch (e: any) {
- error.value = e?.msg || '内容加载失败';
- } finally {
- loading.value = false;
- }
- };
- onMounted(fetchAgreement);
- // Markdown 渲染与安全处理
- marked.setOptions({
- breaks: true,
- gfm: true,
- });
- const renderedHtml = computed(() => {
- const raw = htmlContent.value || '';
- const containsHtmlTag = /<\/?[a-z][\s\S]*>/i.test(raw);
- const html = containsHtmlTag ? raw : (marked.parse(raw) as string);
- return DOMPurify.sanitize(html);
- });
- </script>
- <style scoped lang="scss">
- .agreement-page {
- display: flex;
- flex-direction: column;
- width: 100%;
- height: 100vh;
- background: #fff;
- }
- .agreement-header {
- padding: 16px 20px;
- border-bottom: 1px solid #f0f0f0;
- }
- .agreement-content {
- padding: 20px;
- height: calc(100vh - 64px);
- }
- .agreement-body {
- max-width: 800px;
- margin: 0 auto;
- }
- .agreement-error {
- color: #f56c6c;
- }
- </style>
|