Files
shaguabijia-admin-web/src/app/(main)/layout.tsx
T
zhuzihao 82ffc73be5 feat(ad-revenue): 广告收益报表迁出独立页 + 接入提现激励视频 (#18)
- 报表从「广告管理」页迁出为独立「广告收益」页(ad-revenue-report),ad-revenue 页只留广告配置;
  layout 侧边栏拆成「广告配置」+「广告收益」两个入口
- ad-revenue 配置页新增「提现激励视频开关」(withdrawal_ad_enabled),控制客户端提现是否走看视频
- 广告收益报表新增「提现激励视频」类型标签与筛选项(ad_type=withdrawal_video)

---------

Co-authored-by: zzhyyyyy <2685922758@qq.com>
Reviewed-on: #18
Co-authored-by: zhuzihao <zhuzihao@wonderable.ai>
Co-committed-by: zhuzihao <zhuzihao@wonderable.ai>
2026-06-24 22:37:49 +08:00

122 lines
3.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { useEffect, useState } from 'react';
import { usePathname, useRouter } from 'next/navigation';
import {
BarChartOutlined,
DashboardOutlined,
FileSearchOutlined,
FlagOutlined,
LogoutOutlined,
MessageOutlined,
MobileOutlined,
MoneyCollectOutlined,
NotificationOutlined,
ProfileOutlined,
SettingOutlined,
ShareAltOutlined,
TeamOutlined,
UserOutlined,
} from '@ant-design/icons';
import { Avatar, Dropdown, Layout, Menu } from 'antd';
import { clearAuth, getAdmin, getToken } from '@/lib/auth';
import type { AdminInfo } from '@/lib/types';
const { Sider, Header, Content } = Layout;
const MENU = [
{ key: '/dashboard', icon: <DashboardOutlined />, label: '数据大盘' },
{ key: '/users', icon: <UserOutlined />, label: '用户管理' },
{ key: '/devices', icon: <MobileOutlined />, label: '设备管理' },
{ key: '/withdraws', icon: <MoneyCollectOutlined />, label: '提现管理' },
{ key: '/price-reports', icon: <FlagOutlined />, label: '上报审核' },
{ key: '/comparison-records', icon: <ProfileOutlined />, label: '比价记录' },
{ key: '/feedbacks', icon: <MessageOutlined />, label: '反馈工单' },
{ key: '/ad-revenue', icon: <NotificationOutlined />, label: '广告配置' },
{ key: '/ad-revenue-report', icon: <BarChartOutlined />, label: '广告收益' },
{ key: '/cps', icon: <ShareAltOutlined />, label: 'CPS 分发' },
{ key: '/config', icon: <SettingOutlined />, label: '系统配置' },
{ key: '/admins', icon: <TeamOutlined />, label: '管理员', superOnly: true },
{ key: '/audit-logs', icon: <FileSearchOutlined />, label: '审计日志' },
];
export default function MainLayout({ children }: { children: React.ReactNode }) {
const router = useRouter();
const pathname = usePathname();
const [admin, setAdmin] = useState<AdminInfo | null>(null);
useEffect(() => {
if (!getToken()) {
router.replace('/login');
return;
}
setAdmin(getAdmin());
}, [router]);
if (!admin) return null; // 守卫期间不闪烁内容
const items = MENU.filter((m) => !m.superOnly || admin.role === 'super_admin').map((m) => ({
key: m.key,
icon: m.icon,
label: m.label,
}));
// 选中态:取路径一级(/users/123 → /users)
const selectedKey = '/' + (pathname.split('/')[1] || 'dashboard');
const logout = () => {
clearAuth();
router.replace('/login');
};
return (
<Layout style={{ minHeight: '100vh' }}>
<Sider theme="dark" breakpoint="lg" collapsible>
<div
style={{
height: 48,
margin: 16,
color: '#fff',
fontWeight: 600,
textAlign: 'center',
lineHeight: '48px',
}}
>
</div>
<Menu
theme="dark"
mode="inline"
selectedKeys={[selectedKey]}
items={items}
onClick={({ key }) => router.push(key)}
/>
</Sider>
<Layout>
<Header
style={{
background: '#fff',
padding: '0 24px',
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'center',
}}
>
<Dropdown
menu={{
items: [
{ key: 'logout', icon: <LogoutOutlined />, label: '退出登录', onClick: logout },
],
}}
>
<span style={{ cursor: 'pointer' }}>
<Avatar size="small" icon={<UserOutlined />} /> {admin.username}{admin.role}
</span>
</Dropdown>
</Header>
<Content style={{ margin: 24 }}>{children}</Content>
</Layout>
</Layout>
);
}