add notification page
Change-Id: I494df384bd5f8a20e3ace394d0a8b73161fa036d
diff --git a/src/app/notification/page.tsx b/src/app/notification/page.tsx
index c48b626..9e83252 100644
--- a/src/app/notification/page.tsx
+++ b/src/app/notification/page.tsx
@@ -1,12 +1,161 @@
'use client';
-import React from 'react';
-const EmptyPage: React.FC = () => {
- return (
- <div className="p-d-flex p-jc-center p-ai-center" style={{ height: '100vh' }}>
- {"一个空页面"}
+import React, { useEffect, useRef, useState } from 'react';
+import axios from 'axios';
+import { DataTable } from 'primereact/datatable';
+import { Column } from 'primereact/column';
+import { Sidebar } from 'primereact/sidebar';
+import { Button } from 'primereact/button';
+import { Tag } from 'primereact/tag';
+import { Toast } from 'primereact/toast';
+import { Paginator, PaginatorPageChangeEvent } from 'primereact/paginator';
+import { Card } from 'primereact/card';
+import { TabView, TabPanel } from 'primereact/tabview'; // ✅ TabView 导入
+
+import './notification.scss';
+
+interface Notification {
+ notificationId: number;
+ title: string;
+ content: string;
+ createAt: string;
+ isRead: boolean;
+ triggeredBy: number;
+ relatedId: number;
+}
+
+export default function NotificationPage() {
+ const toast = useRef<Toast>(null);
+ const [notifications, setNotifications] = useState<Notification[]>([]);
+ const [selectedNotification, setSelectedNotification] = useState<Notification | null>(null);
+ const [visible, setVisible] = useState<boolean>(false);
+ const [activeTab, setActiveTab] = useState<number>(0); // ✅ 当前 Tab 下标
+
+ // 分页相关
+ const [first, setFirst] = useState<number>(0);
+ const [rows, setRows] = useState<number>(5);
+ const [totalRecords, setTotalRecords] = useState<number>(0);
+
+ // 加载数据
+ const fetchNotifications = async () => {
+ try {
+ const pageNumber = first / rows + 1;
+ const res = await axios.get(process.env.PUBLIC_URL + '/notification', {
+ params: { pageNumber, rows, userId: 22301145 },
+ });
+ const { records, total } = res.data;
+ setNotifications(records);
+ setTotalRecords(total);
+ } catch (error) {
+ console.error('无法获取通知数据', error);
+ toast.current?.show({ severity: 'error', summary: '加载失败', detail: '无法获取通知数据' });
+ }
+ };
+
+ useEffect(() => {
+ fetchNotifications();
+ }, [first, rows]); // ✅ 加入分页依赖
+
+ const handleRead = async (id: number) => {
+ try {
+ await axios.post(process.env.PUBLIC_URL + '/notification/read', { notificationId: id });
+ setNotifications(prev =>
+ prev.map(n => (n.notificationId === id ? { ...n, isRead: true } : n))
+ );
+ } catch (error) {
+ console.error('已读失败', error);
+ toast.current?.show({ severity: 'error', summary: '设置已读失败' });
+ }
+ };
+
+ const handleDelete = async (id: number) => {
+ try {
+ await axios.delete(process.env.PUBLIC_URL + '/notification', { data: { notificationId: id } });
+ setNotifications(prev => prev.filter(n => n.notificationId !== id));
+ toast.current?.show({ severity: 'success', summary: '删除成功' });
+ } catch (error) {
+ console.error('删除失败', error);
+ toast.current?.show({ severity: 'error', summary: '删除失败' });
+ }
+ };
+
+ const openSidebar = (notification: Notification) => {
+ if (!notification.isRead) handleRead(notification.notificationId);
+ setSelectedNotification(notification);
+ setVisible(true);
+ };
+
+ const readTemplate = (rowData: Notification) => (
+ <Tag value={rowData.isRead ? '已读' : '未读'} severity={rowData.isRead ? undefined : 'warning'} />
+ );
+
+ const actionTemplate = (rowData: Notification) => (
+ <div className="actions">
+ {!rowData.isRead && (
+ <Button
+ icon="pi pi-check"
+ text
+ severity="success"
+ onClick={() => handleRead(rowData.notificationId)}
+ tooltip="标记为已读"
+ />
+ )}
+ <Button icon="pi pi-times" severity="danger" text onClick={() => handleDelete(rowData.notificationId)} />
</div>
);
-};
-export default EmptyPage;
+ const onPageChange = (e: PaginatorPageChangeEvent) => {
+ setFirst(e.first);
+ setRows(e.rows);
+ };
+
+ const unreadNotifications = notifications.filter(n => !n.isRead);
+ const readNotifications = notifications.filter(n => n.isRead);
+
+ return (
+ <div className="notification-page">
+ <Toast ref={toast} />
+ <h2>系统通知</h2>
+
+ <TabView activeIndex={activeTab} onTabChange={(e) => setActiveTab(e.index)}>
+ <TabPanel header="未读通知">
+ <DataTable value={unreadNotifications} paginator={false} emptyMessage="暂无未读通知">
+ <Column field="title" header="标题" body={(row) => (
+ <span className="title-link" onClick={() => openSidebar(row)}>{row.title}</span>
+ )} />
+ <Column field="createAt" header="时间" />
+ <Column field="isRead" header="状态" body={readTemplate} />
+ <Column header="操作" style={{ width: '120px', textAlign: 'center' }} body={actionTemplate} />
+ </DataTable>
+ </TabPanel>
+ <TabPanel header="已读通知">
+ <DataTable value={readNotifications} paginator={false} emptyMessage="暂无已读通知">
+ <Column field="title" header="标题" body={(row) => (
+ <span className="title-link" onClick={() => openSidebar(row)}>{row.title}</span>
+ )} />
+ <Column field="createAt" header="时间" />
+ <Column field="isRead" header="状态" body={readTemplate} />
+ <Column header="操作" style={{ width: '120px', textAlign: 'center' }} body={actionTemplate} />
+ </DataTable>
+ </TabPanel>
+ </TabView>
+
+ <Paginator
+ className="Paginator"
+ first={first}
+ rows={rows}
+ totalRecords={totalRecords}
+ onPageChange={onPageChange}
+ rowsPerPageOptions={[5, 10, 20]}
+ />
+
+ <Sidebar visible={visible} position="right" onHide={() => setVisible(false)} className="p-sidebar-md">
+ {selectedNotification && (
+ <Card title={selectedNotification.title} subTitle={selectedNotification.createAt}>
+ <p className="m-0">{selectedNotification.content}</p>
+ </Card>
+ )}
+ </Sidebar>
+ </div>
+ );
+}