协议问题解决

This commit is contained in:
2026-01-12 11:45:37 +08:00
parent 6336f89f0d
commit 26df740dd0
16 changed files with 728 additions and 243 deletions

View File

@@ -0,0 +1,230 @@
<template>
<div class="agreement-container">
<div class="agreement-header">
<h1 class="agreement-title">{{ title }}</h1>
</div>
<div class="agreement-content" v-loading="loading">
<!-- PDF预览 -->
<div v-if="fileType === 'pdf'" class="pdf-viewer">
<VuePdfEmbed
:source="pdfSource"
:page="currentPage"
@loaded="onPdfLoaded"
@rendered="onPdfRendered"
/>
<!-- PDF分页控制 -->
<div v-if="totalPages > 1" class="pdf-pagination">
<el-button :disabled="currentPage <= 1" @click="currentPage--">上一页</el-button>
<span class="page-info">{{ currentPage }} / {{ totalPages }}</span>
<el-button :disabled="currentPage >= totalPages" @click="currentPage++">下一页</el-button>
</div>
</div>
<!-- TXT预览 -->
<div v-else-if="fileType === 'txt'" class="txt-viewer">
<pre>{{ textContent }}</pre>
</div>
<!-- 无内容 -->
<div v-else-if="!loading" class="empty-content">
<el-empty description="协议内容暂未上传" />
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { useRoute } from 'vue-router';
import { useStore } from 'vuex';
import { FILE_DOWNLOAD_URL } from '@/config';
import VuePdfEmbed from 'vue-pdf-embed';
const route = useRoute();
const store = useStore();
const loading = ref(true);
const textContent = ref('');
const fileType = ref<'pdf' | 'txt' | ''>('');
const pdfSource = ref<string>('');
const currentPage = ref(1);
const totalPages = ref(0);
// 协议类型对应的标题
const titleMap: Record<string, string> = {
platform: '红色思政智能体平台协议',
user: '用户协议',
privacy: '隐私协议'
};
// 获取协议类型
const agreementType = computed(() => route.params.type as string);
// 标题
const title = computed(() => titleMap[agreementType.value] || '协议');
// 获取文件ID
const fileId = computed(() => {
const baseInfo = store.state.system.baseInfo;
if (!baseInfo) return '';
switch (agreementType.value) {
case 'platform':
return baseInfo.platformAgreement || '';
case 'user':
return baseInfo.userAgreement || '';
case 'privacy':
return baseInfo.privacyAgreement || '';
default:
return '';
}
});
// 文件URL
const fileUrl = computed(() => {
if (!fileId.value) return '';
return `${FILE_DOWNLOAD_URL}${fileId.value}`;
});
// PDF加载完成
function onPdfLoaded(pdf: any) {
totalPages.value = pdf.numPages;
}
// PDF渲染完成
function onPdfRendered() {
loading.value = false;
}
onMounted(async () => {
// 确保系统配置已加载
if (!store.state.system.baseInfo) {
await store.dispatch('system/loadBaseInfo');
}
if (!fileId.value) {
loading.value = false;
return;
}
// 根据文件URL判断类型并加载
try {
const response = await fetch(fileUrl.value);
const contentType = response.headers.get('content-type') || '';
const contentDisposition = response.headers.get('content-disposition') || '';
// 判断是否为PDF
const isPdf = contentType.includes('pdf') ||
contentDisposition.includes('.pdf') ||
fileUrl.value.toLowerCase().includes('.pdf');
if (isPdf) {
fileType.value = 'pdf';
// 获取PDF的blob URL
const blob = await response.blob();
pdfSource.value = URL.createObjectURL(blob);
} else {
// 作为文本处理
fileType.value = 'txt';
textContent.value = await response.text();
loading.value = false;
}
} catch (error) {
console.error('加载协议文件失败:', error);
loading.value = false;
}
});
</script>
<style lang="scss" scoped>
.agreement-container {
min-height: 100vh;
background: #f5f5f5;
display: flex;
flex-direction: column;
}
.agreement-header {
background: #fff;
padding: 20px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
.agreement-title {
margin: 0;
font-size: 20px;
font-weight: 600;
color: #333;
text-align: center;
}
}
.agreement-content {
flex: 1;
padding: 20px;
display: flex;
flex-direction: column;
}
.pdf-viewer {
flex: 1;
background: #fff;
border-radius: 8px;
padding: 20px;
overflow-x: hidden;
overflow-y: auto;
:deep(.vue-pdf-embed) {
display: flex;
justify-content: center;
}
:deep(canvas) {
max-width: 100%;
height: auto !important;
display: block;
}
}
.pdf-pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 16px;
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #eee;
.page-info {
font-size: 14px;
color: #666;
}
}
.txt-viewer {
flex: 1;
background: #fff;
border-radius: 8px;
padding: 24px;
overflow: auto;
pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
font-size: 14px;
line-height: 1.8;
color: #333;
}
}
.empty-content {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
background: #fff;
border-radius: 8px;
}
</style>

