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