1
This commit is contained in:
parent
e8cd2575eb
commit
656413d3f7
@ -1,7 +1,8 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { Modal, Form, Input, InputNumber, Radio, message } from 'antd';
|
import { Modal, Form, Input, InputNumber, Radio, message, Select } from 'antd';
|
||||||
import type { Application } from '../types';
|
import type { Application } from '../types';
|
||||||
import { createApplication, updateApplication } from '../service';
|
import { createApplication, updateApplication } from '../service';
|
||||||
|
import { DevelopmentLanguageTypeEnum } from '../types';
|
||||||
|
|
||||||
interface ApplicationModalProps {
|
interface ApplicationModalProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@ -24,12 +25,15 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
if (initialValues) {
|
if (initialValues) {
|
||||||
form.setFieldsValue(initialValues);
|
form.setFieldsValue({
|
||||||
|
...initialValues,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
appStatus: 'ENABLE',
|
projectGroupId,
|
||||||
|
enabled: true,
|
||||||
sort: 0,
|
sort: 0,
|
||||||
projectGroupId: projectGroupId // 设置项目组ID的初始值
|
language: DevelopmentLanguageTypeEnum.JAVA,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,7 +44,7 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
const submitData = {
|
const submitData = {
|
||||||
...values,
|
...values,
|
||||||
projectGroupId: projectGroupId // 确保提交时包含项目组ID
|
projectGroupId,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
@ -70,13 +74,18 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
|
width={600}
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
initialValues={{ appStatus: 'ENABLE', sort: 0 }}
|
initialValues={{
|
||||||
|
enabled: true,
|
||||||
|
sort: 0,
|
||||||
|
language: DevelopmentLanguageTypeEnum.JAVA,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{/* 添加一个隐藏的表单项来存储项目组ID */}
|
{/* 隐藏的项目组ID字段 */}
|
||||||
<Form.Item name="projectGroupId" hidden>
|
<Form.Item name="projectGroupId" hidden>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@ -108,13 +117,37 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="appStatus"
|
name="repoUrl"
|
||||||
|
label="仓库地址"
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: '请输入仓库地址' },
|
||||||
|
{ type: 'url', message: '请输入有效的URL地址' },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input placeholder="请输入仓库地址" />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="language"
|
||||||
|
label="开发语言"
|
||||||
|
rules={[{ required: true, message: '请选择开发语言' }]}
|
||||||
|
>
|
||||||
|
<Select placeholder="请选择开发语言">
|
||||||
|
<Select.Option value={DevelopmentLanguageTypeEnum.JAVA}>Java</Select.Option>
|
||||||
|
<Select.Option value={DevelopmentLanguageTypeEnum.NODE_JS}>NodeJS</Select.Option>
|
||||||
|
<Select.Option value={DevelopmentLanguageTypeEnum.PYTHON}>Python</Select.Option>
|
||||||
|
<Select.Option value={DevelopmentLanguageTypeEnum.GO}>Go</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="enabled"
|
||||||
label="应用状态"
|
label="应用状态"
|
||||||
rules={[{ required: true, message: '请选择应用状态' }]}
|
rules={[{ required: true, message: '请选择应用状态' }]}
|
||||||
>
|
>
|
||||||
<Radio.Group>
|
<Radio.Group>
|
||||||
<Radio value="ENABLE">启用</Radio>
|
<Radio value={true}>启用</Radio>
|
||||||
<Radio value="DISABLE">禁用</Radio>
|
<Radio value={false}>禁用</Radio>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,25 @@
|
|||||||
import React, {useState, useEffect} from 'react';
|
import React, {useState, useEffect} from 'react';
|
||||||
import {PageContainer} from '@ant-design/pro-layout';
|
import {PageContainer} from '@ant-design/pro-layout';
|
||||||
import {Button, message, Popconfirm, Tag, Space, Tooltip, Select} from 'antd';
|
import {Button, message, Popconfirm, Tag, Space, Tooltip, Select} from 'antd';
|
||||||
import {PlusOutlined, EditOutlined, DeleteOutlined, CodeOutlined, CloudUploadOutlined, ApiOutlined} from '@ant-design/icons';
|
import {
|
||||||
|
PlusOutlined,
|
||||||
|
EditOutlined,
|
||||||
|
DeleteOutlined,
|
||||||
|
CodeOutlined,
|
||||||
|
CloudUploadOutlined,
|
||||||
|
ApiOutlined,
|
||||||
|
GithubOutlined,
|
||||||
|
JavaOutlined,
|
||||||
|
NodeIndexOutlined,
|
||||||
|
PythonOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
import {getApplicationPage, deleteApplication} from './service';
|
import {getApplicationPage, deleteApplication} from './service';
|
||||||
import {getProjectGroupList} from '../../ProjectGroup/List/service';
|
import {getProjectGroupList} from '../../ProjectGroup/List/service';
|
||||||
import type {Application, ApplicationQuery} from './types';
|
import type {Application, ApplicationQuery} from './types';
|
||||||
|
import {DevelopmentLanguageTypeEnum} from './types';
|
||||||
import type {ProjectGroup} from '../../ProjectGroup/List/types';
|
import type {ProjectGroup} from '../../ProjectGroup/List/types';
|
||||||
|
import {ProjectGroupTypeEnum} from '../../ProjectGroup/List/types';
|
||||||
|
import {getProjectTypeInfo} from '../../ProjectGroup/List/utils';
|
||||||
import ApplicationModal from './components/ApplicationModal';
|
import ApplicationModal from './components/ApplicationModal';
|
||||||
import {ProTable} from '@ant-design/pro-components';
|
import {ProTable} from '@ant-design/pro-components';
|
||||||
import type {ProColumns, ActionType} from '@ant-design/pro-components';
|
import type {ProColumns, ActionType} from '@ant-design/pro-components';
|
||||||
@ -65,11 +79,40 @@ const ApplicationList: React.FC = () => {
|
|||||||
actionRef.current?.reload();
|
actionRef.current?.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 根据应用编码推测应用类型
|
// 获取开发语言信息
|
||||||
const getAppType = (appCode: string) => {
|
const getLanguageInfo = (language: DevelopmentLanguageTypeEnum) => {
|
||||||
if (appCode.toLowerCase().includes('web')) return {icon: <CodeOutlined/>, name: '前端应用', color: '#1890ff'};
|
switch (language) {
|
||||||
if (appCode.toLowerCase().includes('api')) return {icon: <ApiOutlined/>, name: 'API服务', color: '#52c41a'};
|
case DevelopmentLanguageTypeEnum.JAVA:
|
||||||
return {icon: <CloudUploadOutlined/>, name: '后端服务', color: '#722ed1'};
|
return {
|
||||||
|
label: 'Java',
|
||||||
|
icon: <JavaOutlined/>,
|
||||||
|
color: '#E76F00'
|
||||||
|
};
|
||||||
|
case DevelopmentLanguageTypeEnum.NODE_JS:
|
||||||
|
return {
|
||||||
|
label: 'NodeJS',
|
||||||
|
icon: <NodeIndexOutlined/>,
|
||||||
|
color: '#339933'
|
||||||
|
};
|
||||||
|
case DevelopmentLanguageTypeEnum.PYTHON:
|
||||||
|
return {
|
||||||
|
label: 'Python',
|
||||||
|
icon: <PythonOutlined/>,
|
||||||
|
color: '#3776AB'
|
||||||
|
};
|
||||||
|
case DevelopmentLanguageTypeEnum.GO:
|
||||||
|
return {
|
||||||
|
label: 'Go',
|
||||||
|
icon: <CodeOutlined/>,
|
||||||
|
color: '#00ADD8'
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
label: language || '未知',
|
||||||
|
icon: <CodeOutlined/>,
|
||||||
|
color: '#666666'
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns: ProColumns<Application>[] = [
|
const columns: ProColumns<Application>[] = [
|
||||||
@ -80,17 +123,6 @@ const ApplicationList: React.FC = () => {
|
|||||||
copyable: true,
|
copyable: true,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
fixed: 'left',
|
fixed: 'left',
|
||||||
render: (text, record) => {
|
|
||||||
const appType = getAppType(record.appCode);
|
|
||||||
return (
|
|
||||||
<Space>
|
|
||||||
<Tooltip title={appType.name}>
|
|
||||||
{appType.icon}
|
|
||||||
</Tooltip>
|
|
||||||
{text}
|
|
||||||
</Space>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '应用名称',
|
title: '应用名称',
|
||||||
@ -98,6 +130,22 @@ const ApplicationList: React.FC = () => {
|
|||||||
width: 150,
|
width: 150,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '项目组',
|
||||||
|
dataIndex: ['projectGroup', 'projectGroupName'],
|
||||||
|
width: 150,
|
||||||
|
ellipsis: true,
|
||||||
|
render: (_, record) => (
|
||||||
|
<Space>
|
||||||
|
{record.projectGroup?.projectGroupName}
|
||||||
|
{record.projectGroup?.type && (
|
||||||
|
<Tag color={getProjectTypeInfo(record.projectGroup.type).color}>
|
||||||
|
{getProjectTypeInfo(record.projectGroup.type).label}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '应用描述',
|
title: '应用描述',
|
||||||
dataIndex: 'appDesc',
|
dataIndex: 'appDesc',
|
||||||
@ -105,12 +153,50 @@ const ApplicationList: React.FC = () => {
|
|||||||
width: 200,
|
width: 200,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '应用状态',
|
title: '仓库地址',
|
||||||
dataIndex: 'appStatus',
|
dataIndex: 'repoUrl',
|
||||||
|
width: 200,
|
||||||
|
ellipsis: true,
|
||||||
|
render: (_, record) => record.repoUrl ? (
|
||||||
|
<Space>
|
||||||
|
<GithubOutlined/>
|
||||||
|
<a href={record.repoUrl} target="_blank" rel="noopener noreferrer">
|
||||||
|
{record.repoUrl}
|
||||||
|
</a>
|
||||||
|
</Space>
|
||||||
|
) : '-',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '开发语言',
|
||||||
|
dataIndex: 'language',
|
||||||
|
width: 120,
|
||||||
|
render: (language) => {
|
||||||
|
const langInfo = getLanguageInfo(language as DevelopmentLanguageTypeEnum);
|
||||||
|
return (
|
||||||
|
<Tag color={langInfo.color}>
|
||||||
|
<Space>
|
||||||
|
{langInfo.icon}
|
||||||
|
{langInfo.label}
|
||||||
|
</Space>
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
filters: [
|
||||||
|
{text: 'Java', value: DevelopmentLanguageTypeEnum.JAVA},
|
||||||
|
{text: 'NodeJS', value: DevelopmentLanguageTypeEnum.NODE_JS},
|
||||||
|
{text: 'Python', value: DevelopmentLanguageTypeEnum.PYTHON},
|
||||||
|
{text: 'Go', value: DevelopmentLanguageTypeEnum.GO},
|
||||||
|
],
|
||||||
|
filterMode: 'menu',
|
||||||
|
filtered: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'enabled',
|
||||||
width: 100,
|
width: 100,
|
||||||
valueEnum: {
|
valueEnum: {
|
||||||
'ENABLE': {text: '启用', status: 'Success'},
|
true: {text: '启用', status: 'Success'},
|
||||||
'DISABLE': {text: '禁用', status: 'Default'},
|
false: {text: '禁用', status: 'Default'},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -121,7 +207,7 @@ const ApplicationList: React.FC = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
width: 200,
|
width: 150,
|
||||||
key: 'action',
|
key: 'action',
|
||||||
valueType: 'option',
|
valueType: 'option',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
@ -149,19 +235,37 @@ const ApplicationList: React.FC = () => {
|
|||||||
删除
|
删除
|
||||||
</Button>
|
</Button>
|
||||||
</Popconfirm>,
|
</Popconfirm>,
|
||||||
<Button
|
|
||||||
key="deploy"
|
|
||||||
type="link"
|
|
||||||
icon={<CloudUploadOutlined/>}
|
|
||||||
>
|
|
||||||
部署测试
|
|
||||||
</Button>
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<PageContainer
|
||||||
|
header={{
|
||||||
|
title: '应用管理',
|
||||||
|
subTitle: (
|
||||||
|
<Space>
|
||||||
|
<span>当前项目组:</span>
|
||||||
|
<Select
|
||||||
|
value={selectedProjectGroupId}
|
||||||
|
onChange={handleProjectChange}
|
||||||
|
style={{width: 200}}
|
||||||
|
options={projectGroups.map(project => ({
|
||||||
|
label: (
|
||||||
|
<Space>
|
||||||
|
{project.projectGroupName}
|
||||||
|
<Tag color={getProjectTypeInfo(project.type).color}>
|
||||||
|
{getProjectTypeInfo(project.type).label}
|
||||||
|
</Tag>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
value: project.id,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
),
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ProTable<Application>
|
<ProTable<Application>
|
||||||
columns={columns}
|
columns={columns}
|
||||||
actionRef={actionRef}
|
actionRef={actionRef}
|
||||||
@ -178,10 +282,9 @@ const ApplicationList: React.FC = () => {
|
|||||||
const queryParams: ApplicationQuery = {
|
const queryParams: ApplicationQuery = {
|
||||||
pageSize: params.pageSize,
|
pageSize: params.pageSize,
|
||||||
pageNum: params.current,
|
pageNum: params.current,
|
||||||
projectGroupId: selectedProjectGroupId,
|
|
||||||
appCode: params.appCode as string,
|
appCode: params.appCode as string,
|
||||||
appName: params.appName as string,
|
appName: params.appName as string,
|
||||||
appStatus: params.appStatus as string,
|
enabled: params.enabled as boolean,
|
||||||
};
|
};
|
||||||
const data = await getApplicationPage(queryParams);
|
const data = await getApplicationPage(queryParams);
|
||||||
return {
|
return {
|
||||||
@ -240,7 +343,7 @@ const ApplicationList: React.FC = () => {
|
|||||||
projectGroupId={selectedProjectGroupId}
|
projectGroupId={selectedProjectGroupId}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,31 +1,43 @@
|
|||||||
import type { BaseQuery } from '@/types/base';
|
import type {BaseQuery} from '@/types/base';
|
||||||
|
import {ProjectGroup} from "@/pages/Deploy/ProjectGroup/List/types";
|
||||||
|
|
||||||
|
export enum DevelopmentLanguageTypeEnum {
|
||||||
|
JAVA = 'JAVA',
|
||||||
|
NODE_JS = 'NODE_JS',
|
||||||
|
PYTHON = 'PYTHON',
|
||||||
|
GO = 'GO'
|
||||||
|
}
|
||||||
|
|
||||||
export interface Application {
|
export interface Application {
|
||||||
id: number;
|
id: number;
|
||||||
projectGroupId: number;
|
appCode: string;
|
||||||
appCode: string;
|
appName: string;
|
||||||
appName: string;
|
appDesc?: string;
|
||||||
appDesc?: string;
|
repoUrl: string;
|
||||||
appStatus: 'ENABLE' | 'DISABLE';
|
language: DevelopmentLanguageTypeEnum;
|
||||||
sort: number;
|
enabled: boolean;
|
||||||
|
sort: number;
|
||||||
|
projectGroup: ProjectGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateApplicationRequest {
|
export interface CreateApplicationRequest {
|
||||||
projectGroupId: number;
|
projectGroupId: number;
|
||||||
appCode: string;
|
appCode: string;
|
||||||
appName: string;
|
appName: string;
|
||||||
appDesc?: string;
|
appDesc?: string;
|
||||||
appStatus: string;
|
repoUrl: string;
|
||||||
sort: number;
|
language: DevelopmentLanguageTypeEnum;
|
||||||
|
enabled: boolean;
|
||||||
|
sort: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateApplicationRequest extends CreateApplicationRequest {
|
export interface UpdateApplicationRequest extends CreateApplicationRequest {
|
||||||
id: number;
|
id: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApplicationQuery extends BaseQuery {
|
export interface ApplicationQuery extends BaseQuery {
|
||||||
projectGroupId?: number;
|
projectGroupId?: number;
|
||||||
appCode?: string;
|
appCode?: string;
|
||||||
appName?: string;
|
appName?: string;
|
||||||
appStatus?: string;
|
enabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,8 @@
|
|||||||
import React, {useEffect, useState} from 'react';
|
import React, {useEffect} from 'react';
|
||||||
import {Modal, Form, Input, InputNumber, Radio, message, Select} from 'antd';
|
import {Modal, Form, Input, InputNumber, Radio, message} from 'antd';
|
||||||
import type {ProjectGroup} from '../types';
|
import type {ProjectGroup} from '../types';
|
||||||
import type {Environment} from '../../../Environment/List/types';
|
|
||||||
import {createProjectGroup, updateProjectGroup} from '../service';
|
import {createProjectGroup, updateProjectGroup} from '../service';
|
||||||
import {getEnvironmentList} from '../../../Environment/List/service';
|
import {ProjectGroupTypeEnum} from '../types';
|
||||||
import {BuildTypeEnum} from "../../../Environment/List/types";
|
|
||||||
import {ProjectGroupTypeEnum} from "../types";
|
|
||||||
|
|
||||||
interface ProjectGroupModalProps {
|
interface ProjectGroupModalProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
@ -14,57 +11,44 @@ interface ProjectGroupModalProps {
|
|||||||
initialValues?: ProjectGroup;
|
initialValues?: ProjectGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildProjectGroupTypes = [
|
|
||||||
{label: '产品', value: ProjectGroupTypeEnum.PRODUCT},
|
|
||||||
{label: '项目', value: ProjectGroupTypeEnum.PROJECT}
|
|
||||||
];
|
|
||||||
|
|
||||||
const ProjectGroupModal: React.FC<ProjectGroupModalProps> = ({
|
const ProjectGroupModal: React.FC<ProjectGroupModalProps> = ({
|
||||||
visible,
|
visible,
|
||||||
onCancel,
|
onCancel,
|
||||||
onSuccess,
|
onSuccess,
|
||||||
initialValues,
|
initialValues,
|
||||||
}) => {
|
}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [environments, setEnvironments] = useState<Environment[]>([]);
|
|
||||||
const isEdit = !!initialValues;
|
const isEdit = !!initialValues;
|
||||||
|
|
||||||
// 获取环境列表
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchEnvironments = async () => {
|
if (visible) {
|
||||||
try {
|
if (initialValues) {
|
||||||
const data = await getEnvironmentList();
|
// 将布尔值转换为字符串
|
||||||
setEnvironments(data);
|
form.setFieldsValue({
|
||||||
} catch (error) {
|
...initialValues,
|
||||||
message.error('获取环境列表失败');
|
enabled: initialValues.enabled?.toString()
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
form.setFieldsValue({
|
||||||
|
type: ProjectGroupTypeEnum.PROJECT,
|
||||||
|
enabled: 'true',
|
||||||
|
sort: 0
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
fetchEnvironments();
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (visible && initialValues) {
|
|
||||||
// 设置初始值,包括环境ID列表
|
|
||||||
const envIds = initialValues.environments?.map(env => env.id) || [];
|
|
||||||
form.setFieldsValue({
|
|
||||||
...initialValues,
|
|
||||||
environments: envIds
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}, [visible, initialValues, form]);
|
}, [visible, initialValues, form]);
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
// 转换环境ID数组为对象数组
|
// 将字符串转换回布尔值
|
||||||
const environments = (values.environments || []).map((id: number) => ({id}));
|
|
||||||
const submitData = {
|
const submitData = {
|
||||||
...values,
|
...values,
|
||||||
environments
|
enabled: values.enabled === 'true'
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
await updateProjectGroup({...submitData, id: initialValues.id});
|
await updateProjectGroup({...submitData, id: initialValues?.id});
|
||||||
message.success('更新成功');
|
message.success('更新成功');
|
||||||
} else {
|
} else {
|
||||||
await createProjectGroup(submitData);
|
await createProjectGroup(submitData);
|
||||||
@ -90,24 +74,16 @@ const ProjectGroupModal: React.FC<ProjectGroupModalProps> = ({
|
|||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
width={560}
|
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
initialValues={{projectGroupStatus: 'ENABLE', sort: 0}}
|
initialValues={{
|
||||||
|
type: ProjectGroupTypeEnum.PROJECT,
|
||||||
|
enabled: 'true',
|
||||||
|
sort: 0
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Form.Item
|
|
||||||
name="type"
|
|
||||||
label="项目组类型"
|
|
||||||
rules={[{required: true, message: '请选择项目组类型'}]}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
placeholder="请选择项目组类型"
|
|
||||||
options={buildProjectGroupTypes}
|
|
||||||
style={{width: '100%'}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="projectGroupCode"
|
name="projectGroupCode"
|
||||||
label="项目组编码"
|
label="项目组编码"
|
||||||
@ -133,32 +109,29 @@ const ProjectGroupModal: React.FC<ProjectGroupModalProps> = ({
|
|||||||
>
|
>
|
||||||
<Input.TextArea rows={4} placeholder="请输入项目组描述"/>
|
<Input.TextArea rows={4} placeholder="请输入项目组描述"/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="environments"
|
name="type"
|
||||||
label="关联环境"
|
label="项目组类型"
|
||||||
rules={[{required: true, message: '请选择关联环境'}]}
|
rules={[{required: true, message: '请选择项目组类型'}]}
|
||||||
>
|
|
||||||
<Select
|
|
||||||
mode="multiple"
|
|
||||||
placeholder="请选择关联环境"
|
|
||||||
optionFilterProp="label"
|
|
||||||
options={environments.map(env => ({
|
|
||||||
label: env.envName,
|
|
||||||
value: env.id,
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
name="projectGroupStatus"
|
|
||||||
label="项目组状态"
|
|
||||||
rules={[{required: true, message: '请选择项目组状态'}]}
|
|
||||||
initialValue="ENABLE"
|
|
||||||
>
|
>
|
||||||
<Radio.Group>
|
<Radio.Group>
|
||||||
<Radio value="ENABLE">启用</Radio>
|
<Radio value={ProjectGroupTypeEnum.PRODUCT}>产品型</Radio>
|
||||||
<Radio value="DISABLE">禁用</Radio>
|
<Radio value={ProjectGroupTypeEnum.PROJECT}>项目型</Radio>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="enabled"
|
||||||
|
label="项目组状态"
|
||||||
|
rules={[{required: true, message: '请选择项目组状态'}]}
|
||||||
|
>
|
||||||
|
<Radio.Group>
|
||||||
|
<Radio value="true">启用</Radio>
|
||||||
|
<Radio value="false">禁用</Radio>
|
||||||
|
</Radio.Group>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="sort"
|
name="sort"
|
||||||
label="排序"
|
label="排序"
|
||||||
|
|||||||
@ -7,14 +7,14 @@ import {
|
|||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
TeamOutlined,
|
TeamOutlined,
|
||||||
EnvironmentOutlined,
|
EnvironmentOutlined,
|
||||||
RocketOutlined
|
|
||||||
} from '@ant-design/icons';
|
} from '@ant-design/icons';
|
||||||
import {getProjectGroupPage, deleteProjectGroup} from './service';
|
import {getProjectGroupPage, deleteProjectGroup} from './service';
|
||||||
import type {ProjectGroup, ProjectGroupQueryParams} from './types';
|
import type {ProjectGroup, ProjectGroupQueryParams} from './types';
|
||||||
|
import {ProjectGroupTypeEnum} from './types';
|
||||||
|
import {getProjectTypeInfo} from './utils';
|
||||||
import ProjectGroupModal from './components/ProjectGroupModal';
|
import ProjectGroupModal from './components/ProjectGroupModal';
|
||||||
import { ProjectGroupTypeEnum } from './types';
|
import {ProTable} from '@ant-design/pro-components';
|
||||||
import { ProTable } from '@ant-design/pro-components';
|
import type {ProColumns, ActionType} from '@ant-design/pro-components';
|
||||||
import type { ProColumns, ActionType } from '@ant-design/pro-components';
|
|
||||||
|
|
||||||
const ProjectGroupList: React.FC = () => {
|
const ProjectGroupList: React.FC = () => {
|
||||||
const [modalVisible, setModalVisible] = useState(false);
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
@ -41,35 +41,6 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
setModalVisible(true);
|
setModalVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getProjectTypeInfo = (type: ProjectGroupTypeEnum) => {
|
|
||||||
switch (type) {
|
|
||||||
case ProjectGroupTypeEnum.PRODUCT:
|
|
||||||
return {
|
|
||||||
type: ProjectGroupTypeEnum.PRODUCT,
|
|
||||||
label: '产品型',
|
|
||||||
color: '#1890ff',
|
|
||||||
icon: <RocketOutlined/>,
|
|
||||||
description: '产品型相关的项目组'
|
|
||||||
};
|
|
||||||
case ProjectGroupTypeEnum.PROJECT:
|
|
||||||
return {
|
|
||||||
type: ProjectGroupTypeEnum.PROJECT,
|
|
||||||
label: '项目型',
|
|
||||||
color: '#52c41a',
|
|
||||||
icon: <EnvironmentOutlined/>,
|
|
||||||
description: '项目型相关的项目组'
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
type: ProjectGroupTypeEnum.PROJECT,
|
|
||||||
label: '项目型',
|
|
||||||
color: '#722ed1',
|
|
||||||
icon: <TeamOutlined/>,
|
|
||||||
description: '项目型相关的项目组'
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const columns: ProColumns<ProjectGroup>[] = [
|
const columns: ProColumns<ProjectGroup>[] = [
|
||||||
{
|
{
|
||||||
title: '项目组编码',
|
title: '项目组编码',
|
||||||
@ -93,18 +64,32 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
{
|
{
|
||||||
title: '项目组类型',
|
title: '项目组类型',
|
||||||
dataIndex: 'type',
|
dataIndex: 'type',
|
||||||
width: 100,
|
width: 150,
|
||||||
render: (type) => {
|
render: (type) => {
|
||||||
const typeInfo = getProjectTypeInfo(type as ProjectGroupTypeEnum);
|
const typeInfo = getProjectTypeInfo(type as ProjectGroupTypeEnum);
|
||||||
return (
|
return (
|
||||||
<Tag color={typeInfo.color}>
|
<Tag color={typeInfo.color}>
|
||||||
{typeInfo.label}
|
<Space>
|
||||||
|
{typeInfo.icon}
|
||||||
|
{typeInfo.label}
|
||||||
|
</Space>
|
||||||
</Tag>
|
</Tag>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
filters: [
|
||||||
|
{text: '产品型', value: ProjectGroupTypeEnum.PRODUCT},
|
||||||
|
{text: '项目型', value: ProjectGroupTypeEnum.PROJECT},
|
||||||
|
],
|
||||||
|
filterMode: 'menu',
|
||||||
|
filtered: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'enabled',
|
||||||
|
width: 100,
|
||||||
valueEnum: {
|
valueEnum: {
|
||||||
[ProjectGroupTypeEnum.PRODUCT]: { text: '产品型' },
|
true: {text: '启用', status: 'Success'},
|
||||||
[ProjectGroupTypeEnum.PROJECT]: { text: '项目型' },
|
false: {text: '禁用', status: 'Default'},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -114,7 +99,7 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Tooltip title="环境数量">
|
<Tooltip title="环境数量">
|
||||||
<Space>
|
<Space>
|
||||||
<EnvironmentOutlined />
|
<EnvironmentOutlined/>
|
||||||
{record.environments?.length || 0}
|
{record.environments?.length || 0}
|
||||||
</Space>
|
</Space>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -127,7 +112,7 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Tooltip title="项目数量">
|
<Tooltip title="项目数量">
|
||||||
<Space>
|
<Space>
|
||||||
<TeamOutlined />
|
<TeamOutlined/>
|
||||||
{record.applications?.length || 0}
|
{record.applications?.length || 0}
|
||||||
</Space>
|
</Space>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -145,6 +130,7 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
key: 'action',
|
key: 'action',
|
||||||
valueType: 'option',
|
valueType: 'option',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
|
align: 'center',
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Space>
|
<Space>
|
||||||
<Button
|
<Button
|
||||||
@ -184,7 +170,7 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
pageNum: params.current,
|
pageNum: params.current,
|
||||||
projectGroupName: params.projectGroupName as string,
|
projectGroupName: params.projectGroupName as string,
|
||||||
projectGroupCode: params.projectGroupCode as string,
|
projectGroupCode: params.projectGroupCode as string,
|
||||||
projectGroupStatus: params.projectGroupStatus as string,
|
enabled: params.enabled as boolean,
|
||||||
};
|
};
|
||||||
const data = await getProjectGroupPage(queryParams);
|
const data = await getProjectGroupPage(queryParams);
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -2,13 +2,11 @@ import {BaseResponse, BaseRequest, BaseQuery} from '@/types/base';
|
|||||||
import {Environment} from '../../Environment/List/types';
|
import {Environment} from '../../Environment/List/types';
|
||||||
import {Application} from "@/pages/Deploy/Application/List/types";
|
import {Application} from "@/pages/Deploy/Application/List/types";
|
||||||
|
|
||||||
|
|
||||||
export enum ProjectGroupTypeEnum {
|
export enum ProjectGroupTypeEnum {
|
||||||
PRODUCT = 'PRODUCT',
|
PRODUCT = 'PRODUCT',
|
||||||
PROJECT = 'PROJECT'
|
PROJECT = 'PROJECT'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 项目基础信息
|
// 项目基础信息
|
||||||
export interface ProjectGroup extends BaseResponse {
|
export interface ProjectGroup extends BaseResponse {
|
||||||
tenantCode: string;
|
tenantCode: string;
|
||||||
@ -16,7 +14,7 @@ export interface ProjectGroup extends BaseResponse {
|
|||||||
projectGroupCode: string;
|
projectGroupCode: string;
|
||||||
projectGroupName: string;
|
projectGroupName: string;
|
||||||
projectGroupDesc?: string;
|
projectGroupDesc?: string;
|
||||||
projectGroupStatus: 'ENABLE' | 'DISABLE';
|
enabled: boolean;
|
||||||
environments: Environment[];
|
environments: Environment[];
|
||||||
applications: Application[];
|
applications: Application[];
|
||||||
sort: number;
|
sort: number;
|
||||||
@ -29,7 +27,7 @@ export interface CreateProjectGroupRequest extends BaseRequest {
|
|||||||
projectGroupCode: string;
|
projectGroupCode: string;
|
||||||
projectGroupName: string;
|
projectGroupName: string;
|
||||||
projectGroupDesc?: string;
|
projectGroupDesc?: string;
|
||||||
projectGroupStatus: string;
|
enabled: boolean;
|
||||||
sort: number;
|
sort: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,5 +40,5 @@ export interface UpdateProjectGroupRequest extends CreateProjectGroupRequest {
|
|||||||
export interface ProjectGroupQueryParams extends BaseQuery {
|
export interface ProjectGroupQueryParams extends BaseQuery {
|
||||||
projectGroupName?: string;
|
projectGroupName?: string;
|
||||||
projectGroupCode?: string;
|
projectGroupCode?: string;
|
||||||
projectGroupStatus?: string;
|
enabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
37
frontend/src/pages/Deploy/ProjectGroup/List/utils.tsx
Normal file
37
frontend/src/pages/Deploy/ProjectGroup/List/utils.tsx
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {ProjectOutlined, RocketOutlined} from '@ant-design/icons';
|
||||||
|
import {ProjectGroupTypeEnum} from './types';
|
||||||
|
|
||||||
|
interface ProjectTypeInfo {
|
||||||
|
type: ProjectGroupTypeEnum;
|
||||||
|
label: string;
|
||||||
|
color: string;
|
||||||
|
icon: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取项目组类型信息
|
||||||
|
export const getProjectTypeInfo = (type: ProjectGroupTypeEnum): ProjectTypeInfo => {
|
||||||
|
switch (type) {
|
||||||
|
case ProjectGroupTypeEnum.PRODUCT:
|
||||||
|
return {
|
||||||
|
type: ProjectGroupTypeEnum.PRODUCT,
|
||||||
|
label: '产品型',
|
||||||
|
color: '#1890ff',
|
||||||
|
icon: <RocketOutlined/>,
|
||||||
|
};
|
||||||
|
case ProjectGroupTypeEnum.PROJECT:
|
||||||
|
return {
|
||||||
|
type: ProjectGroupTypeEnum.PROJECT,
|
||||||
|
label: '项目型',
|
||||||
|
color: '#52c41a',
|
||||||
|
icon: <ProjectOutlined/>,
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
type: type,
|
||||||
|
label: type || '未知',
|
||||||
|
color: '#666666',
|
||||||
|
icon: <ProjectOutlined/>,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user