Files
2026-07-13 15:23:29 +08:00

293 lines
9.2 KiB
TypeScript
Raw Permalink 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.
import {Card, Avatar, List, Badge, Tag, Divider, Typography, Space, Empty} from 'antd';
import {
ProjectOutlined,
TeamOutlined,
BellOutlined,
ClockCircleOutlined,
MailOutlined,
PhoneOutlined,
EnvironmentOutlined,
LinkOutlined,
SmileOutlined,
AppstoreOutlined,
ShopOutlined,
FileTextOutlined,
} from '@ant-design/icons';
import { useTranslation } from 'react-i18next';
import useAuthStore from "@/stores/user";
import type {ReactNode} from "react";
const { Meta } = Card;
const { Text, Title } = Typography;
interface AppType {
id: number;
name: string;
description: string;
icon: ReactNode;
badge?: string;
color: string;
}
const PersonalCenter = () => {
const { t } = useTranslation();
// 用户信息数据
const userInfo = useAuthStore(state => state.userinfo);
if (! userInfo ) return <></>;
// 标签页列表数据
const tabList = [
{
key: "projects",
label: <><ProjectOutlined className={'mr-2'}/> {t('dashboard.workplace.myProjects')} </>,
},
{
key: "teams",
label: <><TeamOutlined className={'mr-2'}/> {t('dashboard.workplace.myTeams')} </>,
},
{
key: "activities",
label: <><ClockCircleOutlined className={'mr-2'}/> {t('dashboard.workplace.latestActivities')} </>,
},
{
key: "notifications",
label: (
<Badge count={1} offset={[10, 0]}>
<span>
<BellOutlined className={'mr-2'} />
{t('dashboard.workplace.notifications')}
</span>
</Badge>
)
},
]
// 我的项目数据
const projects = [
{
id: 1,
name: t('dashboard.workplace.project1.name'),
description: t('dashboard.workplace.project1.desc'),
status: t('dashboard.workplace.status.inProgress'),
progress: 65,
members: 5,
},
{
id: 2,
name: t('dashboard.workplace.project2.name'),
description: t('dashboard.workplace.project2.desc'),
status: t('dashboard.workplace.status.completed'),
progress: 100,
members: 3,
},
{
id: 3,
name: t('dashboard.workplace.project3.name'),
description: t('dashboard.workplace.project3.desc'),
status: t('dashboard.workplace.status.planning'),
progress: 10,
members: 2,
},
{
id: 4,
name: t('dashboard.workplace.project4.name'),
description: t('dashboard.workplace.project4.desc'),
status: '2023-06-10',
progress: 10,
members: 2,
},
{
id: 5,
name: t('dashboard.workplace.project5.name'),
description: t('dashboard.workplace.project5.desc'),
status: '2023-06-08',
progress: 15,
members: 5,
},
{
id: 6,
name: t('dashboard.workplace.project6.name'),
description: t('dashboard.workplace.project6.desc'),
status: '2023-06-05',
progress: 60,
members: 3,
},
];
// APP 应用列表
const apps: AppType[] = [
{
id: 1,
name: t('dashboard.workplace.appStore'),
icon: <AppstoreOutlined />,
description: t('dashboard.workplace.appStore.desc'),
badge: t('dashboard.workplace.badge.new'),
color: '#1890ff',
},
{
id: 2,
name: t('dashboard.workplace.mallSystem'),
icon: <ShopOutlined />,
description: t('dashboard.workplace.mallSystem.desc'),
color: '#52c41a',
},
{
id: 3,
name: t('dashboard.workplace.collaboration'),
icon: <TeamOutlined />,
description: t('dashboard.workplace.collaboration.desc'),
color: '#faad14',
},
{
id: 4,
name: t('dashboard.workplace.docCenter'),
icon: <FileTextOutlined />,
description: t('dashboard.workplace.docCenter.desc'),
color: '#13c2c2',
}
];
// 获取当前时间问候语
const getGreeting = () => {
const hour = new Date().getHours();
if (hour < 12) return t('dashboard.workplace.greeting.morning');
if (hour < 18) return t('dashboard.workplace.greeting.afternoon');
return t('dashboard.workplace.greeting.evening');
};
// APP 应用卡片
const AppCard = (props: {app: AppType}) => (
<Card
hoverable
variant={'borderless'}
cover={
<div
className="flex items-center justify-center h-32"
style={{ backgroundColor: `${props.app.color}20` }} // 20表示透明度
>
<Avatar
icon={props.app.icon}
size={64}
style={{
backgroundColor: props.app.color,
color: '#fff',
fontSize: '28px',
}}
/>
</div>
}
>
<Meta
title={<span className="font-semibold">{props.app.name}</span>}
description={props.app.description}
/>
</Card>
)
return (
<div className="grid grid-cols-1 lg:grid-cols-4 gap-6">
{/* 左侧布局显示内容 */}
<div className="lg:col-span-3 space-y-6">
<Card variant={'borderless'} styles={{body: {padding: 0}}} className={'overflow-hidden'}>
<div className="bg-gradient-to-r from-blue-500 to-purple-600 flex items-center p-8">
<Space size="large" className="w-full">
<Avatar
size={64}
src={userInfo.avatar_url}
icon={<SmileOutlined />}
className="border-2 border-white shadow"
/>
<div className="flex-1">
<Title level={3} className="!text-white !mb-1">
{getGreeting()}{userInfo.nickname}{t('dashboard.workplace.welcome')}
</Title>
</div>
<div className="hidden md:block">
<Text className="text-white/80 text-lg">
{t('dashboard.workplace.today')} {new Date().toLocaleDateString('zh-CN', {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
})}
</Text>
</div>
</Space>
</div>
</Card>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{apps.map((app) => (
<div key={app.id}>
{ app.badge ?
<Badge.Ribbon text={app.badge} color={app.color}>
<AppCard app={app}></AppCard>
</Badge.Ribbon>
:
<AppCard app={app} ></AppCard>
}
</div>
))}
</div>
<Card variant={'borderless'} defaultActiveTabKey="projects" tabList={tabList}>
<List
itemLayout="horizontal"
dataSource={projects}
renderItem={(item) => (
<List.Item>
<List.Item.Meta
avatar={<Avatar icon={<ProjectOutlined />} />}
title={<a href="#">{item.name}</a>}
description={item.description}
/>
<div className="flex flex-col items-end">
<Tag color={item.status === t('dashboard.workplace.status.completed') ? 'success' : item.status === t('dashboard.workplace.status.inProgress') ? 'processing' : 'default'}>
{item.status}
</Tag>
<div className="mt-2">
<span className="text-gray-500 mr-2">{t('dashboard.workplace.progress')}: {item.progress}%</span>
<span className="text-gray-500">{t('dashboard.workplace.members')}: {item.members}{t('dashboard.workplace.people')}</span>
</div>
</div>
</List.Item>
)}
/>
</Card>
</div>
{/* 右侧布局显示内容 */}
<div className="lg:col-span-1">
<Card variant={'borderless'} className="mb-5">
<div className="flex flex-col items-center">
<Avatar size={100} src={userInfo.avatar_url} className="mb-4" />
<h2 className="text-xl font-bold mb-2">{userInfo.nickname}</h2>
<Tag color="blue" className="mb-4">
{userInfo.dept_name}
</Tag>
<p className="text-gray-700 mb-2 text-center">hello</p>
<Divider className="my-3 mb-4" />
<div className="w-full space-y-3">
<div className="flex items-center text-gray-600">
<MailOutlined className="mr-2" />
<span>{userInfo.email}</span>
</div>
<div className="flex items-center text-gray-600">
<PhoneOutlined className="mr-2" />
<span>{userInfo.mobile}</span>
</div>
<div className="flex items-center text-gray-600">
<EnvironmentOutlined className="mr-2" />
<span>{t('dashboard.workplace.location')}</span>
</div>
<div className="flex items-center text-gray-600">
<LinkOutlined className="mr-2" />
<a target="_blank" rel="noopener noreferrer" className="text-blue-500">
123
</a>
</div>
</div>
</div>
</Card>
<Card variant={'borderless'} title={t('dashboard.workplace.recentVisits')}>
<Empty/>
</Card>
</div>
</div>
);
};
export default PersonalCenter;