前端重构
This commit is contained in:
parent
cf16ab6448
commit
b770c4a3b6
|
|
@ -136,7 +136,7 @@ const AboutPage: React.FC = () => {
|
|||
{/* 头部信息 */}
|
||||
<Card className={styles.headerCard} variant="borderless">
|
||||
<div className={styles.logoWrapper}>
|
||||
<Logo size={80} />
|
||||
<Logo size="large" />
|
||||
</div>
|
||||
<Title level={2} className={styles.title}>
|
||||
Kratos Admin
|
||||
|
|
|
|||
|
|
@ -1,36 +1,57 @@
|
|||
/**
|
||||
* KRA - Dashboard Banner Component
|
||||
* 与GVA banner.vue 逻辑一致 - 轮播图
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Card } from 'antd';
|
||||
import Logo from '@/components/Logo/Logo';
|
||||
import { Carousel } from 'antd';
|
||||
|
||||
interface BannerItem {
|
||||
img: string;
|
||||
link: string;
|
||||
}
|
||||
|
||||
const banners: BannerItem[] = [
|
||||
{
|
||||
img: 'https://go-kratos.dev/img/logo.svg',
|
||||
link: 'https://go-kratos.dev/'
|
||||
},
|
||||
{
|
||||
img: 'https://avatars.githubusercontent.com/u/68029786?s=200&v=4',
|
||||
link: 'https://github.com/go-kratos/kratos'
|
||||
},
|
||||
];
|
||||
|
||||
const Banner: React.FC = () => {
|
||||
const openLink = (link: string) => {
|
||||
window.open(link, '_blank');
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="kra-dashboard-card"
|
||||
styles={{ body: { padding: 0, height: '160px', overflow: 'hidden' } }}
|
||||
variant="borderless"
|
||||
>
|
||||
<div style={{
|
||||
height: '100%',
|
||||
background: 'linear-gradient(135deg, #1890ff 0%, #722ed1 100%)',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
color: '#fff',
|
||||
padding: '24px',
|
||||
}}>
|
||||
<Logo size="large" />
|
||||
<h3 style={{ margin: '12px 0 4px', fontSize: '18px', fontWeight: 600 }}>
|
||||
Kratos Admin
|
||||
</h3>
|
||||
<p style={{ margin: 0, fontSize: '12px', opacity: 0.85 }}>
|
||||
全栈管理平台
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
<div style={{ marginTop: '-8px', height: '160px', overflow: 'hidden' }}>
|
||||
<Carousel autoplay>
|
||||
{banners.map((item, index) => (
|
||||
<div key={index}>
|
||||
<div
|
||||
onClick={() => openLink(item.link)}
|
||||
style={{
|
||||
height: '160px',
|
||||
cursor: 'pointer',
|
||||
background: 'linear-gradient(135deg, #1890ff 0%, #722ed1 100%)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src={item.img}
|
||||
alt="banner"
|
||||
style={{ maxHeight: '80px', maxWidth: '80%', objectFit: 'contain' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</Carousel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* KRA - Mini Line Chart Component
|
||||
* 统计卡片中的小折线图
|
||||
*/
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
|
||||
interface MiniLineChartProps {
|
||||
data: number[];
|
||||
color?: string;
|
||||
}
|
||||
|
||||
const MiniLineChart: React.FC<MiniLineChartProps> = ({ data, color = '#1890ff' }) => {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
|
||||
const ctx = canvas.getContext('2d');
|
||||
if (!ctx) return;
|
||||
|
||||
const width = canvas.width;
|
||||
const height = canvas.height;
|
||||
const padding = 10;
|
||||
|
||||
// 清空画布
|
||||
ctx.clearRect(0, 0, width, height);
|
||||
|
||||
if (data.length < 2) return;
|
||||
|
||||
const max = Math.max(...data);
|
||||
const min = Math.min(...data);
|
||||
const range = max - min || 1;
|
||||
|
||||
const stepX = (width - padding * 2) / (data.length - 1);
|
||||
|
||||
// 绘制渐变区域
|
||||
const gradient = ctx.createLinearGradient(0, 0, 0, height);
|
||||
gradient.addColorStop(0, `${color}40`);
|
||||
gradient.addColorStop(1, `${color}00`);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(padding, height - padding);
|
||||
|
||||
data.forEach((value, index) => {
|
||||
const x = padding + index * stepX;
|
||||
const y = height - padding - ((value - min) / range) * (height - padding * 2);
|
||||
if (index === 0) {
|
||||
ctx.lineTo(x, y);
|
||||
} else {
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
});
|
||||
|
||||
ctx.lineTo(padding + (data.length - 1) * stepX, height - padding);
|
||||
ctx.closePath();
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fill();
|
||||
|
||||
// 绘制折线
|
||||
ctx.beginPath();
|
||||
data.forEach((value, index) => {
|
||||
const x = padding + index * stepX;
|
||||
const y = height - padding - ((value - min) / range) * (height - padding * 2);
|
||||
if (index === 0) {
|
||||
ctx.moveTo(x, y);
|
||||
} else {
|
||||
ctx.lineTo(x, y);
|
||||
}
|
||||
});
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.stroke();
|
||||
}, [data, color]);
|
||||
|
||||
return (
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
width={150}
|
||||
height={80}
|
||||
style={{ width: '100%', height: '100%' }}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default MiniLineChart;
|
||||
|
|
@ -1,61 +1,100 @@
|
|||
/**
|
||||
* KRA - Dashboard Notice Component
|
||||
* 与GVA notice.vue 逻辑一致
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Card, List, Tag, Typography } from 'antd';
|
||||
import { NotificationOutlined } from '@ant-design/icons';
|
||||
|
||||
const { Text } = Typography;
|
||||
import { Card, Tag, Tooltip } from 'antd';
|
||||
|
||||
interface NoticeItem {
|
||||
id: number;
|
||||
type: 'primary' | 'success' | 'warning' | 'danger' | 'info';
|
||||
typeTitle: string;
|
||||
title: string;
|
||||
type: 'info' | 'warning' | 'success';
|
||||
time: string;
|
||||
}
|
||||
|
||||
const notices: NoticeItem[] = [
|
||||
{ id: 1, title: '系统将于今晚进行维护升级', type: 'warning', time: '2小时前' },
|
||||
{ id: 2, title: '新版本 v1.0.0 已发布', type: 'success', time: '1天前' },
|
||||
{ id: 3, title: '欢迎使用 Kratos Admin', type: 'info', time: '3天前' },
|
||||
{
|
||||
type: 'primary',
|
||||
typeTitle: '公告',
|
||||
title: '欢迎使用 Kratos Admin 管理系统。'
|
||||
},
|
||||
{
|
||||
type: 'success',
|
||||
typeTitle: '通知',
|
||||
title: '系统已完成最新版本升级。'
|
||||
},
|
||||
{
|
||||
type: 'warning',
|
||||
typeTitle: '警告',
|
||||
title: '请定期备份重要数据。'
|
||||
},
|
||||
{
|
||||
type: 'danger',
|
||||
typeTitle: '违规',
|
||||
title: '请勿在生产环境使用默认密码。'
|
||||
},
|
||||
{
|
||||
type: 'info',
|
||||
typeTitle: '信息',
|
||||
title: '感谢您对开源事业的支持。'
|
||||
},
|
||||
{
|
||||
type: 'primary',
|
||||
typeTitle: '公告',
|
||||
title: '让创意更有价值。'
|
||||
},
|
||||
{
|
||||
type: 'success',
|
||||
typeTitle: '通知',
|
||||
title: '让劳动更有意义。'
|
||||
},
|
||||
{
|
||||
type: 'warning',
|
||||
typeTitle: '警告',
|
||||
title: '让思维更有深度。'
|
||||
},
|
||||
{
|
||||
type: 'danger',
|
||||
typeTitle: '错误',
|
||||
title: '让生活更有趣味。'
|
||||
},
|
||||
{
|
||||
type: 'info',
|
||||
typeTitle: '信息',
|
||||
title: '让公司更有活力。'
|
||||
}
|
||||
];
|
||||
|
||||
const typeColors = {
|
||||
info: 'blue',
|
||||
warning: 'orange',
|
||||
const typeColors: Record<string, string> = {
|
||||
primary: 'blue',
|
||||
success: 'green',
|
||||
warning: 'orange',
|
||||
danger: 'red',
|
||||
info: 'default',
|
||||
};
|
||||
|
||||
const Notice: React.FC = () => {
|
||||
return (
|
||||
<Card
|
||||
title="公告"
|
||||
className="kra-dashboard-card"
|
||||
variant="borderless"
|
||||
extra={<a href="#">更多</a>}
|
||||
>
|
||||
<List
|
||||
size="small"
|
||||
dataSource={notices}
|
||||
renderItem={(item) => (
|
||||
<List.Item style={{ padding: '8px 0' }}>
|
||||
<div style={{ width: '100%' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>
|
||||
<NotificationOutlined style={{ color: '#999', fontSize: '12px' }} />
|
||||
<Text ellipsis style={{ flex: 1, fontSize: '13px' }}>
|
||||
{item.title}
|
||||
</Text>
|
||||
<Card title="公告" className="kra-dashboard-card" variant="borderless" extra={<a href="#">更多</a>}>
|
||||
<div style={{ maxHeight: '200px', overflow: 'auto' }}>
|
||||
{notices.map((item, index) => (
|
||||
<div key={index} style={{ display: 'flex', alignItems: 'center', marginBottom: '6px', gap: '12px' }}>
|
||||
<Tag color={typeColors[item.type]} style={{ margin: 0, flexShrink: 0 }}>
|
||||
{item.typeTitle}
|
||||
</Tag>
|
||||
<Tooltip title={item.title} placement="top">
|
||||
<div style={{
|
||||
fontSize: '12px',
|
||||
color: '#666',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
whiteSpace: 'nowrap'
|
||||
}}>
|
||||
{item.title}
|
||||
</div>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Tag color={typeColors[item.type]} style={{ margin: 0 }}>
|
||||
{item.type === 'info' ? '通知' : item.type === 'warning' ? '警告' : '成功'}
|
||||
</Tag>
|
||||
<Text type="secondary" style={{ fontSize: '12px' }}>{item.time}</Text>
|
||||
</div>
|
||||
</div>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,133 +1,98 @@
|
|||
/**
|
||||
* KRA - Dashboard Plugin Table Component
|
||||
* 与GVA pluginTable.vue 逻辑一致 - 最新插件表格
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Card, Table, Tag, Space, Button } from 'antd';
|
||||
import { Card, Table } from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
import { GithubOutlined, LinkOutlined } from '@ant-design/icons';
|
||||
|
||||
interface PluginItem {
|
||||
key: string;
|
||||
name: string;
|
||||
description: string;
|
||||
version: string;
|
||||
status: 'active' | 'inactive' | 'beta';
|
||||
author: string;
|
||||
ranking: number;
|
||||
title: string;
|
||||
click_num: number;
|
||||
hot: number;
|
||||
link: string;
|
||||
}
|
||||
|
||||
const plugins: PluginItem[] = [
|
||||
const tableData: PluginItem[] = [
|
||||
{
|
||||
key: '1',
|
||||
name: '公告管理',
|
||||
description: '系统公告发布与管理',
|
||||
version: 'v1.0.0',
|
||||
status: 'active',
|
||||
author: 'KRA Team',
|
||||
ranking: 1,
|
||||
title: '组织管理插件:更方便管理组织,分配资源权限。',
|
||||
click_num: 523,
|
||||
hot: 263,
|
||||
link: 'https://go-kratos.dev/'
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
name: '邮件服务',
|
||||
description: '邮件配置与发送服务',
|
||||
version: 'v1.0.0',
|
||||
status: 'active',
|
||||
author: 'KRA Team',
|
||||
ranking: 2,
|
||||
title: 'Kubernetes容器管理:Kubernetes 原生资源管理,提供炫酷的YAML编辑,Pod终端。',
|
||||
click_num: 416,
|
||||
hot: 223,
|
||||
link: 'https://go-kratos.dev/'
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
name: '代码生成器',
|
||||
description: '自动生成 CRUD 代码',
|
||||
version: 'v0.9.0',
|
||||
status: 'beta',
|
||||
author: 'KRA Team',
|
||||
ranking: 3,
|
||||
title: '定时任务配置化管理:本插件用于对系统内部的定时任务进行配置化管理。',
|
||||
click_num: 337,
|
||||
hot: 176,
|
||||
link: 'https://go-kratos.dev/'
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
name: '文件管理',
|
||||
description: '文件上传与管理',
|
||||
version: 'v1.0.0',
|
||||
status: 'active',
|
||||
author: 'KRA Team',
|
||||
ranking: 4,
|
||||
title: '官网CMS系统:基于Kratos开发的企业官网类(CMS)系统。',
|
||||
click_num: 292,
|
||||
hot: 145,
|
||||
link: 'https://go-kratos.dev/'
|
||||
},
|
||||
{
|
||||
ranking: 5,
|
||||
title: '微信支付插件:提供扫码支付功能(需自行对接业务)。',
|
||||
click_num: 173,
|
||||
hot: 110,
|
||||
link: 'https://go-kratos.dev/'
|
||||
}
|
||||
];
|
||||
|
||||
const statusColors = {
|
||||
active: 'green',
|
||||
inactive: 'default',
|
||||
beta: 'orange',
|
||||
};
|
||||
|
||||
const statusLabels = {
|
||||
active: '已启用',
|
||||
inactive: '未启用',
|
||||
beta: '测试中',
|
||||
};
|
||||
|
||||
const columns: ColumnsType<PluginItem> = [
|
||||
{
|
||||
title: '插件名称',
|
||||
dataIndex: 'name',
|
||||
key: 'name',
|
||||
width: 120,
|
||||
title: '排名',
|
||||
dataIndex: 'ranking',
|
||||
width: 80,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '描述',
|
||||
dataIndex: 'description',
|
||||
key: 'description',
|
||||
title: '插件标题',
|
||||
dataIndex: 'title',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '版本',
|
||||
dataIndex: 'version',
|
||||
key: 'version',
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
width: 80,
|
||||
render: (status: keyof typeof statusColors) => (
|
||||
<Tag color={statusColors[status]}>{statusLabels[status]}</Tag>
|
||||
render: (text, record) => (
|
||||
<a
|
||||
href={record.link}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{ color: '#1890ff' }}
|
||||
>
|
||||
{text}
|
||||
</a>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '作者',
|
||||
dataIndex: 'author',
|
||||
key: 'author',
|
||||
title: '关注度',
|
||||
dataIndex: 'click_num',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '热度值',
|
||||
dataIndex: 'hot',
|
||||
width: 100,
|
||||
},
|
||||
];
|
||||
|
||||
const PluginTable: React.FC = () => {
|
||||
return (
|
||||
<Card
|
||||
title="最新插件"
|
||||
className="kra-dashboard-card"
|
||||
variant="borderless"
|
||||
extra={
|
||||
<Space>
|
||||
<Button
|
||||
type="link"
|
||||
icon={<GithubOutlined />}
|
||||
href="https://github.com/go-kratos/kratos"
|
||||
target="_blank"
|
||||
>
|
||||
GitHub
|
||||
</Button>
|
||||
<Button
|
||||
type="link"
|
||||
icon={<LinkOutlined />}
|
||||
href="https://go-kratos.dev/"
|
||||
target="_blank"
|
||||
>
|
||||
文档
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Card title="最新插件" className="kra-dashboard-card" variant="borderless">
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={plugins}
|
||||
dataSource={tableData}
|
||||
rowKey="ranking"
|
||||
pagination={false}
|
||||
size="small"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,83 +1,100 @@
|
|||
/**
|
||||
* KRA - Dashboard Quick Links Component
|
||||
* 与GVA quickLinks.vue 逻辑一致
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Card, Row, Col } from 'antd';
|
||||
import {
|
||||
UserOutlined,
|
||||
SettingOutlined,
|
||||
FileTextOutlined,
|
||||
DatabaseOutlined,
|
||||
ApiOutlined,
|
||||
MenuOutlined,
|
||||
LinkOutlined,
|
||||
SafetyOutlined,
|
||||
UserOutlined,
|
||||
FolderOutlined,
|
||||
CodeOutlined,
|
||||
ReadOutlined,
|
||||
AppstoreOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { history } from '@umijs/max';
|
||||
|
||||
interface QuickLink {
|
||||
title: string;
|
||||
interface ShortcutItem {
|
||||
icon: React.ReactNode;
|
||||
title: string;
|
||||
path: string;
|
||||
color: string;
|
||||
isExternal?: boolean;
|
||||
}
|
||||
|
||||
const links: QuickLink[] = [
|
||||
{ title: '用户管理', icon: <UserOutlined />, path: '/system/user', color: '#1890ff' },
|
||||
{ title: '角色管理', icon: <SafetyOutlined />, path: '/system/authority', color: '#52c41a' },
|
||||
{ title: '菜单管理', icon: <FileTextOutlined />, path: '/system/menu', color: '#faad14' },
|
||||
{ title: 'API管理', icon: <ApiOutlined />, path: '/system/api', color: '#722ed1' },
|
||||
{ title: '字典管理', icon: <DatabaseOutlined />, path: '/system/dictionary', color: '#eb2f96' },
|
||||
{ title: '系统配置', icon: <SettingOutlined />, path: '/systemTools/system', color: '#13c2c2' },
|
||||
// 内部快捷功能
|
||||
const shortcuts: ShortcutItem[] = [
|
||||
{ icon: <MenuOutlined />, title: '菜单管理', path: '/system/menu' },
|
||||
{ icon: <LinkOutlined />, title: 'API管理', path: '/system/api' },
|
||||
{ icon: <SafetyOutlined />, title: '角色管理', path: '/system/authority' },
|
||||
{ icon: <UserOutlined />, title: '用户管理', path: '/system/user' },
|
||||
{ icon: <FolderOutlined />, title: '自动化包', path: '/systemTools/autoCodeAdmin' },
|
||||
{ icon: <CodeOutlined />, title: '自动代码', path: '/systemTools/autoCode' },
|
||||
];
|
||||
|
||||
// 外部链接
|
||||
const externalLinks: ShortcutItem[] = [
|
||||
{ icon: <ReadOutlined />, title: 'Kratos文档', path: 'https://go-kratos.dev/', isExternal: true },
|
||||
{ icon: <AppstoreOutlined />, title: 'GitHub', path: 'https://github.com/go-kratos/kratos', isExternal: true },
|
||||
];
|
||||
|
||||
const QuickLinks: React.FC = () => {
|
||||
const handleClick = (path: string) => {
|
||||
history.push(path);
|
||||
const handleClick = (item: ShortcutItem) => {
|
||||
if (item.isExternal) {
|
||||
window.open(item.path, '_blank');
|
||||
} else {
|
||||
history.push(item.path);
|
||||
}
|
||||
};
|
||||
|
||||
const renderItem = (item: ShortcutItem, index: number) => (
|
||||
<Col span={8} key={index}>
|
||||
<div
|
||||
onClick={() => handleClick(item)}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
marginBottom: '12px',
|
||||
cursor: 'pointer',
|
||||
}}
|
||||
className="quick-link-item"
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: '32px',
|
||||
height: '32px',
|
||||
borderRadius: '4px',
|
||||
background: '#f0f0f0',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
transition: 'all 0.2s',
|
||||
}}
|
||||
className="quick-link-icon"
|
||||
>
|
||||
{item.icon}
|
||||
</div>
|
||||
<div style={{ fontSize: '12px', marginTop: '8px', color: '#666' }}>
|
||||
{item.title}
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
);
|
||||
|
||||
return (
|
||||
<Card
|
||||
title="快捷功能"
|
||||
className="kra-dashboard-card"
|
||||
variant="borderless"
|
||||
>
|
||||
<Row gutter={[12, 12]}>
|
||||
{links.map((link, index) => (
|
||||
<Col span={12} key={index}>
|
||||
<div
|
||||
onClick={() => handleClick(link.path)}
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
padding: '12px 8px',
|
||||
borderRadius: '8px',
|
||||
cursor: 'pointer',
|
||||
transition: 'all 0.2s',
|
||||
background: '#fafafa',
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = `${link.color}10`;
|
||||
e.currentTarget.style.transform = 'translateY(-2px)';
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = '#fafafa';
|
||||
e.currentTarget.style.transform = 'translateY(0)';
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: '20px',
|
||||
color: link.color,
|
||||
marginBottom: '4px',
|
||||
}}
|
||||
>
|
||||
{link.icon}
|
||||
</div>
|
||||
<span style={{ fontSize: '12px', color: '#666' }}>{link.title}</span>
|
||||
</div>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
<Card title="快捷功能" className="kra-dashboard-card" variant="borderless" extra={<a href="#">更多</a>}>
|
||||
<div style={{ marginTop: '32px' }}>
|
||||
<Row>{shortcuts.map(renderItem)}</Row>
|
||||
<Row style={{ marginTop: '32px' }}>{externalLinks.map(renderItem)}</Row>
|
||||
</div>
|
||||
<style>{`
|
||||
.quick-link-item:hover .quick-link-icon {
|
||||
background: #1890ff !important;
|
||||
color: #fff;
|
||||
}
|
||||
`}</style>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,36 +1,33 @@
|
|||
/**
|
||||
* KRA - Dashboard Statistics Cards
|
||||
* 与GVA charts.vue 逻辑一致 - 统计卡片带小图表
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Row, Col, Card, Statistic } from 'antd';
|
||||
import { UserOutlined, TeamOutlined, CheckCircleOutlined } from '@ant-design/icons';
|
||||
import { ArrowUpOutlined } from '@ant-design/icons';
|
||||
import MiniLineChart from './MiniLineChart';
|
||||
|
||||
interface StatItem {
|
||||
title: string;
|
||||
value: number;
|
||||
icon: React.ReactNode;
|
||||
color: string;
|
||||
suffix?: string;
|
||||
data: number[];
|
||||
}
|
||||
|
||||
const stats: StatItem[] = [
|
||||
{
|
||||
title: '访问人数',
|
||||
value: 12580,
|
||||
icon: <UserOutlined />,
|
||||
color: '#1890ff',
|
||||
value: 268500,
|
||||
data: [12, 22, 32, 45, 32, 78, 89, 92],
|
||||
},
|
||||
{
|
||||
title: '新增客户',
|
||||
value: 368,
|
||||
icon: <TeamOutlined />,
|
||||
color: '#52c41a',
|
||||
value: 268500,
|
||||
data: [1, 2, 43, 5, 67, 78, 89, 12],
|
||||
},
|
||||
{
|
||||
title: '解决数量',
|
||||
value: 1024,
|
||||
icon: <CheckCircleOutlined />,
|
||||
color: '#722ed1',
|
||||
value: 268500,
|
||||
data: [12, 22, 32, 45, 32, 78, 89, 92],
|
||||
},
|
||||
];
|
||||
|
||||
|
|
@ -40,28 +37,19 @@ const StatCards: React.FC = () => {
|
|||
{stats.map((stat, index) => (
|
||||
<Col xs={24} sm={8} key={index}>
|
||||
<Card className="kra-dashboard-card" variant="borderless">
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '16px' }}>
|
||||
<div
|
||||
style={{
|
||||
width: '48px',
|
||||
height: '48px',
|
||||
borderRadius: '8px',
|
||||
background: `${stat.color}15`,
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
fontSize: '24px',
|
||||
color: stat.color,
|
||||
}}
|
||||
>
|
||||
{stat.icon}
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<div>
|
||||
<div style={{ fontWeight: 'bold', marginBottom: '8px' }}>{stat.title}</div>
|
||||
<div style={{ marginTop: '16px' }}>
|
||||
<Statistic value={stat.value} />
|
||||
</div>
|
||||
<div style={{ marginTop: '8px', color: '#52c41a', fontSize: '14px', fontWeight: 'bold' }}>
|
||||
+80% <ArrowUpOutlined />
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ width: '50%', height: '80px', position: 'relative' }}>
|
||||
<MiniLineChart data={stat.data} />
|
||||
</div>
|
||||
<Statistic
|
||||
title={stat.title}
|
||||
value={stat.value}
|
||||
suffix={stat.suffix}
|
||||
styles={{ content: { color: stat.color } }}
|
||||
/>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* KRA - Dashboard Update Table Component
|
||||
* 与GVA table.vue 逻辑一致 - 最新更新表格
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Card, Table } from 'antd';
|
||||
import type { ColumnsType } from 'antd/es/table';
|
||||
|
||||
interface UpdateItem {
|
||||
ranking: number;
|
||||
title: string;
|
||||
click_num: number;
|
||||
hot: number;
|
||||
}
|
||||
|
||||
const tableData: UpdateItem[] = [
|
||||
{
|
||||
ranking: 1,
|
||||
title: '更简洁的使用界面,更快速的操作体验',
|
||||
click_num: 523,
|
||||
hot: 263
|
||||
},
|
||||
{
|
||||
ranking: 2,
|
||||
title: '更优质的服务,更便捷的使用体验',
|
||||
click_num: 416,
|
||||
hot: 223
|
||||
},
|
||||
{
|
||||
ranking: 3,
|
||||
title: '更快速的创意实现,更高效的工作效率',
|
||||
click_num: 337,
|
||||
hot: 176
|
||||
},
|
||||
{
|
||||
ranking: 4,
|
||||
title: '更多的创意资源,更多的创意灵感',
|
||||
click_num: 292,
|
||||
hot: 145
|
||||
},
|
||||
{
|
||||
ranking: 5,
|
||||
title: '更合理的代码结构,更清晰的代码逻辑',
|
||||
click_num: 173,
|
||||
hot: 110
|
||||
}
|
||||
];
|
||||
|
||||
const columns: ColumnsType<UpdateItem> = [
|
||||
{
|
||||
title: '排名',
|
||||
dataIndex: 'ranking',
|
||||
width: 80,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '内容标题',
|
||||
dataIndex: 'title',
|
||||
ellipsis: true,
|
||||
},
|
||||
{
|
||||
title: '关注度',
|
||||
dataIndex: 'click_num',
|
||||
width: 100,
|
||||
},
|
||||
{
|
||||
title: '热度值',
|
||||
dataIndex: 'hot',
|
||||
width: 100,
|
||||
},
|
||||
];
|
||||
|
||||
const UpdateTable: React.FC = () => {
|
||||
return (
|
||||
<Card title="最新更新" className="kra-dashboard-card" variant="borderless">
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={tableData}
|
||||
rowKey="ranking"
|
||||
pagination={false}
|
||||
size="small"
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateTable;
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* KRA - Dashboard Wiki Component
|
||||
* 与GVA wiki.vue 逻辑一致 - 文档链接
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Card, Row, Col } from 'antd';
|
||||
|
||||
interface WikiItem {
|
||||
title: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
const wikis: WikiItem[] = [
|
||||
{
|
||||
title: 'React',
|
||||
url: 'https://react.dev/'
|
||||
},
|
||||
{
|
||||
title: 'Kratos 文档',
|
||||
url: 'https://go-kratos.dev/'
|
||||
},
|
||||
{
|
||||
title: 'Ant Design',
|
||||
url: 'https://ant.design/'
|
||||
},
|
||||
{
|
||||
title: 'UmiJS',
|
||||
url: 'https://umijs.org/'
|
||||
},
|
||||
{
|
||||
title: 'GitHub 仓库',
|
||||
url: 'https://github.com/go-kratos/kratos'
|
||||
}
|
||||
];
|
||||
|
||||
const Wiki: React.FC = () => {
|
||||
return (
|
||||
<Card title="文档" className="kra-dashboard-card" variant="borderless" extra={<a href="#">更多</a>}>
|
||||
<Row gutter={[8, 8]}>
|
||||
{wikis.map((item, index) => (
|
||||
<Col span={12} key={index}>
|
||||
<a
|
||||
href={item.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{
|
||||
fontSize: '14px',
|
||||
color: '#666',
|
||||
textDecoration: 'none',
|
||||
}}
|
||||
onMouseEnter={(e) => (e.currentTarget.style.color = '#1890ff')}
|
||||
onMouseLeave={(e) => (e.currentTarget.style.color = '#666')}
|
||||
>
|
||||
{item.title}
|
||||
</a>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default Wiki;
|
||||
|
|
@ -1,9 +1,12 @@
|
|||
/**
|
||||
* KRA - Dashboard Components Index
|
||||
* KRA - Dashboard Components Export
|
||||
*/
|
||||
export { default as Banner } from './Banner';
|
||||
export { default as StatCards } from './StatCards';
|
||||
export { default as Charts } from './Charts';
|
||||
export { default as QuickLinks } from './QuickLinks';
|
||||
export { default as Notice } from './Notice';
|
||||
export { default as Wiki } from './Wiki';
|
||||
export { default as UpdateTable } from './UpdateTable';
|
||||
export { default as PluginTable } from './PluginTable';
|
||||
export { default as MiniLineChart } from './MiniLineChart';
|
||||
|
|
|
|||
|
|
@ -1,44 +1,143 @@
|
|||
/**
|
||||
* KRA - Dashboard Styles
|
||||
* Dashboard 样式
|
||||
*/
|
||||
|
||||
.kra-dashboard {
|
||||
padding: 16px;
|
||||
.dashboard {
|
||||
:global {
|
||||
.ant-page-header {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.kra-dashboard-card {
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03);
|
||||
.statCard {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.kra-dashboard-card-header {
|
||||
.statContent {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.statInfo {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.statValue {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
.statTrend {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.statChart {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
.chartCard {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
.dataItem {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.dataValue {
|
||||
font-size: 28px;
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.dataName {
|
||||
color: #666;
|
||||
margin: 8px 0;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.progressSection {
|
||||
margin-top: 32px;
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.progressTitle {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.progressItem {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.progressLabel {
|
||||
margin-bottom: 8px;
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
|
||||
:global(.anticon) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.quickCard {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.shortcutItem {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 12px 4px;
|
||||
cursor: pointer;
|
||||
border-radius: 8px;
|
||||
transition: all 0.2s;
|
||||
|
||||
&:hover {
|
||||
background: #f0f5ff;
|
||||
|
||||
.shortcutIcon {
|
||||
background: #1890ff;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shortcutIcon {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 4px;
|
||||
background: #f0f0f0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 16px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.shortcutTitle {
|
||||
font-size: 12px;
|
||||
margin-top: 8px;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.noticeCard,
|
||||
.docCard,
|
||||
.sysCard {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sysItem {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 16px;
|
||||
align-items: center;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.kra-dashboard-card-body {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
// Dark mode
|
||||
:global(.dark) {
|
||||
.kra-dashboard-card {
|
||||
background: #1f1f1f;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.kra-dashboard-card-header {
|
||||
border-color: #303030;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,57 +1,272 @@
|
|||
/**
|
||||
* KRA - Dashboard Page
|
||||
* Main dashboard with statistics, charts, and quick links
|
||||
* 仪表盘页面
|
||||
* 参考 GVA 的 Dashboard 布局
|
||||
*/
|
||||
import React from 'react';
|
||||
import { Row, Col } from 'antd';
|
||||
import { Helmet } from '@umijs/max';
|
||||
import Banner from './components/Banner';
|
||||
import StatCards from './components/StatCards';
|
||||
import Charts from './components/Charts';
|
||||
import QuickLinks from './components/QuickLinks';
|
||||
import Notice from './components/Notice';
|
||||
import PluginTable from './components/PluginTable';
|
||||
import './index.less';
|
||||
import { PageContainer } from '@ant-design/pro-components';
|
||||
import { Card, Col, Row, Statistic, Tag, List, Typography, Progress, Space, Tooltip } from 'antd';
|
||||
import {
|
||||
UserOutlined,
|
||||
TeamOutlined,
|
||||
ApiOutlined,
|
||||
MenuOutlined,
|
||||
RiseOutlined,
|
||||
SettingOutlined,
|
||||
DatabaseOutlined,
|
||||
LinkOutlined,
|
||||
SafetyOutlined,
|
||||
CloudServerOutlined,
|
||||
CodeOutlined,
|
||||
FolderOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { history } from '@umijs/max';
|
||||
import styles from './index.less';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
// 统计卡片数据
|
||||
const statsData = [
|
||||
{ title: '访问人数', value: 268500, icon: <UserOutlined />, trend: '+80%', color: '#1890ff', percent: 80 },
|
||||
{ title: '新增客户', value: 12580, icon: <TeamOutlined />, trend: '+25%', color: '#52c41a', percent: 65 },
|
||||
{ title: '解决数量', value: 8846, icon: <ApiOutlined />, trend: '+15%', color: '#722ed1', percent: 45 },
|
||||
];
|
||||
|
||||
// 快捷功能 - 与GVA quickLinks.vue 一致
|
||||
const shortcuts = [
|
||||
{ icon: <MenuOutlined />, title: '菜单管理', path: '/admin/menu' },
|
||||
{ icon: <LinkOutlined />, title: 'API管理', path: '/admin/api' },
|
||||
{ icon: <SafetyOutlined />, title: '角色管理', path: '/admin/authority' },
|
||||
{ icon: <UserOutlined />, title: '用户管理', path: '/admin/user' },
|
||||
{ icon: <FolderOutlined />, title: '自动化包', path: '/systemTools/autoCodeAdmin' },
|
||||
{ icon: <CodeOutlined />, title: '自动代码', path: '/systemTools/autoCode' },
|
||||
];
|
||||
|
||||
// 公告数据
|
||||
const notices = [
|
||||
{ type: 'processing', typeTitle: '公告', title: 'Kratos Admin v1.0 正式发布,欢迎使用!' },
|
||||
{ type: 'success', typeTitle: '通知', title: '系统已完成安全升级,请放心使用。' },
|
||||
{ type: 'warning', typeTitle: '警告', title: '请定期修改密码,确保账户安全。' },
|
||||
{ type: 'error', typeTitle: '重要', title: '数据库将于本周日凌晨进行维护。' },
|
||||
{ type: 'default', typeTitle: '信息', title: '感谢您对 Kratos Admin 的支持!' },
|
||||
];
|
||||
|
||||
// 内容数据
|
||||
const contentData = [
|
||||
{ name: '用户', value: 128, color: '#1890ff' },
|
||||
{ name: '角色', value: 8, color: '#52c41a' },
|
||||
{ name: 'API', value: 256, color: '#722ed1' },
|
||||
{ name: '菜单', value: 32, color: '#faad14' },
|
||||
{ name: '字典', value: 15, color: '#13c2c2' },
|
||||
{ name: '部门', value: 12, color: '#eb2f96' },
|
||||
];
|
||||
|
||||
// 文档链接
|
||||
const docLinks = [
|
||||
{ title: 'Kratos 官方文档', url: 'https://go-kratos.dev/' },
|
||||
{ title: 'Ant Design Pro', url: 'https://pro.ant.design/' },
|
||||
{ title: 'React 官方文档', url: 'https://react.dev/' },
|
||||
{ title: 'Go 语言文档', url: 'https://go.dev/doc/' },
|
||||
];
|
||||
|
||||
const Dashboard: React.FC = () => {
|
||||
return (
|
||||
<div className="kra-dashboard">
|
||||
<Helmet>
|
||||
<title>仪表盘 - Kratos Admin</title>
|
||||
</Helmet>
|
||||
|
||||
<PageContainer
|
||||
header={{ title: '' }}
|
||||
className={styles.dashboard}
|
||||
>
|
||||
{/* 统计卡片行 */}
|
||||
<Row gutter={[16, 16]}>
|
||||
{/* Statistics Cards */}
|
||||
{statsData.map((item, index) => (
|
||||
<Col xs={24} sm={12} lg={8} key={index}>
|
||||
<Card className={styles.statCard} variant="borderless">
|
||||
<div className={styles.statContent}>
|
||||
<div className={styles.statInfo}>
|
||||
<Text type="secondary">{item.title}</Text>
|
||||
<div className={styles.statValue}>
|
||||
<Statistic value={item.value} valueStyle={{ fontSize: 28, fontWeight: 600 }} />
|
||||
</div>
|
||||
<div className={styles.statTrend}>
|
||||
<RiseOutlined style={{ color: '#52c41a' }} />
|
||||
<Text style={{ color: '#52c41a', marginLeft: 4 }}>{item.trend}</Text>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.statChart}>
|
||||
<Progress
|
||||
type="circle"
|
||||
percent={item.percent}
|
||||
size={80}
|
||||
strokeColor={item.color}
|
||||
format={() => <span style={{ fontSize: 14 }}>{item.percent}%</span>}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
|
||||
{/* 主内容区 */}
|
||||
<Row gutter={[16, 16]} style={{ marginTop: 16 }}>
|
||||
{/* 左侧内容数据 */}
|
||||
<Col xs={24} lg={18}>
|
||||
<StatCards />
|
||||
<Card title="内容数据" variant="borderless" className={styles.chartCard}>
|
||||
<Row gutter={[16, 24]}>
|
||||
{contentData.map((item, index) => (
|
||||
<Col xs={12} sm={8} md={4} key={index}>
|
||||
<div className={styles.dataItem}>
|
||||
<div className={styles.dataValue} style={{ color: item.color }}>
|
||||
{item.value}
|
||||
</div>
|
||||
<div className={styles.dataName}>{item.name}</div>
|
||||
<Progress
|
||||
percent={Math.min((item.value / 300) * 100, 100)}
|
||||
showInfo={false}
|
||||
strokeColor={item.color}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
<div className={styles.progressSection}>
|
||||
<div className={styles.progressTitle}>系统资源使用情况</div>
|
||||
<Row gutter={[32, 16]} style={{ marginTop: 16 }}>
|
||||
<Col xs={24} sm={12}>
|
||||
<div className={styles.progressItem}>
|
||||
<div className={styles.progressLabel}>
|
||||
<CloudServerOutlined /> CPU 使用率
|
||||
</div>
|
||||
<Progress percent={45} strokeColor="#1890ff" />
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} sm={12}>
|
||||
<div className={styles.progressItem}>
|
||||
<div className={styles.progressLabel}>
|
||||
<DatabaseOutlined /> 内存使用率
|
||||
</div>
|
||||
<Progress percent={68} strokeColor="#52c41a" />
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} sm={12}>
|
||||
<div className={styles.progressItem}>
|
||||
<div className={styles.progressLabel}>
|
||||
<SafetyOutlined /> 磁盘使用率
|
||||
</div>
|
||||
<Progress percent={32} strokeColor="#722ed1" />
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} sm={12}>
|
||||
<div className={styles.progressItem}>
|
||||
<div className={styles.progressLabel}>
|
||||
<ApiOutlined /> API 调用量
|
||||
</div>
|
||||
<Progress percent={85} strokeColor="#faad14" />
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
{/* Quick Links */}
|
||||
{/* 右侧快捷功能 */}
|
||||
<Col xs={24} lg={6}>
|
||||
<QuickLinks />
|
||||
</Col>
|
||||
|
||||
{/* Main Chart */}
|
||||
<Col xs={24} lg={18}>
|
||||
<Charts />
|
||||
</Col>
|
||||
|
||||
{/* Notice */}
|
||||
<Col xs={24} lg={6}>
|
||||
<Notice />
|
||||
</Col>
|
||||
|
||||
{/* Plugin Table */}
|
||||
<Col xs={24} lg={18}>
|
||||
<PluginTable />
|
||||
</Col>
|
||||
|
||||
{/* Banner */}
|
||||
<Col xs={24} lg={6}>
|
||||
<Banner />
|
||||
<Card title="快捷功能" variant="borderless" className={styles.quickCard}>
|
||||
<Row gutter={[8, 16]}>
|
||||
{shortcuts.map((item, index) => (
|
||||
<Col span={8} key={index}>
|
||||
<div
|
||||
className={styles.shortcutItem}
|
||||
onClick={() => history.push(item.path)}
|
||||
>
|
||||
<div className={styles.shortcutIcon}>{item.icon}</div>
|
||||
<Text className={styles.shortcutTitle}>{item.title}</Text>
|
||||
</div>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
{/* 底部区域 */}
|
||||
<Row gutter={[16, 16]} style={{ marginTop: 16 }}>
|
||||
{/* 公告 */}
|
||||
<Col xs={24} md={12} lg={8}>
|
||||
<Card
|
||||
title="公告"
|
||||
variant="borderless"
|
||||
extra={<a>查看更多</a>}
|
||||
className={styles.noticeCard}
|
||||
>
|
||||
<List
|
||||
size="small"
|
||||
dataSource={notices}
|
||||
renderItem={(item) => (
|
||||
<List.Item style={{ padding: '8px 0', border: 'none' }}>
|
||||
<Space>
|
||||
<Tag color={item.type}>{item.typeTitle}</Tag>
|
||||
<Tooltip title={item.title}>
|
||||
<Text ellipsis style={{ maxWidth: 200 }}>{item.title}</Text>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
{/* 文档链接 */}
|
||||
<Col xs={24} md={12} lg={8}>
|
||||
<Card
|
||||
title="文档"
|
||||
variant="borderless"
|
||||
extra={<a>查看更多</a>}
|
||||
className={styles.docCard}
|
||||
>
|
||||
<List
|
||||
size="small"
|
||||
dataSource={docLinks}
|
||||
renderItem={(item) => (
|
||||
<List.Item style={{ padding: '8px 0', border: 'none' }}>
|
||||
<a href={item.url} target="_blank" rel="noopener noreferrer">
|
||||
<Space>
|
||||
<LinkOutlined />
|
||||
<Text>{item.title}</Text>
|
||||
</Space>
|
||||
</a>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
{/* 系统信息 */}
|
||||
<Col xs={24} lg={8}>
|
||||
<Card title="系统信息" variant="borderless" className={styles.sysCard}>
|
||||
<div className={styles.sysItem}>
|
||||
<Text type="secondary">系统名称</Text>
|
||||
<Text strong>Kratos Admin</Text>
|
||||
</div>
|
||||
<div className={styles.sysItem}>
|
||||
<Text type="secondary">后端框架</Text>
|
||||
<Text strong>Go Kratos</Text>
|
||||
</div>
|
||||
<div className={styles.sysItem}>
|
||||
<Text type="secondary">前端框架</Text>
|
||||
<Text strong>React + Ant Design Pro</Text>
|
||||
</div>
|
||||
<div className={styles.sysItem}>
|
||||
<Text type="secondary">版本号</Text>
|
||||
<Text strong>v1.0.0</Text>
|
||||
</div>
|
||||
<div className={styles.sysItem}>
|
||||
<Text type="secondary">服务器状态</Text>
|
||||
<Tag color="success">运行中</Tag>
|
||||
</div>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</PageContainer>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue