Files
qhmes/jeecgboot-vue3/src/views/monitor/mynews/DetailModal.vue

394 lines
11 KiB
Vue
Raw Normal View History

2026-04-03 09:56:14 +08:00
<template>
<BasicModal
v-bind="$attrs"
@register="registerModal"
title="查看详情"
:width="800"
:minHeight="600"
:showCancelBtn="false"
:showOkBtn="false"
:height="88"
:destroyOnClose="true"
@visible-change="handleVisibleChange"
>
<template #title>
<span class="basic-title">查看详情</span>
<div class="print-btn" @click="onPrinter">
<Icon icon="ant-design:printer-filled" />
<span class="print-text">打印</span>
</div>
</template>
<a-card class="daily-article">
<a-card-meta :title="content.titile">
<template #description>
<div class="article-desc">
<span>发布人{{ content.sender }}</span>
<span>发布时间{{ content.sendTime }}</span>
<span v-if="content.visitsNum">
<a-tooltip placement="top" title="访问次数" :autoAdjustOverflow="true">
<eye-outlined class="item-icon" /> {{ content.visitsNum }}
</a-tooltip>
</span>
</div>
</template>
</a-card-meta>
<a-divider />
<div v-html="content.msgContent" class="article-content"></div>
<div>
<a-button v-if="hasHref" @click="jumpToHandlePage">前往办理<ArrowRightOutlined /></a-button>
</div>
</a-card>
<template v-if="noticeFiles && noticeFiles.length > 0">
<div class="files-title">相关附件</div>
<template v-for="(file, index) in noticeFiles" :key="index">
<div class="files-area">
<div class="files-area-text">
<span>
<paper-clip-outlined />
<a
target="_blank"
rel="noopener noreferrer"
:title="file.fileName"
:href="getFileAccessHttpUrl(file.filePath)"
class="ant-upload-list-item-name"
>{{ file.fileName }}</a
>
</span>
</div>
<div class="files-area-operate">
<download-outlined class="item-icon" @click="handleDownloadFile(file.filePath)" />
<eye-outlined class="item-icon" @click="handleViewFile(file.filePath)" />
</div>
</div>
</template>
<a v-if="noticeFiles.length > 1" :href="downLoadFiles + '?id=' + content.id + '&token=' + getToken()" target="_blank" style="margin: 15px 6px; color: #5ac0fa">
<download-outlined class="item-icon" style="margin-right: 5px" /><span>批量下载所有附件</span>
</a>
</template>
</BasicModal>
</template>
<script lang="ts" setup>
import { BasicModal, useModalInner } from '/@/components/Modal';
import { ArrowRightOutlined, PaperClipOutlined, DownloadOutlined, EyeOutlined } from '@ant-design/icons-vue';
import { addVisitsNum } from '@/views/system/notice/notice.api';
import { useRouter } from 'vue-router';
import xss from 'xss';
import { options } from './XssWhiteList';
import { ref, unref } from 'vue';
import { getElectronFileUrl, getFileAccessHttpUrl } from '@/utils/common/compUtils';
import { useGlobSetting } from '@/hooks/setting';
import { encryptByBase64 } from '@/utils/cipher';
import { getToken } from '@/utils/auth';
import {defHttp} from "@/utils/http/axios";
import {$electron} from "@/electron";
const router = useRouter();
const glob = useGlobSetting();
const isUpdate = ref(true);
const content = ref<any>({});
const noticeFiles = ref([]);
/**
* 下载文件路径
*/
const downLoadFiles = `${glob.domainUrl}/sys/annountCement/downLoadFiles`;
const emit = defineEmits(['close', 'register']);
//表单赋值
const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
isUpdate.value = !!data?.isUpdate;
noticeFiles.value = [];
if (unref(isUpdate)) {
//data.record.msgContent = '<p>2323</p><input onmouseover=alert(1)>xss test';
// 代码逻辑说明: VUEN-1702 【禁止问题】sql注入漏洞
if (data.record.msgContent) {
// 代码逻辑说明: 【QQYUN-7049】3.6.0版本 通知公告中发布的富文本消息,在我的消息中查看没有样式---
data.record.msgContent = xss(data.record.msgContent, options);
}
// 代码逻辑说明: [QQYUN-12521]通知公告消息增加访问量
if (!data.record?.busId) {
await addVisitsNum({ id: data.record.id });
}
content.value = data.record;
if(content.value.sender){
const userInfo = await defHttp.get({ url: '/sys/user/queryUserComponentData?isMultiTranslate=true', params: { username: content.value.sender } });
content.value.sender = userInfo && userInfo?.records && userInfo?.records.length>0
?userInfo.records.find((item) => item.username === content.value.sender)?.realname : content.value.sender;
}
console.log('data---------->>>', data);
if (data.record?.files && data.record?.files.length > 0) {
noticeFiles.value = data.record.files.split(',').map((item) => {
return {
fileName: item.split('/').pop(),
filePath: item,
};
});
}
showHrefButton();
}
});
const hasHref = ref(false);
//查看消息详情可以跳转
function showHrefButton() {
if (content.value.busId) {
hasHref.value = true;
}
}
//跳转至办理页面
function jumpToHandlePage() {
let temp: any = content.value;
if (temp.busId) {
//这个busId是 任务ID
let jsonStr = temp.msgAbstract;
let query = {};
try {
if (jsonStr) {
let temp = JSON.parse(jsonStr);
if (temp) {
Object.keys(temp).map((k) => {
query[k] = temp[k];
});
}
}
} catch (e) {
console.log('参数解析异常', e);
}
console.log('query', query, jsonStr);
console.log('busId', temp.busId);
if (Object.keys(query).length > 0) {
// taskId taskDefKey procInsId
router.push({ path: '/task/handle/' + temp.busId, query: query });
} else {
router.push({ path: '/task/handle/' + temp.busId });
}
}
closeModal();
}
//打印
function onPrinter() {
// 获取要打印的内容
const printContent = document.querySelector('.daily-article');
if (!printContent) return;
// 创建一个iframe来处理打印
const printFrame = document.createElement('iframe');
printFrame.style.position = 'absolute';
printFrame.style.width = '0';
printFrame.style.height = '0';
printFrame.style.border = 'none';
printFrame.style.left = '-9999px';
printFrame.onload = function () {
const frameDoc = printFrame.contentDocument || printFrame.contentWindow?.document;
if (!frameDoc) return;
// 复制内容到iframe
const clone = printContent.cloneNode(true);
frameDoc.body.appendChild(clone);
// 添加打印样式
const style = frameDoc.createElement('style');
style.innerHTML = `
body {
margin: 0;
padding: 15px;
font-family: Arial, sans-serif;
}
img {
max-width: 100%;
height: auto;
}
@page {
size: auto;
margin: 15mm;
}
@media print {
body {
padding: 0;
}
}
.ant-card-meta-detail {
display: flex !important ;
justify-content: center !important;
align-items: center !important;
flex-direction: column !important;
}
.ant-card-meta-title {
font-size: 22px !important;
color: rgba(51, 51, 51, 0.88);
font-weight: 600;
font-size: 16px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.ant-card .ant-card-meta-description {
color: rgba(51, 51, 51, 0.45);
}
`;
frameDoc.head.appendChild(style);
// 确保图片加载完成
const images = frameDoc.getElementsByTagName('img');
let imagesToLoad = images.length;
const printWhenReady = () => {
if (imagesToLoad === 0) {
setTimeout(() => {
printFrame.contentWindow?.focus();
printFrame.contentWindow?.print();
document.body.removeChild(printFrame);
}, 300);
}
};
if (imagesToLoad === 0) {
printWhenReady();
} else {
Array.from(images).forEach((img) => {
img.onload = () => {
imagesToLoad--;
printWhenReady();
};
// 处理可能已经缓存的图片
if (img.complete && img.naturalWidth !== 0) {
imagesToLoad--;
printWhenReady();
}
});
}
};
document.body.appendChild(printFrame);
}
/**
* 下载文件
* @param filePath
*/
function handleDownloadFile(filePath) {
window.open(getFileAccessHttpUrl(filePath), '_blank');
}
/**
* 预览文件
* @param filePath
*/
function handleViewFile(filePath) {
if (filePath) {
console.log('glob.onlineUrl', glob.viewUrl);
let url = encodeURIComponent(encryptByBase64(filePath));
let previewUrl = `${glob.viewUrl}?url=` + url;
//update-begin-author:liusq---date:2025-12-16--for: JHHB-1139桌面端 文件预览统一修改
if($electron.isElectron()){
previewUrl = getElectronFileUrl(filePath);
}
//update-end-author:liusq---date:2025-12-16--for: JHHB-1139桌面端 文件预览统一修改
window.open(previewUrl, '_blank');
}
}
function handleVisibleChange(visible: boolean) {
if (!visible) {
emit('close');
}
}
</script>
<style scoped lang="less">
.daily-article {
:deep(.ant-card-meta-detail) {
display: flex !important;
justify-content: center !important;
align-items: center !important;
flex-direction: column !important;
}
:deep(.ant-card-meta-detail .ant-card-meta-title) {
font-size: 22px !important;
}
}
.print-btn {
position: absolute;
right: 100px;
top: 20px;
cursor: pointer;
color: #a3a3a5;
z-index: 999;
.print-text {
margin-left: 5px;
font-size: 14px;
}
&:hover {
color: #40a9ff;
}
}
.detail-iframe {
border: 0;
width: 100%;
height: 100%;
min-height: 600px;
}
.files-title {
font-size: 16px;
margin: 10px;
font-weight: 600;
color: #333;
}
.files-area {
display: flex;
align-items: center;
justify-content: flex-start;
margin: 6px;
&:hover {
background-color: #f5f5f5;
}
.files-area-text {
display: flex;
.ant-upload-list-item-name {
margin: 0 6px;
color: #56befa;
}
}
.files-area-operate {
display: flex;
margin-left: 10px;
.item-icon {
cursor: pointer;
margin: 0 6px;
&:hover {
color: #56befa;
}
}
}
}
.article-desc {
display: flex;
align-items: center;
span:not(:first-child) {
margin-left: 5px;
}
}
/* 确保打印内容中的图片有最大宽度限制 */
.article-content img {
max-width: 100%;
height: auto;
}
.basic-title{
position: relative;
display: flex;
padding-left: 7px;
font-size: 16px;
font-weight: 500;
line-height: 24px;
color: rgba(0,0,0,0.88);
cursor: move;
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
}
</style>