| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170 |
- import { ProLayout } from '@ant-design/pro-components';
- import { Button, Dropdown, Select, Skeleton, message } from 'antd';
- import type { MenuProps } from 'antd';
- import {
- Bot,
- ChevronDown,
- ClipboardList,
- Gift,
- LayoutDashboard,
- LogOut,
- MessageSquareMore,
- Settings,
- Star,
- Users,
- } from 'lucide-react';
- import { Outlet, history, useLocation } from '@umijs/max';
- import { useEffect, useState } from 'react';
- import {
- apiRequest,
- getSelectedBotId,
- jsonOptions,
- setCsrfToken,
- setSelectedBotId,
- } from '@/services/api';
- import type { AdminUser, BotProfile } from '@/types';
- const menuItems = [
- { path: '/dashboard', name: '概览', icon: <LayoutDashboard size={18} /> },
- { path: '/chats', name: '群组管理', icon: <Users size={18} /> },
- { path: '/giveaways', name: '抽奖管理', icon: <Gift size={18} /> },
- { path: '/points', name: '积分管理', icon: <Star size={18} /> },
- { path: '/audit', name: '操作日志', icon: <ClipboardList size={18} /> },
- { path: '/settings', name: '系统设置', icon: <Settings size={18} /> },
- ];
- export default function AdminLayout() {
- const location = useLocation();
- const [user, setUser] = useState<AdminUser | null>(null);
- const [bots, setBots] = useState<BotProfile[]>([]);
- const [selectedBot, setSelectedBot] = useState(getSelectedBotId());
- useEffect(() => {
- apiRequest<AdminUser>('/auth/me')
- .then((current) => {
- setCsrfToken(current.csrf_token);
- if (current.must_change_password) {
- history.replace('/change-password');
- return;
- }
- setUser(current);
- })
- .catch((error) => message.error(error.message));
- }, []);
- useEffect(() => {
- const loadBots = () => {
- apiRequest<{ items: BotProfile[] }>('/bots')
- .then(({ items }) => {
- setBots(items);
- const current = getSelectedBotId();
- if (current && items.some((item) => item.bot_id === current)) {
- setSelectedBot(current);
- return;
- }
- const first = items.find((item) => item.enabled) || items[0];
- const next = first?.bot_id || '';
- setSelectedBot(next);
- setSelectedBotId(next);
- })
- .catch(() => setBots([]));
- };
- loadBots();
- window.addEventListener('bot-profiles-changed', loadBots);
- return () => window.removeEventListener('bot-profiles-changed', loadBots);
- }, []);
- const accountMenu: MenuProps['items'] = [
- {
- key: 'settings',
- icon: <Settings size={16} />,
- label: '账号设置',
- onClick: () => history.push('/settings'),
- },
- {
- key: 'logout',
- danger: true,
- icon: <LogOut size={16} />,
- label: '退出登录',
- onClick: async () => {
- await apiRequest('/auth/logout', jsonOptions('POST'));
- sessionStorage.removeItem('admin_csrf');
- history.replace('/login');
- },
- },
- ];
- if (!user) {
- return <Skeleton active style={{ padding: 24 }} />;
- }
- return (
- <ProLayout
- title="Telegram 群管"
- logo={<Bot size={24} color="#fff" aria-hidden="true" />}
- location={{ pathname: location.pathname }}
- menu={{ request: async () => menuItems }}
- layout="mix"
- fixedHeader
- fixSiderbar
- siderWidth={224}
- breakpoint="lg"
- token={{
- header: { colorBgHeader: '#ffffff', colorTextMenu: '#17212b' },
- sider: { colorMenuBackground: '#17212b' },
- pageContainer: { paddingInlinePageContainerContent: 20 },
- }}
- menuItemRender={(item, dom) => (
- <button
- type="button"
- onClick={() => item.path && history.push(item.path)}
- style={{
- width: '100%',
- padding: 0,
- color: 'inherit',
- textAlign: 'left',
- background: 'transparent',
- border: 0,
- cursor: 'pointer',
- }}
- >
- {dom}
- </button>
- )}
- avatarProps={{
- src: undefined,
- icon: <MessageSquareMore size={18} />,
- title: (
- <Dropdown menu={{ items: accountMenu }} trigger={['click']}>
- <Button type="text" icon={<ChevronDown size={15} />} iconPosition="end">
- {user.username}
- </Button>
- </Dropdown>
- ),
- render: (_, dom) => dom,
- }}
- actionsRender={() => [
- <Select
- key="bot-selector"
- aria-label="当前机器人"
- value={selectedBot || undefined}
- placeholder="选择机器人"
- style={{ width: 200, maxWidth: '34vw' }}
- options={bots.map((item) => ({
- value: item.bot_id,
- label: item.identity?.username ? `@${item.identity.username}` : item.label,
- }))}
- onChange={(value) => {
- setSelectedBot(value);
- setSelectedBotId(value);
- }}
- />,
- ]}
- >
- <main className="page-content" id="main-content">
- <Outlet />
- </main>
- </ProLayout>
- );
- }
|