第一次提交
This commit is contained in:
393
jeecgboot-vue3/src/views/monitor/mynews/DetailModal.vue
Normal file
393
jeecgboot-vue3/src/views/monitor/mynews/DetailModal.vue
Normal file
@@ -0,0 +1,393 @@
|
||||
<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>
|
||||
35
jeecgboot-vue3/src/views/monitor/mynews/DynamicNotice.vue
Normal file
35
jeecgboot-vue3/src/views/monitor/mynews/DynamicNotice.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<component :is="currentModal" :formData="formData" v-model:visible="modalVisible"></component>
|
||||
</template>
|
||||
<script setup lang="ts" name="dynamic-notice">
|
||||
import { ref, shallowRef, ComponentOptions, nextTick, defineAsyncComponent } from 'vue';
|
||||
const props = defineProps({
|
||||
path: { type: String, default: '' },
|
||||
formData: { type: Object, default: {} },
|
||||
});
|
||||
const modalVisible = ref<Boolean>(false);
|
||||
const currentModal = shallowRef<Nullable<ComponentOptions>>(null);
|
||||
const formData = ref<any>(props.formData);
|
||||
|
||||
const componentType = {
|
||||
};
|
||||
|
||||
/**
|
||||
* 跟换组件和传值事件
|
||||
*/
|
||||
function detail() {
|
||||
setTimeout(() => {
|
||||
if (props.path) {
|
||||
nextTick(() => {
|
||||
currentModal.value = componentType[props.path];
|
||||
formData.value = props.formData;
|
||||
modalVisible.value = true;
|
||||
});
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
detail,
|
||||
});
|
||||
</script>
|
||||
41
jeecgboot-vue3/src/views/monitor/mynews/XssWhiteList.ts
Normal file
41
jeecgboot-vue3/src/views/monitor/mynews/XssWhiteList.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
//xss攻击白名单列表
|
||||
export const options = {
|
||||
whiteList: {
|
||||
h1: ['style'],
|
||||
h2: ['style'],
|
||||
h3: ['style'],
|
||||
h4: ['style'],
|
||||
h5: ['style'],
|
||||
h6: ['style'],
|
||||
hr: ['style'],
|
||||
span: ['style'],
|
||||
strong: ['style'],
|
||||
b: ['style'],
|
||||
i: ['style'],
|
||||
br: [],
|
||||
p: ['style'],
|
||||
pre: ['style'],
|
||||
code: ['style'],
|
||||
a: ['style', 'target', 'href', 'title', 'rel'],
|
||||
img: ['style', 'src', 'title','width','height'],
|
||||
div: ['style'],
|
||||
table: ['style', 'width', 'border', 'height'],
|
||||
tr: ['style'],
|
||||
td: ['style', 'width', 'colspan'],
|
||||
th: ['style', 'width', 'colspan'],
|
||||
tbody: ['style'],
|
||||
ul: ['style'],
|
||||
li: ['style'],
|
||||
ol: ['style'],
|
||||
dl: ['style'],
|
||||
dt: ['style'],
|
||||
em: ['style'],
|
||||
cite: ['style'],
|
||||
section: ['style'],
|
||||
header: ['style'],
|
||||
footer: ['style'],
|
||||
blockquote: ['style'],
|
||||
audio: ['autoplay', 'controls', 'loop', 'preload', 'src'],
|
||||
video: ['autoplay', 'controls', 'loop', 'preload', 'src', 'height', 'width'],
|
||||
},
|
||||
};
|
||||
210
jeecgboot-vue3/src/views/monitor/mynews/index.vue
Normal file
210
jeecgboot-vue3/src/views/monitor/mynews/index.vue
Normal file
@@ -0,0 +1,210 @@
|
||||
<template>
|
||||
<div>
|
||||
<BasicTable @register="registerTable" :searchInfo="searchInfo" :rowSelection="rowSelection">
|
||||
<template #tableTitle>
|
||||
<a-button type="primary" @click="handlerReadAllMsg">全部标注已读</a-button>
|
||||
<a-dropdown v-if="selectedRowKeys.length > 0">
|
||||
<template #overlay>
|
||||
<a-menu>
|
||||
<a-menu-item key="1" @click="batchHandleDelete">
|
||||
<Icon icon="ant-design:delete-outlined"></Icon>
|
||||
删除
|
||||
</a-menu-item>
|
||||
</a-menu>
|
||||
</template>
|
||||
<a-button>
|
||||
批量操作
|
||||
<Icon icon="mdi:chevron-down"></Icon>
|
||||
</a-button>
|
||||
</a-dropdown>
|
||||
</template>
|
||||
<template #action="{ record }">
|
||||
<TableAction :actions="getActions(record)" />
|
||||
</template>
|
||||
</BasicTable>
|
||||
<DetailModal @register="register" />
|
||||
<keep-alive>
|
||||
<component v-if="currentModal" v-bind="bindParams" :key="currentModal" :is="currentModal" @register="modalRegCache[currentModal].register" />
|
||||
</keep-alive>
|
||||
</div>
|
||||
</template>
|
||||
<script lang="ts" name="monitor-mynews" setup>
|
||||
import {ref, onMounted, unref} from 'vue';
|
||||
import { BasicTable, useTable, TableAction } from '/@/components/Table';
|
||||
import DetailModal from './DetailModal.vue';
|
||||
import { getMyNewsList, editCementSend, syncNotic, readAllMsg, getOne, deleteAnnSend, deleteBatchAnnSend } from './mynews.api';
|
||||
import { columns, searchFormSchema } from './mynews.data';
|
||||
import { useMessage } from '/@/hooks/web/useMessage';
|
||||
import { getToken } from '/@/utils/auth';
|
||||
import { useModal } from '/@/components/Modal';
|
||||
import { useGlobSetting } from '/@/hooks/setting';
|
||||
const glob = useGlobSetting();
|
||||
const { createMessage } = useMessage();
|
||||
const checkedKeys = ref<Array<string | number>>([]);
|
||||
const content = ref({});
|
||||
const searchInfo = { logType: '1' };
|
||||
const [register, { openModal: openDetail }] = useModal();
|
||||
import { useListPage } from '/@/hooks/system/useListPage';
|
||||
import { getLogList } from '/@/views/monitor/log/log.api';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useAppStore } from '/@/store/modules/app';
|
||||
import { useMessageHref } from '/@/views/system/message/components/useSysMessage';
|
||||
const appStore = useAppStore();
|
||||
const router = useRouter();
|
||||
const { currentRoute } = useRouter();
|
||||
const { goPage, currentModal, modalRegCache, bindParams } = useMessageHref();
|
||||
// 代码逻辑说明: 【QQYUN-13058】我的消息区分类型且支持根据url参数查询类型
|
||||
const querystring = currentRoute.value.query;
|
||||
const findItem: any = searchFormSchema.find((item: any) => item.field === 'msgCategory');
|
||||
if (findItem) {
|
||||
if (querystring?.msgCategory) {
|
||||
findItem.componentProps.defaultValue = querystring.msgCategory
|
||||
} else if (querystring.noticeType) {
|
||||
findItem.componentProps.defaultValue = querystring.noticeType;
|
||||
} else {
|
||||
findItem.componentProps.defaultValue = null
|
||||
}
|
||||
}
|
||||
const { prefixCls, tableContext } = useListPage({
|
||||
designScope: 'mynews-list',
|
||||
tableProps: {
|
||||
title: '我的消息',
|
||||
api: getMyNewsList,
|
||||
columns: columns,
|
||||
formConfig: {
|
||||
schemas: searchFormSchema,
|
||||
// 代码逻辑说明: 【TV360X-545】我的消息列表不能通过时间范围查询---
|
||||
fieldMapToTime: [['sendTime', ['sendTimeBegin', 'sendTimeEnd'], 'YYYY-MM-DD']],
|
||||
},
|
||||
beforeFetch: (params) => {
|
||||
// 代码逻辑说明: 【QQYUN-13058】我的消息区分类型且支持根据url参数查询类型
|
||||
if (params.msgCategory) {
|
||||
if (['1', '2'].includes(params.msgCategory)) {
|
||||
params.msgCategory = params.msgCategory;
|
||||
} else {
|
||||
params.noticeType = params.msgCategory;
|
||||
delete params.msgCategory;
|
||||
}
|
||||
} else {
|
||||
if (querystring?.msgCategory) {
|
||||
params.msgCategory = querystring.msgCategory;
|
||||
} else if (querystring.noticeType) {
|
||||
params.noticeType = querystring.noticeType;
|
||||
}
|
||||
}
|
||||
return params;
|
||||
},
|
||||
},
|
||||
});
|
||||
const [registerTable, { reload }, { rowSelection, selectedRows, selectedRowKeys }] = tableContext;
|
||||
/**
|
||||
* 操作列定义
|
||||
* @param record
|
||||
*/
|
||||
function getActions(record) {
|
||||
return [
|
||||
{
|
||||
label: '查看',
|
||||
onClick: handleDetail.bind(null, record),
|
||||
},
|
||||
{
|
||||
label: '删除',
|
||||
popConfirm: {
|
||||
title: '是否确认删除',
|
||||
confirm: handleDelete.bind(null, record.id),
|
||||
},
|
||||
ifShow: record.readFlag === 1
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 查看
|
||||
*/
|
||||
function handleDetail(record) {
|
||||
let anntId = record.anntId;
|
||||
editCementSend({ anntId: anntId }).then((res) => {
|
||||
reload();
|
||||
syncNotic({ anntId: anntId });
|
||||
});
|
||||
const openModalFun = ()=>{
|
||||
openDetail(true, {
|
||||
record,
|
||||
isUpdate: true,
|
||||
});
|
||||
}
|
||||
goPage(record, openModalFun);
|
||||
|
||||
}
|
||||
// 日志类型
|
||||
function callback(key) {
|
||||
searchInfo.logType = key;
|
||||
reload();
|
||||
}
|
||||
|
||||
//全部标记已读
|
||||
function handlerReadAllMsg() {
|
||||
readAllMsg({}, reload);
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择事件
|
||||
*/
|
||||
function onSelectChange(selectedRowKeys: (string | number)[]) {
|
||||
checkedKeys.value = selectedRowKeys;
|
||||
}
|
||||
|
||||
// 代码逻辑说明: 消息跳转,打开详情表单
|
||||
onMounted(()=>{
|
||||
initHrefModal();
|
||||
});
|
||||
function initHrefModal(){
|
||||
let params = appStore.getMessageHrefParams;
|
||||
if(params){
|
||||
let anntId = params.id;
|
||||
if(anntId){
|
||||
editCementSend({ anntId: anntId }).then(() => {
|
||||
reload();
|
||||
syncNotic({ anntId: anntId });
|
||||
});
|
||||
}
|
||||
let detailId = params.detailId;
|
||||
if(detailId){
|
||||
getOne(detailId).then(data=>{
|
||||
console.log('getOne', data)
|
||||
openDetail(true, {
|
||||
record: data,
|
||||
isUpdate: true,
|
||||
});
|
||||
appStore.setMessageHrefParams('')
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleSuccess() {
|
||||
selectedRowKeys.value = [];
|
||||
reload();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除我的消息
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
async function handleDelete(id) {
|
||||
await deleteAnnSend({ id: id }, handleSuccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除我的消息
|
||||
*/
|
||||
async function batchHandleDelete() {
|
||||
let unRead = unref(selectedRows).filter((item) => item.readFlag == 0);
|
||||
if (unref(unRead).length > 0) {
|
||||
createMessage.warning('未阅读的消息禁止删除!');
|
||||
return;
|
||||
}
|
||||
await deleteBatchAnnSend({ ids: selectedRowKeys.value }, handleSuccess);
|
||||
}
|
||||
</script>
|
||||
94
jeecgboot-vue3/src/views/monitor/mynews/mynews.api.ts
Normal file
94
jeecgboot-vue3/src/views/monitor/mynews/mynews.api.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { defHttp } from '/@/utils/http/axios';
|
||||
import { Modal } from 'ant-design-vue';
|
||||
|
||||
enum Api {
|
||||
list = '/sys/sysAnnouncementSend/getMyAnnouncementSend',
|
||||
editCementSend = '/sys/sysAnnouncementSend/editByAnntIdAndUserId',
|
||||
readAllMsg = '/sys/sysAnnouncementSend/readAll',
|
||||
syncNotic = '/sys/annountCement/syncNotic',
|
||||
getOne = '/sys/sysAnnouncementSend/getOne',
|
||||
delete = '/sys/sysAnnouncementSend/delete',
|
||||
deleteBatch = '/sys/sysAnnouncementSend/deleteBatch',
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询消息列表
|
||||
* @param params
|
||||
*/
|
||||
export const getMyNewsList = (params) => {
|
||||
return defHttp.get({ url: Api.list, params });
|
||||
};
|
||||
|
||||
/**
|
||||
* 更新用户系统消息阅读状态
|
||||
* @param params
|
||||
*/
|
||||
export const editCementSend = (params) => {
|
||||
return defHttp.put({ url: Api.editCementSend, params });
|
||||
};
|
||||
|
||||
/**
|
||||
* 一键已读
|
||||
* @param params
|
||||
*/
|
||||
export const readAllMsg = (params, handleSuccess) => {
|
||||
Modal.confirm({
|
||||
title: '确认操作',
|
||||
content: '是否全部标注已读?',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.put({ url: Api.readAllMsg, data: params }, { joinParamsToUrl: true }).then(() => {
|
||||
handleSuccess();
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 同步消息
|
||||
* @param params
|
||||
*/
|
||||
export const syncNotic = (params) => {
|
||||
return defHttp.get({ url: Api.syncNotic, params });
|
||||
};
|
||||
|
||||
/**
|
||||
* 根据消息发送记录ID获取消息内容
|
||||
* @param sendId
|
||||
*/
|
||||
export const getOne = (sendId) => {
|
||||
return defHttp.get({ url: Api.getOne, params:{sendId} });
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除用户通告阅读标记的数据
|
||||
* @param params
|
||||
* @param handleSuccess
|
||||
*/
|
||||
export const deleteAnnSend = (params, handleSuccess) =>{
|
||||
return defHttp.delete({ url: Api.delete, params }, { joinParamsToUrl: true }).then(()=>{
|
||||
handleSuccess();
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除用户通告阅读标记的数据
|
||||
* @param params
|
||||
* @param handleSuccess
|
||||
*/
|
||||
export const deleteBatchAnnSend = (params, handleSuccess) =>{
|
||||
Modal.confirm({
|
||||
iconType: 'warning',
|
||||
title: '确认删除',
|
||||
content: '是否删除选中数据',
|
||||
okText: '确认',
|
||||
cancelText: '取消',
|
||||
onOk: () => {
|
||||
return defHttp.delete({ url: Api.deleteBatch, params }, { joinParamsToUrl: true }).then(()=>{
|
||||
handleSuccess();
|
||||
})
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
102
jeecgboot-vue3/src/views/monitor/mynews/mynews.data.ts
Normal file
102
jeecgboot-vue3/src/views/monitor/mynews/mynews.data.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
import { BasicColumn, FormSchema } from '/@/components/Table';
|
||||
import { render } from '/@/utils/common/renderUtils';
|
||||
|
||||
export const columns: BasicColumn[] = [
|
||||
{
|
||||
title: '标题',
|
||||
dataIndex: 'titile',
|
||||
width: 100,
|
||||
align: 'left',
|
||||
},
|
||||
{
|
||||
title: '消息类型',
|
||||
dataIndex: 'msgCategory',
|
||||
width: 80,
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDictNative(
|
||||
text,
|
||||
[
|
||||
{ label: '通知公告', value: '1', color: 'blue' },
|
||||
{ label: '系统消息', value: '2' },
|
||||
],
|
||||
true
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '发布人',
|
||||
dataIndex: 'sender',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '发布时间',
|
||||
dataIndex: 'sendTime',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '优先级',
|
||||
dataIndex: 'priority',
|
||||
width: 80,
|
||||
customRender: ({ text }) => {
|
||||
const color = text == 'L' ? 'blue' : text == 'M' ? 'yellow' : 'red';
|
||||
return render.renderTag(render.renderDict(text, 'priority'), color);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '阅读状态',
|
||||
dataIndex: 'readFlag',
|
||||
width: 80,
|
||||
customRender: ({ text }) => {
|
||||
return render.renderDictNative(
|
||||
text,
|
||||
[
|
||||
{ label: '未读', value: '0', color: 'red' },
|
||||
{ label: '已读', value: '1' },
|
||||
],
|
||||
true
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const searchFormSchema: FormSchema[] = [
|
||||
{
|
||||
field: 'titile',
|
||||
label: '标题',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
field: 'sender',
|
||||
label: '发布人',
|
||||
component: 'Input',
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
field: 'sendTime',
|
||||
label: '发布时间',
|
||||
component: 'RangeDate',
|
||||
componentProps: {
|
||||
valueType: 'Date',
|
||||
},
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
{
|
||||
field: 'msgCategory',
|
||||
label: '消息类型',
|
||||
component: 'Select',
|
||||
componentProps: {
|
||||
options: [
|
||||
{ label: '通知公告', value: '1' },
|
||||
{ label: '系统消息', value: '2' },
|
||||
{ label: '日程计划', value: 'plan' },
|
||||
{ label: '流程消息', value: 'flow' },
|
||||
{ label: '会议', value: 'meeting' },
|
||||
{ label: '知识库', value: 'file' },
|
||||
{ label: '协同通知', value: 'collab' },
|
||||
{ label: '督办通知', value: 'supe' },
|
||||
],
|
||||
},
|
||||
colProps: { span: 6 },
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user