feat: 完善服务监控与下游重投
This commit is contained in:
+40
-13
@@ -50,6 +50,10 @@ export type AuditNotificationItem = {
|
||||
to: string;
|
||||
};
|
||||
|
||||
export type AlertNotificationItem = AuditNotificationItem & {
|
||||
description: string;
|
||||
};
|
||||
|
||||
type AppShellProps = {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
@@ -60,7 +64,7 @@ type AppShellProps = {
|
||||
userRole: string;
|
||||
navSections: ShellNavSection[];
|
||||
auditNotifications?: AuditNotificationItem[];
|
||||
retirementAlert?: { count: number; to: string };
|
||||
alertNotifications?: AlertNotificationItem[];
|
||||
onSessionLockedChange?: (locked: boolean) => void;
|
||||
};
|
||||
|
||||
@@ -73,7 +77,7 @@ export function AppShell({
|
||||
userRole,
|
||||
navSections,
|
||||
auditNotifications = [],
|
||||
retirementAlert,
|
||||
alertNotifications = [],
|
||||
onSessionLockedChange,
|
||||
}: AppShellProps) {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
@@ -81,6 +85,7 @@ export function AppShell({
|
||||
const [closedSections, setClosedSections] = useState<Record<string, boolean>>({});
|
||||
const [userMenuOpen, setUserMenuOpen] = useState(false);
|
||||
const [noticeOpen, setNoticeOpen] = useState(false);
|
||||
const [alertNoticeOpen, setAlertNoticeOpen] = useState(false);
|
||||
const [passwordModalOpen, setPasswordModalOpen] = useState(false);
|
||||
const [currentPassword, setCurrentPassword] = useState('');
|
||||
const [newPassword, setNewPassword] = useState('');
|
||||
@@ -107,6 +112,10 @@ export function AppShell({
|
||||
() => auditNotifications.reduce((sum, item) => sum + item.count, 0),
|
||||
[auditNotifications],
|
||||
);
|
||||
const alertTotal = useMemo(
|
||||
() => alertNotifications.reduce((sum, item) => sum + item.count, 0),
|
||||
[alertNotifications],
|
||||
);
|
||||
|
||||
async function changeOwnPassword() {
|
||||
if (!currentPassword || newPassword.length < 6) {
|
||||
@@ -417,23 +426,41 @@ export function AppShell({
|
||||
<button className="icon-button topbar-help" type="button" aria-label="帮助中心">
|
||||
<CircleHelp size={18} />
|
||||
</button>
|
||||
{retirementAlert ? (
|
||||
<Link
|
||||
aria-label={`今日未读且未抑制签名清退预警 ${retirementAlert.count} 条`}
|
||||
className={['icon-button', retirementAlert.count > 0 ? 'has-dot' : ''].filter(Boolean).join(' ')}
|
||||
title="今日未读且未抑制签名清退预警"
|
||||
to={retirementAlert.to}
|
||||
>
|
||||
<Bell size={18} />
|
||||
{retirementAlert.count > 0 ? <span className="notice-count">{retirementAlert.count}</span> : null}
|
||||
</Link>
|
||||
{alertNotifications.length ? (
|
||||
<div className="notice-menu-wrap">
|
||||
<button
|
||||
aria-expanded={alertNoticeOpen}
|
||||
aria-haspopup="menu"
|
||||
aria-label="预警通知"
|
||||
className={['icon-button', alertTotal > 0 ? 'has-dot' : ''].filter(Boolean).join(' ')}
|
||||
onClick={() => { setAlertNoticeOpen((open) => !open); setNoticeOpen(false); }}
|
||||
type="button"
|
||||
>
|
||||
<Bell size={18} />
|
||||
{alertTotal > 0 ? <span className="notice-count">{alertTotal}</span> : null}
|
||||
</button>
|
||||
{alertNoticeOpen ? (
|
||||
<div className="notice-popover notice-popover--alerts" role="menu">
|
||||
<div className="notice-popover__header">
|
||||
<strong>预警中心</strong>
|
||||
<span className={alertTotal === 0 ? 'is-zero' : ''}>{alertTotal} 条</span>
|
||||
</div>
|
||||
{alertNotifications.map((item) => (
|
||||
<NavLink key={item.to} onClick={() => setAlertNoticeOpen(false)} role="menuitem" to={item.to}>
|
||||
<span className="notice-popover__copy"><b>{item.label}</b><small>{item.description}</small></span>
|
||||
<strong className={item.count === 0 ? 'is-zero' : ''}>{item.count}</strong>
|
||||
</NavLink>
|
||||
))}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
<div className="notice-menu-wrap">
|
||||
<button
|
||||
aria-expanded={noticeOpen}
|
||||
aria-haspopup="menu"
|
||||
className={['icon-button', auditTotal > 0 ? 'has-dot' : ''].filter(Boolean).join(' ')}
|
||||
onClick={() => setNoticeOpen((open) => !open)}
|
||||
onClick={() => { setNoticeOpen((open) => !open); setAlertNoticeOpen(false); }}
|
||||
type="button"
|
||||
aria-label="通知"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user