feat(admin,store): landline contact phone and package audit UX
Allow store contactPhone as landline, show pending package audit badge, and split live vs pending packages in HQ review. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Outlet, useLocation, useNavigate } from 'react-router-dom';
|
||||
import { Layout, Menu, Typography, Button, Space } from 'antd';
|
||||
import { Layout, Menu, Typography, Button, Space, Badge } from 'antd';
|
||||
import type { MenuProps } from 'antd';
|
||||
import {
|
||||
RobotOutlined,
|
||||
@@ -23,6 +23,7 @@ import {
|
||||
import { hasAnySystemSettingsPermission } from '@dukang/shared-types';
|
||||
import { clearAuth, request, type HqProfile } from '../lib/api';
|
||||
import { bindAdminEllipsisTitle } from '../lib/ellipsis-title';
|
||||
import { PACKAGE_AUDIT_CHANGED_EVENT } from '../lib/admin-events';
|
||||
|
||||
const { Header, Sider, Content } = Layout;
|
||||
|
||||
@@ -243,6 +244,30 @@ function filterMenuItems(items: MenuProps['items'], permissionKeys: string[]): M
|
||||
.filter(Boolean) as MenuProps['items'];
|
||||
}
|
||||
|
||||
function attachPackageAuditBadge(items: MenuProps['items'], pendingCount: number): MenuProps['items'] {
|
||||
if (!items) return items;
|
||||
return items.map((item) => {
|
||||
if (!item || typeof item !== 'object' || !('key' in item)) return item;
|
||||
if ('children' in item && Array.isArray(item.children)) {
|
||||
return {
|
||||
...item,
|
||||
children: attachPackageAuditBadge(item.children as MenuProps['items'], pendingCount),
|
||||
} as MenuItem;
|
||||
}
|
||||
if (String(item.key) === '/store-package-audits') {
|
||||
return {
|
||||
...item,
|
||||
label: (
|
||||
<Badge count={pendingCount} size="small" offset={[8, 0]}>
|
||||
套餐审核
|
||||
</Badge>
|
||||
),
|
||||
} as MenuItem;
|
||||
}
|
||||
return item;
|
||||
});
|
||||
}
|
||||
|
||||
const IS_STAGING = import.meta.env.VITE_APP_ENV === 'staging';
|
||||
|
||||
export default function AdminLayout() {
|
||||
@@ -250,11 +275,28 @@ export default function AdminLayout() {
|
||||
const location = useLocation();
|
||||
const contentRef = useRef<HTMLDivElement>(null);
|
||||
const [profile, setProfile] = useState<HqProfile | null>(null);
|
||||
const [packagePendingCount, setPackagePendingCount] = useState(0);
|
||||
|
||||
function refreshPackagePendingCount() {
|
||||
request<{ pendingCount: number }>('/admin/store-package-audits/summary')
|
||||
.then((data) => setPackagePendingCount(data.pendingCount ?? 0))
|
||||
.catch(() => {});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
request<HqProfile>('/admin/auth/me').then(setProfile).catch(() => {});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
refreshPackagePendingCount();
|
||||
}, [location.pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
const onChanged = () => refreshPackagePendingCount();
|
||||
window.addEventListener(PACKAGE_AUDIT_CHANGED_EVENT, onChanged);
|
||||
return () => window.removeEventListener(PACKAGE_AUDIT_CHANGED_EVENT, onChanged);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
contentRef.current?.scrollTo({ top: 0, left: 0 });
|
||||
}, [location.pathname]);
|
||||
@@ -273,10 +315,12 @@ export default function AdminLayout() {
|
||||
: location.pathname;
|
||||
|
||||
const menuItems = useMemo(() => {
|
||||
if (!profile) return MENU_ITEMS;
|
||||
if (profile.adminRole === 'SUPER_ADMIN') return MENU_ITEMS;
|
||||
return filterMenuItems(MENU_ITEMS, profile.permissionKeys ?? []);
|
||||
}, [profile]);
|
||||
const base =
|
||||
!profile || profile.adminRole === 'SUPER_ADMIN'
|
||||
? MENU_ITEMS
|
||||
: filterMenuItems(MENU_ITEMS, profile.permissionKeys ?? []);
|
||||
return attachPackageAuditBadge(base, packagePendingCount);
|
||||
}, [profile, packagePendingCount]);
|
||||
|
||||
return (
|
||||
<Layout style={{ height: '100vh', overflow: 'hidden' }}>
|
||||
|
||||
Reference in New Issue
Block a user