15 changed files with 1917 additions and 537 deletions
Binary file not shown.
@ -0,0 +1,361 @@ |
|||||
|
<template> |
||||
|
<div v-if="visible" class="agreement-modal-overlay" @click="handleCancel"> |
||||
|
<div class="agreement-modal" @click.stop> |
||||
|
<!-- 头部 --> |
||||
|
<div class="modal-header"> |
||||
|
<h3 class="modal-title">{{ noticeDetail.title || '平台协议' }}</h3> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 内容 --> |
||||
|
<div class="modal-content"> |
||||
|
<div class="agreement-content" @scroll="handleScroll"> |
||||
|
<div v-if="noticeDetail.title" class="agreement-text"> |
||||
|
<div class="content-header"> |
||||
|
<h4>{{ noticeDetail.title }}</h4> |
||||
|
<div class="content-header-info"> |
||||
|
<span v-if="noticeDetail.author">作者:{{ noticeDetail.author }}</span> |
||||
|
<span v-if="noticeDetail.source">来源:{{ noticeDetail.source }}</span> |
||||
|
<span v-if="noticeDetail.publishTime">发布时间:{{ noticeDetail.publishTime }}</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="content-html" v-html="noticeDetail.contentHtml"></div> |
||||
|
<div v-if="!noticeDetail.contentHtml" class="default-content"> |
||||
|
<p>请仔细阅读本承诺书...</p> |
||||
|
</div> |
||||
|
<p class="important">请仔细阅读以上协议内容,点击"同意并继续"表示您已阅读并同意本协议。</p> |
||||
|
</div> |
||||
|
<div v-else class="agreement-text"> |
||||
|
<h4>用户协议与承诺书</h4> |
||||
|
<div class="default-content"> |
||||
|
<p>请仔细阅读本承诺书...</p> |
||||
|
</div> |
||||
|
<p class="important">请仔细阅读以上协议内容,点击"同意并继续"表示您已阅读并同意本协议。</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<!-- 底部按钮 --> |
||||
|
<div class="modal-footer"> |
||||
|
<button class="btn btn-secondary" @click="handleCancel">不同意</button> |
||||
|
<button |
||||
|
class="btn btn-primary" |
||||
|
@click="handleConfirm" |
||||
|
:disabled="!hasScrolledToBottom" |
||||
|
> |
||||
|
同意并继续 |
||||
|
<span v-if="!hasScrolledToBottom">(请阅读完全文后点击)</span> |
||||
|
</button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</template> |
||||
|
|
||||
|
<script setup> |
||||
|
import { ref, onMounted, reactive, watch } from 'vue' |
||||
|
import { useRouter } from 'vue-router' |
||||
|
import { message } from 'ant-design-vue' |
||||
|
import { letterApi } from '/@/api/business/letter/letter-api' |
||||
|
import { noticeApi } from '/@/api/business/oa/notice-api' |
||||
|
|
||||
|
const router = useRouter() |
||||
|
const emit = defineEmits(['confirm', 'cancel']) |
||||
|
|
||||
|
// 组件属性 |
||||
|
const props = defineProps({ |
||||
|
visible: { |
||||
|
type: Boolean, |
||||
|
default: false |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
// 组件状态 |
||||
|
const loading = ref(false) |
||||
|
const hasScrolledToBottom = ref(false) |
||||
|
|
||||
|
// 公告详情数据 |
||||
|
const noticeDetail = reactive({ |
||||
|
title: '', |
||||
|
contentHtml: '', |
||||
|
author: '', |
||||
|
source: '', |
||||
|
publishTime: '' |
||||
|
}) |
||||
|
|
||||
|
// 监听visible变化 |
||||
|
watch(() => props.visible, (newVisible) => { |
||||
|
if (newVisible) { |
||||
|
getNoticeDetail() |
||||
|
} |
||||
|
}, { immediate: true }) |
||||
|
|
||||
|
onMounted(() => { |
||||
|
if (props.visible) { |
||||
|
getNoticeDetail() |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
// 获取承诺书详情 |
||||
|
async function getNoticeDetail() { |
||||
|
try { |
||||
|
loading.value = true |
||||
|
|
||||
|
// 调用获取承诺书详情接口 |
||||
|
const result = await noticeApi.getOne({}) |
||||
|
console.log('获取承诺书详情结果:', result) |
||||
|
|
||||
|
if (result.code === 0 && result.data) { |
||||
|
Object.assign(noticeDetail, result.data) |
||||
|
} else { |
||||
|
// 如果接口调用失败,显示默认内容 |
||||
|
Object.assign(noticeDetail, { |
||||
|
title: '用户协议与承诺书', |
||||
|
contentHtml: '', |
||||
|
author: '系统管理员', |
||||
|
source: '平台管理', |
||||
|
publishTime: new Date().toLocaleDateString() |
||||
|
}) |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error('获取承诺书详情失败:', error) |
||||
|
// 接口调用失败,显示默认内容 |
||||
|
Object.assign(noticeDetail, { |
||||
|
title: '用户协议与承诺书', |
||||
|
contentHtml: '', |
||||
|
author: '系统管理员', |
||||
|
source: '平台管理', |
||||
|
publishTime: new Date().toLocaleDateString() |
||||
|
}) |
||||
|
} finally { |
||||
|
loading.value = false |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 滚动事件处理 |
||||
|
function handleScroll(event) { |
||||
|
const element = event.target |
||||
|
// 检查是否滚动到底部 |
||||
|
if (element.scrollTop + element.clientHeight >= element.scrollHeight - 10) { |
||||
|
hasScrolledToBottom.value = true |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 同意按钮点击处理 |
||||
|
async function handleConfirm() { |
||||
|
try { |
||||
|
// 调用签署承诺书接口 |
||||
|
const signRes = await letterApi.add() |
||||
|
|
||||
|
if (signRes.code === 0) { |
||||
|
message.success('承诺书签署成功') |
||||
|
emit('confirm') |
||||
|
} else { |
||||
|
message.error(signRes.msg || '承诺书签署失败') |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error('签署承诺书失败:', error) |
||||
|
message.error('承诺书签署失败,请稍后重试') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 不同意按钮点击处理 |
||||
|
function handleCancel() { |
||||
|
emit('cancel') |
||||
|
// 跳转到登录页面 |
||||
|
router.push('/login') |
||||
|
} |
||||
|
</script> |
||||
|
|
||||
|
<style scoped> |
||||
|
/* 遮罩层 */ |
||||
|
.agreement-modal-overlay { |
||||
|
position: fixed; |
||||
|
top: 0; |
||||
|
left: 0; |
||||
|
right: 0; |
||||
|
bottom: 0; |
||||
|
background-color: rgba(0, 0, 0, 0.5); |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
z-index: 1000; |
||||
|
} |
||||
|
|
||||
|
/* 弹框容器 */ |
||||
|
.agreement-modal { |
||||
|
width: 90%; |
||||
|
max-width: 500px; |
||||
|
background-color: white; |
||||
|
border-radius: 12px; |
||||
|
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15); |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
max-height: 80vh; |
||||
|
} |
||||
|
|
||||
|
/* 头部 */ |
||||
|
.modal-header { |
||||
|
padding: 16px; |
||||
|
border-bottom: 1px solid #e8e8e8; |
||||
|
} |
||||
|
|
||||
|
.modal-title { |
||||
|
font-size: 18px; |
||||
|
font-weight: 600; |
||||
|
margin: 0; |
||||
|
text-align: center; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
/* 内容区域 */ |
||||
|
.modal-content { |
||||
|
flex: 1; |
||||
|
overflow: hidden; |
||||
|
padding: 0 16px; |
||||
|
} |
||||
|
|
||||
|
.agreement-content { |
||||
|
height: 50vh; |
||||
|
overflow-y: auto; |
||||
|
padding: 16px 0; |
||||
|
} |
||||
|
|
||||
|
/* 滚动条样式 */ |
||||
|
.agreement-content::-webkit-scrollbar { |
||||
|
width: 6px; |
||||
|
} |
||||
|
|
||||
|
.agreement-content::-webkit-scrollbar-track { |
||||
|
background: #f1f1f1; |
||||
|
border-radius: 3px; |
||||
|
} |
||||
|
|
||||
|
.agreement-content::-webkit-scrollbar-thumb { |
||||
|
background: #888; |
||||
|
border-radius: 3px; |
||||
|
} |
||||
|
|
||||
|
.agreement-content::-webkit-scrollbar-thumb:hover { |
||||
|
background: #555; |
||||
|
} |
||||
|
|
||||
|
/* 内容样式 */ |
||||
|
.agreement-text { |
||||
|
line-height: 1.6; |
||||
|
color: #555; |
||||
|
} |
||||
|
|
||||
|
.content-header { |
||||
|
margin-bottom: 16px; |
||||
|
padding-bottom: 12px; |
||||
|
border-bottom: 1px solid #f0f0f0; |
||||
|
} |
||||
|
|
||||
|
.content-header h4 { |
||||
|
margin: 0 0 8px 0; |
||||
|
font-size: 16px; |
||||
|
font-weight: 600; |
||||
|
color: #333; |
||||
|
} |
||||
|
|
||||
|
.content-header-info { |
||||
|
font-size: 12px; |
||||
|
color: #999; |
||||
|
display: flex; |
||||
|
gap: 12px; |
||||
|
flex-wrap: wrap; |
||||
|
} |
||||
|
|
||||
|
.content-html { |
||||
|
margin-bottom: 16px; |
||||
|
} |
||||
|
|
||||
|
/* 默认内容 */ |
||||
|
.default-content { |
||||
|
margin-bottom: 16px; |
||||
|
padding: 16px; |
||||
|
background-color: #fafafa; |
||||
|
border-radius: 6px; |
||||
|
font-size: 14px; |
||||
|
line-height: 1.6; |
||||
|
} |
||||
|
|
||||
|
/* 重要提示 */ |
||||
|
.important { |
||||
|
font-size: 14px; |
||||
|
color: #ff4d4f; |
||||
|
font-weight: 500; |
||||
|
text-align: center; |
||||
|
margin-top: 24px; |
||||
|
} |
||||
|
|
||||
|
/* 底部按钮 */ |
||||
|
.modal-footer { |
||||
|
padding: 16px; |
||||
|
border-top: 1px solid #e8e8e8; |
||||
|
display: flex; |
||||
|
gap: 12px; |
||||
|
justify-content: space-between; |
||||
|
} |
||||
|
|
||||
|
.btn { |
||||
|
flex: 1; |
||||
|
padding: 12px; |
||||
|
font-size: 16px; |
||||
|
font-weight: 500; |
||||
|
border: none; |
||||
|
border-radius: 6px; |
||||
|
cursor: pointer; |
||||
|
transition: all 0.3s; |
||||
|
} |
||||
|
|
||||
|
.btn-primary { |
||||
|
background: linear-gradient(135deg, #1890ff 0%, #096dd9 100%); |
||||
|
color: white; |
||||
|
} |
||||
|
|
||||
|
.btn-primary:hover { |
||||
|
opacity: 0.9; |
||||
|
transform: translateY(-1px); |
||||
|
box-shadow: 0 4px 12px rgba(24, 144, 255, 0.3); |
||||
|
} |
||||
|
|
||||
|
.btn-primary:disabled { |
||||
|
opacity: 0.6; |
||||
|
cursor: not-allowed; |
||||
|
transform: none; |
||||
|
box-shadow: none; |
||||
|
} |
||||
|
|
||||
|
.btn-secondary { |
||||
|
background-color: #f0f0f0; |
||||
|
color: #666; |
||||
|
border: 1px solid #d9d9d9; |
||||
|
} |
||||
|
|
||||
|
.btn-secondary:hover { |
||||
|
background-color: #e8e8e8; |
||||
|
transform: translateY(-1px); |
||||
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); |
||||
|
} |
||||
|
|
||||
|
/* 响应式设计 */ |
||||
|
@media (max-width: 375px) { |
||||
|
.agreement-modal { |
||||
|
width: 95%; |
||||
|
max-width: none; |
||||
|
} |
||||
|
|
||||
|
.modal-title { |
||||
|
font-size: 16px; |
||||
|
} |
||||
|
|
||||
|
.modal-footer { |
||||
|
flex-direction: column; |
||||
|
} |
||||
|
|
||||
|
.btn { |
||||
|
font-size: 14px; |
||||
|
padding: 10px; |
||||
|
} |
||||
|
} |
||||
|
</style> |
||||
File diff suppressed because it is too large
Loading…
Reference in new issue