feat: 美化界面并统一列表分页为 10 条
CI / lint-and-build (push) Has been cancelled

- 左上角名称改为火炬VOD管理器

- 登录页使用渐变背景、LOGO、圆角卡片

- 视频列表、操作日志默认每页 10 条

- 布局增加底部版权信息 © meshel.cn · MIT 开源
This commit is contained in:
2026-06-29 18:12:03 +06:00
parent 10c5c0cb03
commit b84bac5828
4 changed files with 71 additions and 13 deletions
+12 -2
View File
@@ -9,7 +9,7 @@ import {
import { Outlet, useLocation, useNavigate } from 'react-router-dom'; import { Outlet, useLocation, useNavigate } from 'react-router-dom';
import { useAuthStore } from '../store/auth'; import { useAuthStore } from '../store/auth';
const { Header, Sider, Content } = AntLayout; const { Header, Sider, Content, Footer } = AntLayout;
export default function Layout() { export default function Layout() {
const location = useLocation(); const location = useLocation();
@@ -54,7 +54,7 @@ export default function Layout() {
fontSize: 16, fontSize: 16,
}} }}
> >
VOD VOD管理器
</div> </div>
<Menu <Menu
mode="inline" mode="inline"
@@ -87,6 +87,16 @@ export default function Layout() {
> >
<Outlet /> <Outlet />
</Content> </Content>
<Footer
style={{
textAlign: 'center',
background: colorBgContainer,
color: '#888',
fontSize: 13,
}}
>
© {new Date().getFullYear()} meshel.cn · VOD管理器 · MIT
</Footer>
</AntLayout> </AntLayout>
</AntLayout> </AntLayout>
); );
+57 -9
View File
@@ -1,9 +1,12 @@
import { useState } from 'react'; import { useState } from 'react';
import { Form, Input, Button, Card, message } from 'antd'; import { Form, Input, Button, Card, message, Typography, Space } from 'antd';
import { VideoCameraOutlined, LockOutlined, UserOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useAuthStore } from '../store/auth'; import { useAuthStore } from '../store/auth';
import { login } from '../api/auth'; import { login } from '../api/auth';
const { Title, Text } = Typography;
export default function LoginPage() { export default function LoginPage() {
const navigate = useNavigate(); const navigate = useNavigate();
const setAuth = useAuthStore((state) => state.setAuth); const setAuth = useAuthStore((state) => state.setAuth);
@@ -30,32 +33,77 @@ export default function LoginPage() {
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center',
background: '#f0f2f5', background: 'linear-gradient(135deg, #1677ff 0%, #0958d9 100%)',
}} }}
> >
<Card title="阿里云 VOD 媒体库管理器" style={{ width: 400 }}> <Card
style={{
width: 420,
borderRadius: 16,
boxShadow: '0 20px 50px rgba(0, 0, 0, 0.15)',
overflow: 'hidden',
}}
bodyStyle={{ padding: '40px 32px' }}
>
<Space direction="vertical" align="center" style={{ width: '100%', marginBottom: 32 }}>
<div
style={{
width: 64,
height: 64,
borderRadius: '50%',
background: 'linear-gradient(135deg, #1677ff 0%, #0958d9 100%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}}
>
<VideoCameraOutlined style={{ fontSize: 32, color: '#fff' }} />
</div>
<Title level={3} style={{ margin: 0 }}>VOD管理器</Title>
<Text type="secondary"></Text>
</Space>
<Form name="login" onFinish={handleSubmit} autoComplete="off" layout="vertical"> <Form name="login" onFinish={handleSubmit} autoComplete="off" layout="vertical">
<Form.Item <Form.Item
label="用户名"
name="username" name="username"
rules={[{ required: true, message: '请输入用户名' }]} rules={[{ required: true, message: '请输入用户名' }]}
> >
<Input placeholder="admin" /> <Input
prefix={<UserOutlined />}
placeholder="用户名"
size="large"
/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label="密码"
name="password" name="password"
rules={[{ required: true, message: '请输入密码' }]} rules={[{ required: true, message: '请输入密码' }]}
> >
<Input.Password placeholder="admin" /> <Input.Password
prefix={<LockOutlined />}
placeholder="密码"
size="large"
/>
</Form.Item> </Form.Item>
<Form.Item> <Form.Item style={{ marginBottom: 12 }}>
<Button type="primary" htmlType="submit" loading={loading} block> <Button
type="primary"
htmlType="submit"
loading={loading}
size="large"
block
style={{ borderRadius: 8 }}
>
</Button> </Button>
</Form.Item> </Form.Item>
<div style={{ textAlign: 'center' }}>
<Text type="secondary" style={{ fontSize: 12 }}>
admin / admin
</Text>
</div>
</Form> </Form>
</Card> </Card>
</div> </div>
+1 -1
View File
@@ -20,7 +20,7 @@ export default function LogsPage() {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [total, setTotal] = useState(0); const [total, setTotal] = useState(0);
const [pageNo, setPageNo] = useState(1); const [pageNo, setPageNo] = useState(1);
const [pageSize, setPageSize] = useState(20); const [pageSize, setPageSize] = useState(10);
const fetchLogs = async (page: number, size: number) => { const fetchLogs = async (page: number, size: number) => {
setLoading(true); setLoading(true);
+1 -1
View File
@@ -48,7 +48,7 @@ export default function VideosPage() {
const [selectedRows, setSelectedRows] = useState<VideoItem[]>([]); const [selectedRows, setSelectedRows] = useState<VideoItem[]>([]);
const [total, setTotal] = useState(0); const [total, setTotal] = useState(0);
const [pageNo, setPageNo] = useState(1); const [pageNo, setPageNo] = useState(1);
const [pageSize, setPageSize] = useState(20); const [pageSize, setPageSize] = useState(10);
const [categories, setCategories] = useState<Record<string, unknown>[]>([]); const [categories, setCategories] = useState<Record<string, unknown>[]>([]);
const [detail, setDetail] = useState<VideoItem | null>(null); const [detail, setDetail] = useState<VideoItem | null>(null);
const [drawerOpen, setDrawerOpen] = useState(false); const [drawerOpen, setDrawerOpen] = useState(false);