View File

@@ -181,8 +181,8 @@
<div class="agreement-wrapper">
<el-checkbox v-model="loginForm.agree" />
<span class="agreement-text">
登录即为同意&nbsp;<span class="agreement-link">红色思政智能体平台</span><span class="agreement-link">用户协议</span>
<span class="agreement-link">隐私协议</span>
登录即为同意&nbsp;<span class="agreement-link" @click="openAgreement('platform')">红色思政智能体平台</span><span class="agreement-link" @click="openAgreement('user')">用户协议</span>
<span class="agreement-link" @click="openAgreement('privacy')">隐私协议</span>
</span>
</div>
</el-form-item>
@@ -519,6 +519,15 @@ function goToForgotPassword() {
router.push('/forgot-password');
}
/**
* 打开协议文件(新标签页)
*/
function openAgreement(type: 'platform' | 'user' | 'privacy') {
// 跳转到协议预览页面
const url = router.resolve({ path: `/agreement/${type}` }).href;
window.open(url, '_blank');
}
// 组件挂载时检查是否需要显示验证码
onMounted(() => {
// 可以根据需要决定是否默认显示验证码

View File

@@ -181,9 +181,9 @@
<div class="agreement-wrapper">
<el-checkbox v-model="loginForm.agree" />
<span class="agreement-text">
登录即为同意&nbsp;<span class="agreement-link">红色思政智能体平台</span>
<span class="agreement-link">用户协议</span>
<span class="agreement-link">隐私协议</span>
登录即为同意&nbsp;<span class="agreement-link" @click="openAgreement('platform')">红色思政智能体平台</span>
<span class="agreement-link" @click="openAgreement('user')">用户协议</span>
<span class="agreement-link" @click="openAgreement('privacy')">隐私协议</span>
</span>
</div>
</el-form-item>
@@ -521,6 +521,15 @@ function goToForgotPassword() {
router.push('/forgot-password');
}
/**
* 打开协议文件(新标签页)
*/
function openAgreement(type: 'platform' | 'user' | 'privacy') {
// 跳转到协议预览页面
const url = router.resolve({ path: `/agreement/${type}` }).href;
window.open(url, '_blank');
}
// 组件挂载时检查是否需要显示验证码
onMounted(() => {
// 可以根据需要决定是否默认显示验证码

View File

@@ -167,8 +167,8 @@
<div class="agreement-wrapper">
<el-checkbox v-model="registerForm.agree" />
<span class="agreement-text">
注册即为同意&nbsp;<span class="agreement-link">《红色思政智能体平台》</span><span class="agreement-link">《用户协议》</span>
<span class="agreement-link">《隐私协议》</span>
注册即为同意&nbsp;<span class="agreement-link" @click="openAgreement('platform')">《红色思政智能体平台》</span><span class="agreement-link" @click="openAgreement('user')">《用户协议》</span>
<span class="agreement-link" @click="openAgreement('privacy')">《隐私协议》</span>
</span>
</div>
</el-form-item>
@@ -515,6 +515,15 @@ onUnmounted(() => {
clearInterval(emailTimer);
}
});
/**
* 打开协议文件(新标签页)
*/
function openAgreement(type: 'platform' | 'user' | 'privacy') {
// 跳转到协议预览页面
const url = router.resolve({ path: `/agreement/${type}` }).href;
window.open(url, '_blank');
}
</script>
<style lang="scss" scoped>

View File

@@ -174,8 +174,8 @@
<div class="agreement-wrapper">
<el-checkbox v-model="registerForm.agree" />
<span class="agreement-text">
注册即为同意&nbsp;<span class="agreement-link">红色思政智能体平台</span><span class="agreement-link">用户协议</span>
<span class="agreement-link">隐私协议</span>
注册即为同意&nbsp;<span class="agreement-link" @click="openAgreement('platform')">红色思政智能体平台</span><span class="agreement-link" @click="openAgreement('user')">用户协议</span>
<span class="agreement-link" @click="openAgreement('privacy')">隐私协议</span>
</span>
</div>
</el-form-item>
@@ -522,6 +522,15 @@ function goToLogin() {
router.push('/login');
}
/**
* 打开协议文件(新标签页)
*/
function openAgreement(type: 'platform' | 'user' | 'privacy') {
// 跳转到协议预览页面
const url = router.resolve({ path: `/agreement/${type}` }).href;
window.open(url, '_blank');
}
// 组件卸载时清除定时器
import { onUnmounted } from 'vue';
onUnmounted(() => {