From 6f48ff656b79a4b7ffda80deaf0d1bb8b7f06988 Mon Sep 17 00:00:00 2001 From: susie-laptop Date: Wed, 19 Mar 2025 22:01:09 -0400 Subject: [PATCH] [dev]notificationcenter & setting --- public/index.html | 12 + src/components/NotificationCenter.jsx | 214 ++++++++++++++++++ src/components/UserSettingsModal.jsx | 101 +++++++++ src/icons/icons.js | 4 +- src/layouts/HeaderWithNav.jsx | 104 +++++---- src/pages/Chat/ChatWindow.jsx | 30 ++- src/pages/Chat/NewChat.jsx | 2 +- src/pages/Permissions/PermissionsPage.jsx | 4 +- .../components/PendingRequests.jsx | 142 +++--------- .../components/RequestDetailSlideOver.jsx | 124 ++++++++++ .../components/UserPermissions.jsx | 202 ++--------------- src/services/mockApi.js | 70 +++--- src/store/chat/chat.slice.js | 33 ++- .../notificationCenter.slice.js | 64 ++++++ src/store/permissions/permissions.slice.js | 106 ++++++--- src/store/permissions/permissions.thunks.js | 95 +++++++- src/store/store.js | 2 + src/styles/style.scss | 99 +++++++- 18 files changed, 966 insertions(+), 442 deletions(-) create mode 100644 public/index.html create mode 100644 src/components/NotificationCenter.jsx create mode 100644 src/components/UserSettingsModal.jsx create mode 100644 src/pages/Permissions/components/RequestDetailSlideOver.jsx create mode 100644 src/store/notificationCenter/notificationCenter.slice.js diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..9da09c4 --- /dev/null +++ b/public/index.html @@ -0,0 +1,12 @@ + + + + + + OOIN 智能知识库 + + + +
+ + \ No newline at end of file diff --git a/src/components/NotificationCenter.jsx b/src/components/NotificationCenter.jsx new file mode 100644 index 0000000..545383b --- /dev/null +++ b/src/components/NotificationCenter.jsx @@ -0,0 +1,214 @@ +import React, { useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import { clearNotifications } from '../store/notificationCenter/notificationCenter.slice'; +import RequestDetailSlideOver from '../pages/Permissions/components/RequestDetailSlideOver'; +import { approvePermissionThunk, rejectPermissionThunk } from '../store/permissions/permissions.thunks'; +import { showNotification } from '../store/notification.slice'; + +export default function NotificationCenter({ show, onClose }) { + const [showAll, setShowAll] = useState(false); + const dispatch = useDispatch(); + const { notifications } = useSelector((state) => state.notificationCenter); + const [selectedRequest, setSelectedRequest] = useState(null); + const [showSlideOver, setShowSlideOver] = useState(false); + const [showResponseInput, setShowResponseInput] = useState(false); + const [currentRequestId, setCurrentRequestId] = useState(null); + const [isApproving, setIsApproving] = useState(false); + const [responseMessage, setResponseMessage] = useState(''); + + const displayedNotifications = showAll ? notifications : notifications.slice(0, 2); + + const handleClearAll = () => { + dispatch(clearNotifications()); + }; + + const handleViewDetail = (notification) => { + if (notification.type === 'permission') { + setSelectedRequest(notification); + setShowSlideOver(true); + } + }; + + const handleCloseSlideOver = () => { + setShowSlideOver(false); + setTimeout(() => { + setSelectedRequest(null); + }, 300); + }; + + const handleOpenResponseInput = (requestId, approving) => { + setCurrentRequestId(requestId); + setIsApproving(approving); + setShowResponseInput(true); + }; + + const handleCloseResponseInput = () => { + setShowResponseInput(false); + setCurrentRequestId(null); + setResponseMessage(''); + }; + + const handleProcessRequest = () => { + if (!currentRequestId) return; + + const params = { + id: currentRequestId, + responseMessage, + }; + + if (isApproving) { + dispatch(approvePermissionThunk(params)); + } else { + dispatch(rejectPermissionThunk(params)); + } + }; + + if (!show) return null; + + return ( + <> +
+
+
通知中心
+
+ + +
+
+
+ {displayedNotifications.map((notification) => ( +
+
+
+ +
+
+
+
{notification.title}
+ {notification.time} +
+

{notification.content}

+
+ {notification.hasDetail && ( + + )} +
+
+
+
+ ))} +
+
+ +
+
+ + {/* 使用滑动面板组件 */} + handleOpenResponseInput(id, true)} + onReject={(id) => handleOpenResponseInput(id, false)} + processingId={currentRequestId} + approveRejectStatus={showResponseInput ? 'loading' : 'idle'} + isApproving={isApproving} + /> + + {/* 回复输入弹窗 */} + {showResponseInput && ( +
+
+
+
+
{isApproving ? '批准' : '拒绝'}申请
+ +
+
+
+ + +
+
+
+ + +
+
+
+
+
+ )} + + ); +} diff --git a/src/components/UserSettingsModal.jsx b/src/components/UserSettingsModal.jsx new file mode 100644 index 0000000..73a0828 --- /dev/null +++ b/src/components/UserSettingsModal.jsx @@ -0,0 +1,101 @@ +import React, { useState } from 'react'; +import { useSelector } from 'react-redux'; +import '../styles/style.scss'; + +export default function UserSettingsModal({ show, onClose }) { + const { user } = useSelector((state) => state.auth); + const [lastPasswordChange] = useState('30天前'); // This would come from backend in real app + + if (!show) return null; + + return ( +
+
+
+
+
管理员个人设置
+ +
+
+
+
个人信息
+
+ + +
+
+ + +
+
+ +
+
安全设置
+
+
+
+ + 修改密码 +
+ 上次修改:{lastPasswordChange} +
+ +
+
+
+
+ + 双重认证 +
+ 增强账户安全性 +
+ +
+
+ +
+
通知设置
+
+ + +
新的数据集访问申请通知
+
+
+ + +
异常登录和权限变更提醒
+
+
+
+
+ + +
+
+
+
+ ); +} diff --git a/src/icons/icons.js b/src/icons/icons.js index 79c8a41..d559ece 100644 --- a/src/icons/icons.js +++ b/src/icons/icons.js @@ -101,5 +101,7 @@ export const icons = { chat: ``, 'arrowup-upload': ``, send: ``, - search: `` + search: ``, + bell: ``, + 'magnifying-glass': `` }; diff --git a/src/layouts/HeaderWithNav.jsx b/src/layouts/HeaderWithNav.jsx index a7eb64d..76abc4c 100644 --- a/src/layouts/HeaderWithNav.jsx +++ b/src/layouts/HeaderWithNav.jsx @@ -1,13 +1,19 @@ -import React from 'react'; +import React, { useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Link, useNavigate, useLocation } from 'react-router-dom'; import { logoutThunk } from '../store/auth/auth.thunk'; +import UserSettingsModal from '../components/UserSettingsModal'; +import NotificationCenter from '../components/NotificationCenter'; +import SvgIcon from '../components/SvgIcon'; export default function HeaderWithNav() { const dispatch = useDispatch(); const navigate = useNavigate(); const location = useLocation(); const { user } = useSelector((state) => state.auth); + const [showSettings, setShowSettings] = useState(false); + const [showNotifications, setShowNotifications] = useState(false); + const { notifications } = useSelector((state) => state.notificationCenter); const handleLogout = async () => { try { @@ -22,13 +28,13 @@ export default function HeaderWithNav() { return location.pathname.startsWith(path); }; console.log('user', user); - + // 检查用户是否有管理权限(leader 或 admin) const hasManagePermission = user && (user.role === 'leader' || user.role === 'admin'); return ( -
-