初始化项目

This commit is contained in:
2026-03-25 22:34:17 +08:00
parent 39db00e022
commit c3e7288953
18 changed files with 214 additions and 93 deletions

View File

@@ -0,0 +1,50 @@
package com.jeesite.modules.apps.Module;
import lombok.Data;
import java.io.Serializable;
@Data
public class FileList implements Serializable {
private String filePath;
private String fileName;
private String fileType;
private String fileIcon;
private String fileSize;
public FileList() {
}
public FileList(String filePath, String fileName, String fileType, String fileSize) {
this.filePath = filePath;
this.fileName = fileName;
this.fileType = fileType;
this.fileIcon = getIcon(fileType);
this.fileSize = fileSize;
}
private String getIcon(String type) {
switch (type) {
case "gz":
return "icons/file-gz.png";
case "py":
return "icons/file-py.png";
case "pdf":
return "icons/file-pdf.png";
case "sql":
return "icons/file-sql.png";
case "zip":
return "icons/file-zip.png";
case "ppt", "pptx":
return "icons/file-pptx.png";
case "xls", "xlsx":
return "icons/file-xlsx.png";
case "wps", "doc", "docx":
return "icons/file-wps.png";
default:
return "icons/file.png";
}
}
}

View File

@@ -48,7 +48,7 @@ import java.io.Serial;
@Column(name = "user_name", attrName = "userName", label = "接收姓名", isQuery = false),
@Column(name = "create_user", attrName = "createUser", label = "创建用户", isQuery = false, isUpdate = false, isUpdateForce = true),
@Column(name = "login_user", attrName = "loginUser", label = "接收用户"),
}, orderBy = "a.id DESC"
}, orderBy = "a.create_time DESC"
)
@Data
public class MyNoticeTodo extends DataEntity<MyNoticeTodo> implements Serializable {

View File

@@ -1,10 +1,17 @@
package com.jeesite.modules.biz.web;
import java.io.File;
import java.util.*;
import java.util.stream.Collectors;
import com.jeesite.common.io.FileUtils;
import com.jeesite.modules.apps.Module.FileList;
import com.jeesite.modules.apps.Module.TabItem;
import com.jeesite.modules.apps.dict.NotifyType;
import com.jeesite.modules.file.entity.FileUpload;
import com.jeesite.modules.file.utils.FileUploadUtils;
import com.jeesite.modules.sys.entity.User;
import com.jeesite.modules.sys.utils.UserUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
@@ -91,6 +98,9 @@ public class MyNoticeTodoController extends BaseController {
@PostMapping(value = "save")
@ResponseBody
public String save(@Validated MyNoticeTodo myNoticeTodo) {
User user = UserUtils.getUser();
myNoticeTodo.setAvatar(user.getAvatar());
myNoticeTodo.setCreateUser(user.getLoginCode());
myNoticeTodoService.save(myNoticeTodo);
return renderResult(Global.TRUE, text("保存消息成功!"));
}
@@ -148,6 +158,34 @@ public class MyNoticeTodoController extends BaseController {
return renderResult(Global.TRUE, text("删除消息成功!"));
}
@RequestMapping(value = "listAll")
@ResponseBody
public List<MyNoticeTodo> listAll(MyNoticeTodo myNoticeTodo) {
return myNoticeTodoService.findList(myNoticeTodo);
}
@RequestMapping(value = "fileList")
@ResponseBody
public List<FileList> fileList(MyNoticeTodo myNoticeTodo) {
List<FileList> fileLists = new ArrayList<>();
List<FileUpload> fileUploadList = FileUploadUtils.findFileUpload(myNoticeTodo.getId(), "myNoticeTodo_file");
for (FileUpload fileUpload : fileUploadList) {
fileLists.add(new FileList(fileUpload.getFileUrl(), fileUpload.getFileName(), fileUpload.getFileEntity().getFileExtension(), fileUpload.getFileEntity().getFileSizeFormat()));
}
return fileLists;
}
@RequestMapping(value = "downloadFile")
@ResponseBody
public void downloadFile(HttpServletRequest request, HttpServletResponse response, FileList fileList) {
try {
File file = new File("/ogsapp/files/" + fileList.getFilePath());
FileUtils.downFile(file, request, response, fileList.getFileName());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
@RequestMapping(value = "tabListData")
@ResponseBody

View File

@@ -43,12 +43,27 @@ export interface TabItem {
unreadlist?: MyNoticeTodo[];
}
export interface MyFileList {
filePath: string;
fileName: string;
fileType?: number;
fileIcon?: string;
fileSize?: string;
}
export const tabListDataAll = (params?: MyNoticeTodo | any) =>
defHttp.get<TabItem[]>({ url: adminPath + '/biz/myNoticeTodo/tabListData', params});
export const myNoticeTodoList = (params?: MyNoticeTodo | any) =>
defHttp.get<MyNoticeTodo>({ url: adminPath + '/biz/myNoticeTodo/list', params });
export const myNoticeTodoFileList = (params?: MyNoticeTodo | any) =>
defHttp.get<MyFileList[]>({ url: adminPath + '/biz/myNoticeTodo/fileList', params });
export const myNoticeTodoListAll = (params?: MyNoticeTodo | any) =>
defHttp.get<MyNoticeTodo[]>({ url: adminPath + '/biz/myNoticeTodo/listAll', params });
export const myNoticeTodoListData = (params?: MyNoticeTodo | any) =>
defHttp.post<Page<MyNoticeTodo>>({ url: adminPath + '/biz/myNoticeTodo/listData', params });

View File

@@ -130,6 +130,7 @@
sorter: true,
width: 130,
align: 'center',
dictType: 'msg_type',
},
{
title: t('是否已读'),
@@ -138,6 +139,7 @@
sorter: true,
width: 130,
align: 'center',
dictType: 'read_flag',
},
{
title: t('是否关闭'),
@@ -146,6 +148,7 @@
sorter: true,
width: 130,
align: 'center',
dictType: 'click_close',
},
{
title: t('额外信息'),
@@ -186,6 +189,7 @@
sorter: true,
width: 130,
align: 'center',
dictType: 'notice_status',
},
];

View File

@@ -103,13 +103,13 @@ const tableProps: BasicTableProps = {
},
columns: tableColumns,
formConfig: searchForm,
rowKey: 'userCode',
rowKey: 'loginCode',
};
export default {
modalProps,
tableProps,
itemCode: 'userCode',
itemCode: 'loginCode',
itemName: 'userName',
isShowCode: true,
};

View File

@@ -7,7 +7,7 @@
v-for="item in tabs"
:key="item.key"
:class="['tab-item', { active: activeTab === item.key }]"
@click="activeTab = item.key"
@click="handleTabChange(item.key)"
>
{{ item.label }}
</button>
@@ -15,52 +15,56 @@
</div>
<div class="card-content">
<div ref="tableWrapRef" class="table-container">
<el-table :data="currentList" :height="tableHeight" :show-header="true" :border="false">
<el-table-column prop="title" label="标题" min-width="120">
<el-table :data="listData" :height="tableHeight" :show-header="true" :border="false">
<el-table-column prop="title" label="标题" min-width="120" show-overflow-tooltip="true" />
<el-table-column prop="datetime" label="到期时间" width="180" />
<el-table-column label="操作" width="90" align="center" fixed="right">
<template #default="{ row }">
<el-button class="notice-title-button" link type="primary" @click="openNoticeDialog(row)">
{{ row.title }}
<el-button class="notice-action-button" link type="primary" @click="openNoticeDialog(row)">
查看
</el-button>
</template>
</el-table-column>
<el-table-column prop="time" label="时间" width="180" />
<el-table-column prop="content" label="内容" min-width="200" show-overflow-tooltip="true" />
</el-table>
</div>
</div>
<el-dialog v-model="dialogVisible" class="notice-info-dialog" title="通知详情" width="60%" destroy-on-close>
<el-dialog v-model="dialogVisible" class="notice-info-dialog" title="通知详情" width="50%" destroy-on-close>
<template v-if="selectedNotice">
<div class="notice-dialog">
<div class="notice-dialog__header">
<div class="notice-dialog__title">{{ selectedNotice.title }}</div>
<div class="notice-dialog__header-divider"></div>
<div class="notice-dialog__time">{{ selectedNotice.time }}</div>
<div class="notice-dialog__time">
<div class="notice-dialog__time-left">
<span>发布时间{{ selectedNotice.createTime }}</span>
<span>发布人{{ selectedNotice.createUser }}</span>
</div>
<div class="notice-dialog__time-right">截至时间{{ selectedNotice.datetime }}</div>
</div>
</div>
<el-divider class="notice-dialog__divider" />
<div class="notice-dialog__content-panel">
<div class="notice-dialog__content" v-html="selectedNotice.content"></div>
<div class="notice-dialog__content" v-html="selectedNotice.description"></div>
</div>
<div v-if="selectedNotice.attachments?.length" class="notice-dialog__attachments-panel">
<div class="notice-dialog__attachments-title">附件区域</div>
<div v-if="fileData?.length" class="notice-dialog__attachments-panel">
<div class="notice-dialog__attachments-title">附件区域({{ fileData?.length }})</div>
<div class="notice-dialog__attachments-list">
<div
v-for="attachment in selectedNotice.attachments"
:key="attachment"
class="notice-dialog__attachment-item"
>
<div v-for="item in fileData" :key="item" class="notice-dialog__attachment-item">
<div class="notice-dialog__attachment-meta">
<el-icon class="notice-dialog__attachment-icon"><Document /></el-icon>
<span class="notice-dialog__attachment-name">{{ attachment }}</span>
<Icon :icon="item.fileIcon" class="icon-img" size="24" />
<el-tooltip :content="item.fileName" placement="top" :show-after="200">
<span class="notice-dialog__attachment-name">{{ item.fileName }}</span>
</el-tooltip>
</div>
<div class="notice-dialog__attachment-actions">
<span class="notice-dialog__attachment-size">{{ getAttachmentSize(attachment) }}</span>
<span class="notice-dialog__attachment-size">{{ item.fileSize }}</span>
<el-button
class="notice-dialog__attachment-download"
type="primary"
link
:icon="Download"
@click.stop="handleAttachmentDownload(attachment)"
@click.stop="handleDownload(item)"
>下载</el-button
>
</div>
@@ -75,15 +79,17 @@
<script setup lang="ts">
import { ElMessage } from 'element-plus';
import { Icon } from '@jeesite/core/components/Icon';
import { Document, Download } from '@element-plus/icons-vue';
import { useGlobSetting } from '@jeesite/core/hooks/setting';
import { downloadByUrl } from '@jeesite/core/utils/file/download';
import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue';
interface NoticeItem {
title: string;
time: string;
content: string;
attachments?: string[];
}
import {
MyFileList,
myNoticeTodoFileList,
MyNoticeTodo,
myNoticeTodoListAll,
} from '@jeesite/biz/api/biz/myNoticeTodo';
const tabs = [
{ key: '0', label: '未读' },
@@ -91,74 +97,28 @@
];
const activeTab = ref('0');
const fileData = ref<MyFileList[]>([]);
const listData = ref<MyNoticeTodo[]>([]);
const noticeData: Record<string, NoticeItem[]> = {
0: [
{
title: '系统升级通知',
time: '2025-03-25 10:00',
content: '<p>系统将于今晚进行升级维护,请提前保存工作内容。</p><p><strong>维护时间:</strong>23:00 - 02:00</p>',
attachments: [
'升级说明.pdf',
'影响范围清单.xlsx',
'系统切换流程.docx',
'升级回退预案.pdf',
'服务影响通知单.xls',
'值班安排表.doc',
'数据库检查项.txt',
],
},
{
title: '安全检查提醒',
time: '2025-03-25 09:30',
content:
'<p>请及时完成本周安全检查任务,确保系统运行稳定。</p><ul><li>检查设备运行状态</li><li>确认日志采集是否正常</li></ul>',
attachments: ['安全检查模板.docx', '巡检项清单.pdf', '整改说明.docx', '告警记录.xlsx'],
},
{
title: '备份任务完成',
time: '2025-03-25 08:15',
content: '<p>数据库备份任务已完成,备份文件已存储至指定位置。</p>',
attachments: [],
},
],
1: [
{
title: '巡检报告提交',
time: '2025-03-24 16:20',
content: '<p>昨日巡检报告已提交并审核通过。</p><p>请相关负责人及时查看结果。</p>',
attachments: ['巡检报告-0324.pdf'],
},
{
title: '权限变更通知',
time: '2025-03-24 14:10',
content: '<p>用户权限调整已生效,请相关人员知悉。</p>',
attachments: [],
},
],
};
const currentList = computed(() => noticeData[activeTab.value] || []);
const tableWrapRef = ref<HTMLElement>();
const tableHeight = ref(0);
const dialogVisible = ref(false);
const selectedNotice = ref<NoticeItem | null>(null);
const selectedNotice = ref<MyNoticeTodo | null>(null);
let resizeObserver: ResizeObserver | null = null;
function openNoticeDialog(notice: NoticeItem) {
function openNoticeDialog(notice: MyNoticeTodo) {
getFileList(notice.id);
selectedNotice.value = notice;
dialogVisible.value = true;
}
function handleAttachmentDownload(attachment: string) {
ElMessage.info(`待接入下载地址:${attachment}`);
}
function getAttachmentSize(attachment: string) {
const seed = attachment.split('').reduce((total, char) => total + char.charCodeAt(0), 0);
return `${((seed % 9000) / 100 + 0.8).toFixed(2)} MB`;
async function handleDownload(item: MyFileList) {
const { ctxAdminPath } = useGlobSetting();
await downloadByUrl({
url: ctxAdminPath + '/biz/myNoticeTodo/downloadFile',
params: item,
});
}
function updateTableHeight() {
@@ -169,7 +129,42 @@
});
}
function handleTabChange(tabKey: string) {
if (activeTab.value === tabKey) return;
activeTab.value = tabKey;
getDataList();
}
const getDataList = async () => {
try {
const reqParams = {
type: '1',
clickClose: '0',
readFlag: activeTab.value,
};
const result = await myNoticeTodoListAll(reqParams);
listData.value = result || [];
} catch (error) {
listData.value = [];
}
};
const getFileList = async (bizId: string) => {
try {
const reqParams = {
id: bizId,
};
const result = await myNoticeTodoFileList(reqParams);
fileData.value = result || [];
console.log(fileData.value);
} catch (error) {
fileData.value = [];
}
};
onMounted(() => {
getDataList();
updateTableHeight();
if (tableWrapRef.value) {
resizeObserver = new ResizeObserver(() => {
@@ -296,12 +291,16 @@
line-height: 20px;
}
.notice-title-button {
.notice-action-button {
padding: 0;
font-weight: 500;
text-align: left;
white-space: normal;
word-break: break-all;
}
.notice-description {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: rgb(71 85 105);
}
}
}
@@ -352,8 +351,23 @@
}
&__time {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
font-size: 13px;
color: rgb(100 116 139);
}
&__time-left {
display: flex;
align-items: center;
gap: 16px;
min-width: 0;
}
&__time-right {
flex-shrink: 0;
text-align: right;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB