feat: project list
This commit is contained in:
10
apps/web/src/hooks/useAsyncEffect.ts
Normal file
10
apps/web/src/hooks/useAsyncEffect.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
export function useAsyncEffect(
|
||||
effect: () => Promise<void>,
|
||||
deps: React.DependencyList,
|
||||
) {
|
||||
useEffect(() => {
|
||||
effect();
|
||||
}, [...deps]);
|
||||
}
|
||||
@@ -1,12 +1,9 @@
|
||||
import { Avatar, Layout, Menu } from '@arco-design/web-react';
|
||||
import {
|
||||
IconApps,
|
||||
IconBulb,
|
||||
IconFire,
|
||||
IconMenuFold,
|
||||
IconMenuUnfold,
|
||||
IconRobot,
|
||||
IconSafe,
|
||||
IconUser,
|
||||
} from '@arco-design/web-react/icon';
|
||||
import { useState } from 'react';
|
||||
@@ -21,9 +18,15 @@ function Home() {
|
||||
<Layout.Sider
|
||||
collapsible
|
||||
onCollapse={setCollapsed}
|
||||
trigger={collapsed ? <IconMenuUnfold /> : <IconMenuFold />}
|
||||
trigger={
|
||||
collapsed ? (
|
||||
<IconMenuUnfold fontSize={16} />
|
||||
) : (
|
||||
<IconMenuFold fontSize={16} />
|
||||
)
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row items-center justify-center px-2 py-3">
|
||||
<div className="flex flex-row items-center justify-center h-[56px]">
|
||||
<Logo />
|
||||
{!collapsed && <h2 className="ml-4 text-xl font-medium">Foka CI</h2>}
|
||||
</div>
|
||||
@@ -31,16 +34,17 @@ function Home() {
|
||||
className="flex-1"
|
||||
defaultOpenKeys={['0']}
|
||||
defaultSelectedKeys={['0_1']}
|
||||
collapse={collapsed}
|
||||
>
|
||||
<Menu.Item key="0">
|
||||
<Link to="/project" className="flex flex-row items-center">
|
||||
<IconApps fontSize={18} />
|
||||
项目管理
|
||||
<Link to="/project">
|
||||
<IconApps fontSize={16} />
|
||||
<span>项目管理</span>
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="1">
|
||||
<Link to="/env" className="flex flex-row items-center">
|
||||
<IconRobot fontSize={18} />
|
||||
<Link to="/env">
|
||||
<IconRobot fontSize={16} />
|
||||
环境管理
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
|
||||
@@ -1,8 +1,114 @@
|
||||
import { Card, Grid, Link, Tag, Avatar, Space, Typography, Button } from '@arco-design/web-react';
|
||||
import { IconBranch, IconCalendar, IconEye } from '@arco-design/web-react/icon';
|
||||
import { useState } from 'react';
|
||||
import type { Project } from './types';
|
||||
import { useAsyncEffect } from '../../hooks/useAsyncEffect';
|
||||
import { projectService } from './service';
|
||||
import IconGitea from '@assets/images/gitea.svg?react'
|
||||
|
||||
function Project() {
|
||||
const [projects, setProjects] = useState([]);
|
||||
return <div>project page</div>;
|
||||
const { Text, Paragraph } = Typography;
|
||||
|
||||
function ProjectPage() {
|
||||
const [projects, setProjects] = useState<Project[]>([]);
|
||||
|
||||
useAsyncEffect(async () => {
|
||||
const list = await projectService.list();
|
||||
setProjects(list);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="p-6 bg-gray-100 min-h-screen">
|
||||
<div className="mb-6">
|
||||
<Typography.Title heading={2} className="!m-0 !text-gray-900">
|
||||
我的项目
|
||||
</Typography.Title>
|
||||
<Text type="secondary">管理和查看您的所有项目</Text>
|
||||
</div>
|
||||
|
||||
<Grid.Row gutter={[16, 16]}>
|
||||
{projects.map((project) => (
|
||||
<Grid.Col key={project.id} span={8}>
|
||||
<Card
|
||||
className="foka-card !rounded-xl border border-gray-200 h-[280px] hover:border-blue-200"
|
||||
hoverable
|
||||
bodyStyle={{ padding: '20px' }}
|
||||
>
|
||||
{/* 项目头部 */}
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center space-x-3">
|
||||
<Avatar
|
||||
size={40}
|
||||
className="bg-blue-600 text-white text-base font-semibold"
|
||||
>
|
||||
{project.name.charAt(0).toUpperCase()}
|
||||
</Avatar>
|
||||
<div className="ml-3">
|
||||
<Typography.Title
|
||||
heading={5}
|
||||
className="!m-0 !text-base !font-semibold"
|
||||
>
|
||||
{project.name}
|
||||
</Typography.Title>
|
||||
<Text type="secondary" className="text-xs">
|
||||
更新于 2天前
|
||||
</Text>
|
||||
</div>
|
||||
</div>
|
||||
<Tag color="blue" size="small">
|
||||
活跃
|
||||
</Tag>
|
||||
</div>
|
||||
|
||||
{/* 项目描述 */}
|
||||
<Paragraph
|
||||
className="!m-0 !mb-4 !text-gray-600 !text-sm !leading-6 h-[42px] overflow-hidden line-clamp-2"
|
||||
>
|
||||
{project.description || '暂无描述'}
|
||||
</Paragraph>
|
||||
|
||||
{/* 项目信息 */}
|
||||
<div className="mb-4">
|
||||
<div className="mb-2 flex items-center">
|
||||
<IconGitea className="mr-1.5 w-4" />
|
||||
<Text
|
||||
type="secondary"
|
||||
className="text-xs"
|
||||
>
|
||||
{project.repository}
|
||||
</Text>
|
||||
</div>
|
||||
<Space size={16}>
|
||||
<div className="flex items-center">
|
||||
<IconBranch className="mr-1 text-gray-500 text-xs" />
|
||||
<Text className="text-xs text-gray-500">main</Text>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<IconCalendar className="mr-1 text-gray-500 text-xs" />
|
||||
<Text className="text-xs text-gray-500">3个提交</Text>
|
||||
</div>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
{/* 操作按钮 */}
|
||||
<div className="flex items-center justify-between pt-3 border-t border-gray-100">
|
||||
<Button
|
||||
type="text"
|
||||
size="small"
|
||||
icon={<IconEye />}
|
||||
className="text-gray-500"
|
||||
>
|
||||
查看详情
|
||||
</Button>
|
||||
<Link className="text-xs font-medium">
|
||||
管理项目 →
|
||||
</Link>
|
||||
</div>
|
||||
</Card>
|
||||
</Grid.Col>
|
||||
))}
|
||||
</Grid.Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Project;
|
||||
export default ProjectPage;
|
||||
|
||||
16
apps/web/src/pages/project/service.ts
Normal file
16
apps/web/src/pages/project/service.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { net, type APIResponse } from "@shared";
|
||||
import type { Project } from "./types";
|
||||
|
||||
|
||||
class ProjectService {
|
||||
|
||||
async list() {
|
||||
const { data } = await net.request<APIResponse<Project[]>>({
|
||||
method: 'GET',
|
||||
url: '/api/project/list',
|
||||
})
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
export const projectService = new ProjectService();
|
||||
@@ -8,7 +8,7 @@ export interface Project {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
git: string;
|
||||
repository: string;
|
||||
env: Record<string, string>;
|
||||
createdAt: string;
|
||||
status: BuildStatus;
|
||||
|
||||
Reference in New Issue
Block a user