diff --git a/back/api/system.ts b/back/api/system.ts index f51c6575..23e557b6 100644 --- a/back/api/system.ts +++ b/back/api/system.ts @@ -374,6 +374,19 @@ export default (app: Router) => { }, ); + route.get( + '/notify-log', + async (req: Request, res: Response, next: NextFunction) => { + try { + const systemService = Container.get(SystemService); + const data = await systemService.getNotifyLog(); + res.send({ code: 200, data }); + } catch (e) { + return next(e); + } + }, + ); + route.delete( '/log', async (req: Request, res: Response, next: NextFunction) => { diff --git a/back/data/system.ts b/back/data/system.ts index 2dc14f50..8c463dfe 100644 --- a/back/data/system.ts +++ b/back/data/system.ts @@ -28,6 +28,12 @@ export enum AuthDataType { 'removeLogFrequency' = 'removeLogFrequency', 'systemConfig' = 'systemConfig', 'authConfig' = 'authConfig', + 'notifyLog' = 'notifyLog', +} + +export enum NotifyStatus { + 'success', + 'fail', } export interface SystemConfigInfo { @@ -49,6 +55,14 @@ export interface LoginLogInfo { status?: LoginStatus; } +export interface NotifyLogInfo { + timestamp?: number; + title?: string; + content?: string; + status?: NotifyStatus; + notifyType?: string; +} + export interface TokenInfo { value: string; timestamp: number; @@ -81,6 +95,7 @@ export interface AuthInfo { export type SystemModelInfo = SystemConfigInfo & Partial & LoginLogInfo & + Partial & Partial; export interface SystemInstance diff --git a/back/services/system.ts b/back/services/system.ts index ecc2a732..c3bb467a 100644 --- a/back/services/system.ts +++ b/back/services/system.ts @@ -30,6 +30,8 @@ import { SystemInstance, SystemModel, SystemModelInfo, + NotifyStatus, + NotifyLogInfo, } from '../data/system'; import taskLimit from '../shared/pLimit'; import NotificationService from './notify'; @@ -389,11 +391,33 @@ export default class SystemService { if (notificationInfo && typeString) { notificationInfo.type = typeString; } + + let notifyType: string | undefined; + try { + const notifConfig = await this.getDb({ type: AuthDataType.notification }); + notifyType = notifConfig.info?.type as string | undefined; + } catch (e) {} + if (notificationInfo?.type) { + notifyType = typeString || (notificationInfo.type as string); + } + const isSuccess = await this.notificationService.notify( title, content, notificationInfo, ); + + await SystemModel.create({ + type: AuthDataType.notifyLog, + info: { + timestamp: Date.now(), + title, + content, + status: isSuccess ? NotifyStatus.success : NotifyStatus.fail, + notifyType, + }, + }); + if (isSuccess) { return { code: 200, message: '通知发送成功' }; } else { @@ -401,6 +425,18 @@ export default class SystemService { } } + public async getNotifyLog(): Promise> { + const docs = await SystemModel.findAll({ + where: { type: AuthDataType.notifyLog }, + order: [['id', 'DESC']], + }); + if (docs.length > 200) { + const ids = docs.slice(200).map((x) => x.id!); + await SystemModel.destroy({ where: { id: ids } }); + } + return docs.slice(0, 200).map((x) => ({ ...x.info, id: x.id })); + } + public async run({ command, logPath }: { command: string; logPath?: string }, callback: TaskCallbacks) { if (!command.startsWith(TASK_COMMAND)) { command = `${TASK_COMMAND} ${command}`; diff --git a/src/pages/setting/index.tsx b/src/pages/setting/index.tsx index a3242536..f3b1853a 100644 --- a/src/pages/setting/index.tsx +++ b/src/pages/setting/index.tsx @@ -26,6 +26,7 @@ import { } from '@ant-design/icons'; import SecuritySettings from './security'; import LoginLog from './loginLog'; +import NotifyLog from './notifyLog'; import NotificationSetting from './notification'; import Other from './other'; import About from './about'; @@ -125,6 +126,7 @@ const Setting = () => { const [editedApp, setEditedApp] = useState(); const [tabActiveKey, setTabActiveKey] = useState('security'); const [loginLogData, setLoginLogData] = useState([]); + const [notifyLogData, setNotifyLogData] = useState([]); const [notificationInfo, setNotificationInfo] = useState(); const containergRef = useRef(null); const [height, setHeight] = useState(0); @@ -253,6 +255,8 @@ const Setting = () => { getApps(); } else if (activeKey === 'login') { getLoginLog(); + } else if (activeKey === 'notifylog') { + getNotifyLog(); } else if (activeKey === 'notification') { getNotification(); } @@ -271,6 +275,19 @@ const Setting = () => { }); }; + const getNotifyLog = () => { + request + .get(`${config.apiPrefix}system/notify-log`) + .then(({ code, data }) => { + if (code === 200) { + setNotifyLogData(data); + } + }) + .catch((error: any) => { + console.log(error); + }); + }; + useEffect(() => { if (isDemoEnv) { getApps(); @@ -344,6 +361,11 @@ const Setting = () => { label: intl.get('登录日志'), children: , }, + { + key: 'notifylog', + label: intl.get('通知日志'), + children: , + }, { key: 'dependence', label: intl.get('依赖设置'), diff --git a/src/pages/setting/notifyLog.tsx b/src/pages/setting/notifyLog.tsx new file mode 100644 index 00000000..de466296 --- /dev/null +++ b/src/pages/setting/notifyLog.tsx @@ -0,0 +1,93 @@ +import intl from 'react-intl-universal'; +import React from 'react'; +import { Table, Tag } from 'antd'; +import dayjs from 'dayjs'; + +enum NotifyStatus { + '成功', + '失败', +} + +enum NotifyStatusColor { + 'success', + 'error', +} + +const columns = [ + { + title: intl.get('序号'), + width: 50, + render: (text: string, record: any, index: number) => { + return index + 1; + }, + }, + { + title: intl.get('发送时间'), + dataIndex: 'timestamp', + key: 'timestamp', + width: 160, + render: (text: string, record: any) => { + return dayjs(record.timestamp).format('YYYY-MM-DD HH:mm:ss'); + }, + }, + { + title: intl.get('标题'), + dataIndex: 'title', + key: 'title', + width: 200, + }, + { + title: intl.get('内容'), + dataIndex: 'content', + key: 'content', + render: (text: string) => { + if (!text) return ''; + return text.length > 100 ? text.slice(0, 100) + '...' : text; + }, + }, + { + title: intl.get('推送渠道'), + dataIndex: 'notifyType', + key: 'notifyType', + width: 120, + }, + { + title: intl.get('发送状态'), + dataIndex: 'status', + key: 'status', + width: 90, + render: (text: string, record: any) => { + return ( + + {intl.get(NotifyStatus[record.status])} + + ); + }, + }, +]; + +const NotifyLog = ({ + data, + height, +}: { + data: Array; + height: number; +}) => { + return ( + <> + + + ); +}; + +export default NotifyLog;