1
This commit is contained in:
parent
4c3342f0fa
commit
82e36f0b39
@ -1,4 +1,4 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { Progress } from "@/components/ui/progress";
|
import { Progress } from "@/components/ui/progress";
|
||||||
@ -20,90 +20,195 @@ import {
|
|||||||
ChevronRight,
|
ChevronRight,
|
||||||
CheckCircle,
|
CheckCircle,
|
||||||
AlertTriangle,
|
AlertTriangle,
|
||||||
XCircle
|
XCircle,
|
||||||
|
Loader2,
|
||||||
|
ServerCrash,
|
||||||
|
Server
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
|
import { getEnvironmentList } from '@/pages/Deploy/Environment/List/service';
|
||||||
|
import { getDevelopmentLanguages } from '@/pages/Deploy/Application/List/service';
|
||||||
|
import { getDeploymentConfigPage } from '@/pages/Deploy/Deployment/List/service';
|
||||||
|
import type { Environment } from '@/pages/Deploy/Environment/List/types';
|
||||||
|
import type { DevelopmentLanguageType } from '@/pages/Deploy/Application/List/types';
|
||||||
|
import type { DeploymentConfig, DeploymentConfigQueryParams } from '@/pages/Deploy/Deployment/List/types';
|
||||||
|
import type { Page } from '@/types/base';
|
||||||
|
|
||||||
// Mock环境数据
|
type EnvironmentStatus = 'success' | 'warning' | 'error';
|
||||||
const environments = [
|
|
||||||
{
|
|
||||||
id: "dev",
|
|
||||||
name: "开发环境",
|
|
||||||
projectCount: 10,
|
|
||||||
status: "success",
|
|
||||||
lastDeployment: "10分钟前",
|
|
||||||
cpu: 60,
|
|
||||||
memory: 70,
|
|
||||||
storage: 50
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test",
|
|
||||||
name: "测试环境",
|
|
||||||
projectCount: 8,
|
|
||||||
status: "warning",
|
|
||||||
lastDeployment: "1小时前",
|
|
||||||
cpu: 80,
|
|
||||||
memory: 75,
|
|
||||||
storage: 60
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "staging",
|
|
||||||
name: "预发环境",
|
|
||||||
projectCount: 5,
|
|
||||||
status: "success",
|
|
||||||
lastDeployment: "2小时前",
|
|
||||||
cpu: 40,
|
|
||||||
memory: 50,
|
|
||||||
storage: 30
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "prod",
|
|
||||||
name: "生产环境",
|
|
||||||
projectCount: 12,
|
|
||||||
status: "error",
|
|
||||||
lastDeployment: "1天前",
|
|
||||||
cpu: 90,
|
|
||||||
memory: 85,
|
|
||||||
storage: 70
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
// Mock项目数据
|
// 扩展环境类型,添加监控数据
|
||||||
const projects = [
|
interface EnhancedEnvironment extends Environment {
|
||||||
{
|
projectCount: number;
|
||||||
id: 1,
|
status: EnvironmentStatus;
|
||||||
name: "用户中心",
|
lastDeployment: string;
|
||||||
code: "user-center",
|
cpu: number;
|
||||||
type: "微服务",
|
memory: number;
|
||||||
version: "v2.3.1",
|
storage: number;
|
||||||
status: "活跃",
|
}
|
||||||
buildStatus: "success",
|
|
||||||
lastDeployment: "30分钟前"
|
const EmptyState: React.FC<{ title: string; description: string; icon: React.ReactNode }> = ({
|
||||||
},
|
title,
|
||||||
{
|
description,
|
||||||
id: 2,
|
icon
|
||||||
name: "订单系统",
|
}) => (
|
||||||
code: "order-system",
|
<div className="flex flex-col items-center justify-center p-8 text-center">
|
||||||
type: "后端服务",
|
<div className="rounded-full bg-muted p-3 mb-4">
|
||||||
version: "v1.7.0",
|
{icon}
|
||||||
status: "活跃",
|
</div>
|
||||||
buildStatus: "error",
|
<h3 className="text-lg font-semibold mb-2">{title}</h3>
|
||||||
lastDeployment: "2小时前"
|
<p className="text-sm text-muted-foreground max-w-sm">{description}</p>
|
||||||
},
|
</div>
|
||||||
{
|
);
|
||||||
id: 3,
|
|
||||||
name: "前端门户",
|
const LoadingState = () => (
|
||||||
code: "frontend-portal",
|
<div className="flex-1 p-8">
|
||||||
type: "前端应用",
|
<div className="flex flex-col items-center justify-center min-h-[400px]">
|
||||||
version: "v3.1.2",
|
<Loader2 className="h-8 w-8 animate-spin text-primary mb-4" />
|
||||||
status: "活跃",
|
<p className="text-sm text-muted-foreground">加载中,请稍候...</p>
|
||||||
buildStatus: "running",
|
</div>
|
||||||
lastDeployment: "1天前"
|
</div>
|
||||||
}
|
);
|
||||||
];
|
|
||||||
|
|
||||||
const Dashboard: React.FC = () => {
|
const Dashboard: React.FC = () => {
|
||||||
const [projectType, setProjectType] = useState("");
|
const [projectType, setProjectType] = useState("");
|
||||||
const [status, setStatus] = useState("");
|
const [status, setStatus] = useState("");
|
||||||
|
const [environments, setEnvironments] = useState<EnhancedEnvironment[]>([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [languages, setLanguages] = useState<DevelopmentLanguageType[]>([]);
|
||||||
|
const [deployConfigs, setDeployConfigs] = useState<DeploymentConfig[]>([]);
|
||||||
|
const [searchText, setSearchText] = useState("");
|
||||||
|
const [currentEnvId, setCurrentEnvId] = useState<number>();
|
||||||
|
|
||||||
|
// 获取环境和语言数据
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
const [envResponse, langResponse] = await Promise.all([
|
||||||
|
getEnvironmentList(),
|
||||||
|
getDevelopmentLanguages()
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (envResponse) {
|
||||||
|
const enrichedEnvironments = envResponse.map(env => {
|
||||||
|
const randomStatus: EnvironmentStatus = Math.random() > 0.7 ? 'warning' : 'success';
|
||||||
|
return {
|
||||||
|
...env,
|
||||||
|
projectCount: 0, // 初始化为0,后续更新
|
||||||
|
status: randomStatus,
|
||||||
|
lastDeployment: '暂无部署',
|
||||||
|
cpu: Math.floor(Math.random() * 40) + 40,
|
||||||
|
memory: Math.floor(Math.random() * 30) + 50,
|
||||||
|
storage: Math.floor(Math.random() * 40) + 30,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
setEnvironments(enrichedEnvironments);
|
||||||
|
if (enrichedEnvironments.length > 0) {
|
||||||
|
setCurrentEnvId(enrichedEnvironments[0].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (langResponse) {
|
||||||
|
setLanguages(langResponse);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch data:', error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 获取部署配置数据
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchDeployConfigs = async () => {
|
||||||
|
if (!currentEnvId) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const queryParams: DeploymentConfigQueryParams = {
|
||||||
|
pageSize: 100,
|
||||||
|
pageNum: 1,
|
||||||
|
environmentId: currentEnvId,
|
||||||
|
workflowDefinitionId: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await getDeploymentConfigPage(queryParams);
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
setDeployConfigs(response.content);
|
||||||
|
// 更新环境的项目数量
|
||||||
|
setEnvironments(prevEnvs =>
|
||||||
|
prevEnvs.map(env =>
|
||||||
|
env.id === currentEnvId
|
||||||
|
? { ...env, projectCount: response.totalElements }
|
||||||
|
: env
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to fetch deployment configs:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchDeployConfigs();
|
||||||
|
}, [currentEnvId]);
|
||||||
|
|
||||||
|
const handleSearch = async () => {
|
||||||
|
if (!currentEnvId) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const queryParams: DeploymentConfigQueryParams = {
|
||||||
|
pageSize: 100,
|
||||||
|
pageNum: 1,
|
||||||
|
environmentId: currentEnvId,
|
||||||
|
workflowDefinitionId: 0,
|
||||||
|
enabled: status === 'active' ? true : status === 'paused' ? false : undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await getDeploymentConfigPage(queryParams);
|
||||||
|
|
||||||
|
if (response) {
|
||||||
|
// 在前端过滤开发语言
|
||||||
|
const filteredConfigs = response.content.filter(config => {
|
||||||
|
if (projectType && config.languageType !== projectType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
setDeployConfigs(filteredConfigs);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to search deployment configs:', error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleReset = () => {
|
||||||
|
setSearchText("");
|
||||||
|
setProjectType("");
|
||||||
|
setStatus("");
|
||||||
|
if (currentEnvId) {
|
||||||
|
const queryParams: DeploymentConfigQueryParams = {
|
||||||
|
pageSize: 100,
|
||||||
|
pageNum: 1,
|
||||||
|
environmentId: currentEnvId,
|
||||||
|
workflowDefinitionId: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
getDeploymentConfigPage(queryParams).then(response => {
|
||||||
|
if (response) {
|
||||||
|
setDeployConfigs(response.content);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleTabChange = (envCode: string) => {
|
||||||
|
const env = environments.find(e => e.envCode === envCode);
|
||||||
|
if (env) {
|
||||||
|
setCurrentEnvId(env.id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getStatusIcon = (status: string) => {
|
const getStatusIcon = (status: string) => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -118,13 +223,11 @@ const Dashboard: React.FC = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getBuildStatusBadge = (status: string) => {
|
const getBuildStatusBadge = (enabled: boolean) => {
|
||||||
const statusConfig = {
|
const config = enabled
|
||||||
success: { className: "bg-green-100 text-green-800", text: "成功" },
|
? { className: "bg-green-100 text-green-800", text: "活跃" }
|
||||||
error: { className: "bg-red-100 text-red-800", text: "失败" },
|
: { className: "bg-red-100 text-red-800", text: "暂停" };
|
||||||
running: { className: "bg-blue-100 text-blue-800", text: "进行中" }
|
|
||||||
};
|
|
||||||
const config = statusConfig[status as keyof typeof statusConfig] || statusConfig.running;
|
|
||||||
return (
|
return (
|
||||||
<Badge className={cn("rounded-full", config.className)}>
|
<Badge className={cn("rounded-full", config.className)}>
|
||||||
{config.text}
|
{config.text}
|
||||||
@ -132,149 +235,194 @@ const Dashboard: React.FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <LoadingState />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasEnvironments = environments.length > 0;
|
||||||
|
const hasProjects = deployConfigs.length > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex-1 p-8">
|
<div className="flex-1 p-8">
|
||||||
<h2 className="text-2xl font-semibold mb-6">部署环境概览</h2>
|
<h2 className="text-2xl font-semibold mb-6">部署环境概览</h2>
|
||||||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
|
||||||
{environments.map((env) => (
|
{!hasEnvironments ? (
|
||||||
<Card key={env.id} className="hover:shadow-lg transition-shadow duration-300">
|
<Card>
|
||||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
<CardContent>
|
||||||
<CardTitle className="text-sm font-medium">{env.name}</CardTitle>
|
<EmptyState
|
||||||
{getStatusIcon(env.status)}
|
icon={<ServerCrash className="h-8 w-8 text-muted-foreground" />}
|
||||||
</CardHeader>
|
title="暂无环境数据"
|
||||||
<CardContent>
|
description="当前系统中还没有配置任何环境。请先添加部署环境,然后开始使用部署功能。"
|
||||||
<div className="text-2xl font-bold">{env.projectCount}</div>
|
/>
|
||||||
<p className="text-xs text-muted-foreground">个项目</p>
|
</CardContent>
|
||||||
<div className="mt-4 space-y-2">
|
</Card>
|
||||||
<div className="flex items-center text-sm">
|
) : (
|
||||||
<Clock className="mr-2 h-4 w-4 text-muted-foreground" />
|
<>
|
||||||
最近部署: {env.lastDeployment}
|
<div className="grid grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||||
</div>
|
{environments.map((env) => (
|
||||||
<div className="space-y-1">
|
<Card key={env.id} className="hover:shadow-lg transition-shadow duration-300">
|
||||||
<div className="flex justify-between text-xs">
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||||
<span>CPU</span>
|
<CardTitle className="text-sm font-medium">{env.envName}</CardTitle>
|
||||||
<span>{env.cpu}%</span>
|
{getStatusIcon(env.status)}
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="text-2xl font-bold">{env.projectCount}</div>
|
||||||
|
<p className="text-xs text-muted-foreground">个项目</p>
|
||||||
|
<div className="mt-4 space-y-2">
|
||||||
|
<div className="flex items-center text-sm">
|
||||||
|
<Clock className="mr-2 h-4 w-4 text-muted-foreground" />
|
||||||
|
最近部署: {env.lastDeployment}
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<div className="flex justify-between text-xs">
|
||||||
|
<span>CPU</span>
|
||||||
|
<span>{env.cpu}%</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={env.cpu} className="h-1" />
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<div className="flex justify-between text-xs">
|
||||||
|
<span>内存</span>
|
||||||
|
<span>{env.memory}%</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={env.memory} className="h-1" />
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<div className="flex justify-between text-xs">
|
||||||
|
<span>存储</span>
|
||||||
|
<span>{env.storage}%</span>
|
||||||
|
</div>
|
||||||
|
<Progress value={env.storage} className="h-1" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Progress value={env.cpu} className="h-1" />
|
</CardContent>
|
||||||
</div>
|
</Card>
|
||||||
<div className="space-y-1">
|
))}
|
||||||
<div className="flex justify-between text-xs">
|
|
||||||
<span>内存</span>
|
|
||||||
<span>{env.memory}%</span>
|
|
||||||
</div>
|
|
||||||
<Progress value={env.memory} className="h-1" />
|
|
||||||
</div>
|
|
||||||
<div className="space-y-1">
|
|
||||||
<div className="flex justify-between text-xs">
|
|
||||||
<span>存储</span>
|
|
||||||
<span>{env.storage}%</span>
|
|
||||||
</div>
|
|
||||||
<Progress value={env.storage} className="h-1" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</CardContent>
|
|
||||||
</Card>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="bg-white rounded-lg shadow">
|
|
||||||
<Tabs defaultValue={environments[0].id} className="w-full">
|
|
||||||
<div className="border-b px-6">
|
|
||||||
<TabsList className="h-16">
|
|
||||||
{environments.map((env) => (
|
|
||||||
<TabsTrigger
|
|
||||||
key={env.id}
|
|
||||||
value={env.id}
|
|
||||||
className="px-6 py-3 data-[state=active]:border-b-2 data-[state=active]:border-blue-600"
|
|
||||||
>
|
|
||||||
{env.name}
|
|
||||||
</TabsTrigger>
|
|
||||||
))}
|
|
||||||
</TabsList>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{environments.map((env) => (
|
<div className="bg-white rounded-lg shadow">
|
||||||
<TabsContent key={env.id} value={env.id} className="p-6">
|
<Tabs
|
||||||
<div className="mb-6">
|
defaultValue={environments[0]?.envCode}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
className="w-full"
|
||||||
<Input placeholder="项目名称或代码" />
|
onValueChange={handleTabChange}
|
||||||
<Select value={projectType} onValueChange={setProjectType}>
|
>
|
||||||
<SelectTrigger>
|
<div className="border-b px-6">
|
||||||
<SelectValue placeholder="项目类型" />
|
<TabsList className="h-16">
|
||||||
</SelectTrigger>
|
{environments.map((env) => (
|
||||||
<SelectContent>
|
<TabsTrigger
|
||||||
<SelectItem value="frontend">前端应用</SelectItem>
|
key={env.id}
|
||||||
<SelectItem value="backend">后端服务</SelectItem>
|
value={env.envCode}
|
||||||
<SelectItem value="microservice">微服务</SelectItem>
|
className="px-6 py-3 data-[state=active]:border-b-2 data-[state=active]:border-blue-600"
|
||||||
</SelectContent>
|
>
|
||||||
</Select>
|
{env.envName}
|
||||||
<Select value={status} onValueChange={setStatus}>
|
</TabsTrigger>
|
||||||
<SelectTrigger>
|
))}
|
||||||
<SelectValue placeholder="项目状态" />
|
</TabsList>
|
||||||
</SelectTrigger>
|
|
||||||
<SelectContent>
|
|
||||||
<SelectItem value="active">活跃</SelectItem>
|
|
||||||
<SelectItem value="archived">归档</SelectItem>
|
|
||||||
<SelectItem value="paused">暂停</SelectItem>
|
|
||||||
</SelectContent>
|
|
||||||
</Select>
|
|
||||||
<div className="flex space-x-2">
|
|
||||||
<Button className="flex-1">
|
|
||||||
<Search className="w-4 h-4 mr-2" />
|
|
||||||
搜索
|
|
||||||
</Button>
|
|
||||||
<Button variant="outline" className="flex-1">重置</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
{environments.map((env) => (
|
||||||
{projects.map((project) => (
|
<TabsContent key={env.id} value={env.envCode} className="p-6">
|
||||||
<Card key={project.id} className="hover:shadow-md transition-shadow duration-300">
|
<div className="mb-6">
|
||||||
<CardContent className="p-4">
|
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||||
<div className="flex justify-between items-start mb-2">
|
<Input
|
||||||
<div>
|
placeholder="项目名称或代码"
|
||||||
<h3 className="text-lg font-semibold">{project.name}</h3>
|
value={searchText}
|
||||||
<p className="text-sm text-gray-500">{project.code}</p>
|
onChange={(e) => setSearchText(e.target.value)}
|
||||||
</div>
|
/>
|
||||||
{getBuildStatusBadge(project.buildStatus)}
|
<Select value={projectType} onValueChange={setProjectType}>
|
||||||
</div>
|
<SelectTrigger>
|
||||||
<div className="grid grid-cols-2 gap-2 text-sm mb-4">
|
<SelectValue placeholder="开发语言" />
|
||||||
<div>
|
</SelectTrigger>
|
||||||
<p className="text-gray-500">类型</p>
|
<SelectContent>
|
||||||
<p className="font-medium">{project.type}</p>
|
{languages.map(lang => (
|
||||||
</div>
|
<SelectItem key={lang.code} value={lang.code}>
|
||||||
<div>
|
{lang.name}
|
||||||
<p className="text-gray-500">版本</p>
|
</SelectItem>
|
||||||
<p className="font-medium">{project.version}</p>
|
))}
|
||||||
</div>
|
</SelectContent>
|
||||||
<div>
|
</Select>
|
||||||
<p className="text-gray-500">状态</p>
|
<Select value={status} onValueChange={setStatus}>
|
||||||
<p className="font-medium">{project.status}</p>
|
<SelectTrigger>
|
||||||
</div>
|
<SelectValue placeholder="项目状态" />
|
||||||
<div>
|
</SelectTrigger>
|
||||||
<p className="text-gray-500">最近部署</p>
|
<SelectContent>
|
||||||
<p className="font-medium">{project.lastDeployment}</p>
|
<SelectItem value="active">活跃</SelectItem>
|
||||||
</div>
|
<SelectItem value="paused">暂停</SelectItem>
|
||||||
</div>
|
</SelectContent>
|
||||||
<div className="flex justify-end space-x-2">
|
</Select>
|
||||||
<Button variant="outline" size="sm">
|
<div className="flex space-x-2">
|
||||||
<Edit className="h-4 w-4 mr-1" />
|
<Button className="flex-1" onClick={handleSearch}>
|
||||||
编辑
|
<Search className="w-4 h-4 mr-2" />
|
||||||
|
搜索
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="outline" size="sm">
|
<Button variant="outline" className="flex-1" onClick={handleReset}>
|
||||||
<ChevronRight className="h-4 w-4" />
|
重置
|
||||||
详情
|
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</div>
|
||||||
</Card>
|
</div>
|
||||||
))}
|
|
||||||
</div>
|
{!hasProjects ? (
|
||||||
</TabsContent>
|
<Card>
|
||||||
))}
|
<CardContent>
|
||||||
</Tabs>
|
<EmptyState
|
||||||
</div>
|
icon={<Server className="h-8 w-8 text-muted-foreground" />}
|
||||||
|
title="暂无项目数据"
|
||||||
|
description="当前环境中还没有配置任何项目。请先创建项目,然后开始部署。"
|
||||||
|
/>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
) : (
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{deployConfigs.map((config) => (
|
||||||
|
<Card key={config.id} className="hover:shadow-md transition-shadow duration-300">
|
||||||
|
<CardContent className="p-4">
|
||||||
|
<div className="flex justify-between items-start mb-2">
|
||||||
|
<div>
|
||||||
|
<h3 className="text-lg font-semibold">{config.application.appName}</h3>
|
||||||
|
<p className="text-sm text-gray-500">{config.application.appCode}</p>
|
||||||
|
</div>
|
||||||
|
{getBuildStatusBadge(config.enabled)}
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 gap-2 text-sm mb-4">
|
||||||
|
<div>
|
||||||
|
<p className="text-gray-500">构建类型</p>
|
||||||
|
<p className="font-medium">{config.buildType}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-gray-500">开发语言</p>
|
||||||
|
<p className="font-medium">{config.languageType}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-gray-500">工作流</p>
|
||||||
|
<p className="font-medium">{config.publishedWorkflowDefinition?.name || '未配置'}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-gray-500">最近更新</p>
|
||||||
|
<p className="font-medium">{new Date(config.updateTime).toLocaleString()}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-end space-x-2">
|
||||||
|
<Button variant="outline" size="sm">
|
||||||
|
<Edit className="h-4 w-4 mr-1" />
|
||||||
|
编辑
|
||||||
|
</Button>
|
||||||
|
<Button variant="outline" size="sm">
|
||||||
|
<ChevronRight className="h-4 w-4" />
|
||||||
|
详情
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</TabsContent>
|
||||||
|
))}
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type { CreateApplicationRequest, UpdateApplicationRequest, Application, ApplicationQuery } from './types';
|
import type { CreateApplicationRequest, UpdateApplicationRequest, Application, ApplicationQuery } from './types';
|
||||||
import type { Page } from '@/types/base';
|
import type { Page } from '@/types/base';
|
||||||
|
import {DevelopmentLanguageType} from "./types";
|
||||||
|
|
||||||
const BASE_URL = '/api/v1/applications';
|
const BASE_URL = '/api/v1/applications';
|
||||||
|
|
||||||
@ -31,3 +32,6 @@ export const getApplicationList = () =>
|
|||||||
// 条件查询应用列表
|
// 条件查询应用列表
|
||||||
export const getApplicationListByCondition = (params?: ApplicationQuery) =>
|
export const getApplicationListByCondition = (params?: ApplicationQuery) =>
|
||||||
request.get<Application[]>(`${BASE_URL}/list`, { params });
|
request.get<Application[]>(`${BASE_URL}/list`, { params });
|
||||||
|
|
||||||
|
export const getDevelopmentLanguages = () =>
|
||||||
|
request.get<DevelopmentLanguageType[]>(`${BASE_URL}/development-languages`);
|
||||||
|
|||||||
@ -40,4 +40,10 @@ export interface ApplicationQuery extends BaseQuery {
|
|||||||
appCode?: string;
|
appCode?: string;
|
||||||
appName?: string;
|
appName?: string;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
|
language?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DevelopmentLanguageType {
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user