1
This commit is contained in:
parent
8f5c05d16f
commit
224a3fe5cc
@ -1,166 +1,175 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, {useState} from 'react';
|
||||||
import { Modal, Form, Input, InputNumber, Radio, message, Select } from 'antd';
|
import {Modal, Form, Input, Select, Switch, InputNumber, App} from 'antd';
|
||||||
import type { Application } from '../types';
|
import type {Application} from '../types';
|
||||||
import { createApplication, updateApplication } from '../service';
|
import {DevelopmentLanguageTypeEnum} from '../types';
|
||||||
import { DevelopmentLanguageTypeEnum } from '../types';
|
import {createApplication, updateApplication} from '../service';
|
||||||
|
|
||||||
interface ApplicationModalProps {
|
interface ApplicationModalProps {
|
||||||
visible: boolean;
|
open: boolean;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onSuccess: () => void;
|
onSuccess: () => void;
|
||||||
initialValues?: Application;
|
initialValues?: Application;
|
||||||
projectGroupId: number;
|
projectGroupId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
const ApplicationModal: React.FC<ApplicationModalProps> = ({
|
||||||
visible,
|
open,
|
||||||
onCancel,
|
onCancel,
|
||||||
onSuccess,
|
onSuccess,
|
||||||
initialValues,
|
initialValues,
|
||||||
projectGroupId,
|
projectGroupId,
|
||||||
}) => {
|
}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const isEdit = !!initialValues;
|
const [loading, setLoading] = useState(false);
|
||||||
|
const {message: messageApi} = App.useApp();
|
||||||
|
const isEdit = !!initialValues?.id;
|
||||||
|
|
||||||
useEffect(() => {
|
const handleSubmit = async () => {
|
||||||
if (visible) {
|
try {
|
||||||
if (initialValues) {
|
setLoading(true);
|
||||||
form.setFieldsValue({
|
const values = await form.validateFields();
|
||||||
...initialValues,
|
if (isEdit) {
|
||||||
});
|
await updateApplication({
|
||||||
} else {
|
...values,
|
||||||
form.setFieldsValue({
|
id: initialValues.id,
|
||||||
projectGroupId,
|
});
|
||||||
enabled: true,
|
} else {
|
||||||
sort: 0,
|
await createApplication({
|
||||||
language: DevelopmentLanguageTypeEnum.JAVA,
|
...values,
|
||||||
});
|
projectGroupId,
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
}, [visible, initialValues, form, projectGroupId]);
|
messageApi.success(`${isEdit ? '更新' : '创建'}成功`);
|
||||||
|
form.resetFields();
|
||||||
|
onSuccess();
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
messageApi.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
|
||||||
|
} else {
|
||||||
|
messageApi.error(`${isEdit ? '更新' : '创建'}失败`);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
return (
|
||||||
try {
|
<Modal
|
||||||
const values = await form.validateFields();
|
title={`${isEdit ? '编辑' : '新建'}应用`}
|
||||||
const submitData = {
|
open={open}
|
||||||
...values,
|
onCancel={() => {
|
||||||
projectGroupId,
|
form.resetFields();
|
||||||
};
|
onCancel();
|
||||||
|
}}
|
||||||
if (isEdit) {
|
onOk={handleSubmit}
|
||||||
await updateApplication({ ...submitData, id: initialValues?.id });
|
confirmLoading={loading}
|
||||||
message.success('更新成功');
|
maskClosable={false}
|
||||||
} else {
|
destroyOnClose
|
||||||
await createApplication(submitData);
|
|
||||||
message.success('创建成功');
|
|
||||||
}
|
|
||||||
onSuccess();
|
|
||||||
onCancel();
|
|
||||||
form.resetFields();
|
|
||||||
} catch (error) {
|
|
||||||
message.error(isEdit ? '更新失败' : '创建失败');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
form.resetFields();
|
|
||||||
onCancel();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
title={isEdit ? '编辑应用' : '新建应用'}
|
|
||||||
open={visible}
|
|
||||||
onOk={handleSubmit}
|
|
||||||
onCancel={handleCancel}
|
|
||||||
destroyOnClose
|
|
||||||
width={600}
|
|
||||||
>
|
|
||||||
<Form
|
|
||||||
form={form}
|
|
||||||
layout="vertical"
|
|
||||||
initialValues={{
|
|
||||||
enabled: true,
|
|
||||||
sort: 0,
|
|
||||||
language: DevelopmentLanguageTypeEnum.JAVA,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{/* 隐藏的项目组ID字段 */}
|
|
||||||
<Form.Item name="projectGroupId" hidden>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
name="appCode"
|
|
||||||
label="应用编码"
|
|
||||||
rules={[
|
|
||||||
{ required: true, message: '请输入应用编码' },
|
|
||||||
{ pattern: /^[A-Za-z0-9_-]+$/, message: '应用编码只能包含字母、数字、下划线和连字符' }
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<Input placeholder="请输入应用编码" disabled={isEdit} />
|
<Form
|
||||||
</Form.Item>
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
|
initialValues={{
|
||||||
|
enabled: true,
|
||||||
|
sort: 0,
|
||||||
|
...initialValues,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
name="appCode"
|
||||||
|
label="应用编码"
|
||||||
|
rules={[
|
||||||
|
{required: true, message: '请输入应用编码'},
|
||||||
|
{max: 50, message: '应用编码不能超过50个字符'},
|
||||||
|
]}
|
||||||
|
tooltip="应用的唯一标识,创建后不可修改"
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
placeholder="请输入应用编码"
|
||||||
|
disabled={isEdit}
|
||||||
|
maxLength={50}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="appName"
|
name="appName"
|
||||||
label="应用名称"
|
label="应用名称"
|
||||||
rules={[{ required: true, message: '请输入应用名称' }]}
|
rules={[
|
||||||
>
|
{required: true, message: '请输入应用名称'},
|
||||||
<Input placeholder="请输入应用名称" />
|
{max: 50, message: '应用名称不能超过50个字符'},
|
||||||
</Form.Item>
|
]}
|
||||||
|
tooltip="应用的显示名称"
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
placeholder="请输入应用名称"
|
||||||
|
maxLength={50}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="appDesc"
|
name="language"
|
||||||
label="应用描述"
|
label="开发语言"
|
||||||
>
|
rules={[{required: true, message: '请选择开发语言'}]}
|
||||||
<Input.TextArea rows={4} placeholder="请输入应用描述" />
|
tooltip="应用的主要开发语言,创建后不可修改"
|
||||||
</Form.Item>
|
>
|
||||||
|
<Select
|
||||||
|
placeholder="请选择开发语言"
|
||||||
|
disabled={isEdit}
|
||||||
|
>
|
||||||
|
<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
|
<Form.Item
|
||||||
name="repoUrl"
|
name="repoUrl"
|
||||||
label="仓库地址"
|
label="仓库地址"
|
||||||
rules={[
|
rules={[
|
||||||
{ required: true, message: '请输入仓库地址' },
|
{required: true, message: '请输入仓库地址'},
|
||||||
{ type: 'url', message: '请输入有效的URL地址' },
|
{type: 'url', message: '请输入有效的URL地址'},
|
||||||
]}
|
]}
|
||||||
>
|
tooltip="应用代码仓库的URL地址"
|
||||||
<Input placeholder="请输入仓库地址" />
|
>
|
||||||
</Form.Item>
|
<Input
|
||||||
|
placeholder="请输入仓库地址"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="language"
|
name="appDesc"
|
||||||
label="开发语言"
|
label="应用描述"
|
||||||
rules={[{ required: true, message: '请选择开发语言' }]}
|
rules={[{max: 200, message: '应用描述不能超过200个字符'}]}
|
||||||
>
|
tooltip="应用的详细描述信息"
|
||||||
<Select placeholder="请选择开发语言">
|
>
|
||||||
<Select.Option value={DevelopmentLanguageTypeEnum.JAVA}>Java</Select.Option>
|
<Input.TextArea
|
||||||
<Select.Option value={DevelopmentLanguageTypeEnum.NODE_JS}>NodeJS</Select.Option>
|
placeholder="请输入应用描述"
|
||||||
<Select.Option value={DevelopmentLanguageTypeEnum.PYTHON}>Python</Select.Option>
|
maxLength={200}
|
||||||
<Select.Option value={DevelopmentLanguageTypeEnum.GO}>Go</Select.Option>
|
showCount
|
||||||
</Select>
|
rows={4}
|
||||||
</Form.Item>
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="enabled"
|
name="enabled"
|
||||||
label="应用状态"
|
label="状态"
|
||||||
rules={[{ required: true, message: '请选择应用状态' }]}
|
valuePropName="checked"
|
||||||
>
|
tooltip="是否启用该应用"
|
||||||
<Radio.Group>
|
>
|
||||||
<Radio value={true}>启用</Radio>
|
<Switch checkedChildren="启用" unCheckedChildren="禁用"/>
|
||||||
<Radio value={false}>禁用</Radio>
|
</Form.Item>
|
||||||
</Radio.Group>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="sort"
|
name="sort"
|
||||||
label="排序"
|
label="排序"
|
||||||
rules={[{ required: true, message: '请输入排序值' }]}
|
tooltip="数字越小越靠前"
|
||||||
>
|
>
|
||||||
<InputNumber min={0} placeholder="请输入排序值" style={{ width: '100%' }} />
|
<InputNumber min={0} style={{width: '100%'}}/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ApplicationModal;
|
export default ApplicationModal;
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
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, Space, Popconfirm, Tag, Select, App} from 'antd';
|
||||||
import {
|
import {
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
EditOutlined,
|
EditOutlined,
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
CodeOutlined,
|
CodeOutlined,
|
||||||
CloudUploadOutlined,
|
|
||||||
ApiOutlined,
|
|
||||||
GithubOutlined,
|
GithubOutlined,
|
||||||
JavaOutlined,
|
JavaOutlined,
|
||||||
NodeIndexOutlined,
|
NodeIndexOutlined,
|
||||||
@ -32,6 +30,7 @@ const ApplicationList: React.FC = () => {
|
|||||||
const [modalVisible, setModalVisible] = useState(false);
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
const [currentApplication, setCurrentApplication] = useState<Application>();
|
const [currentApplication, setCurrentApplication] = useState<Application>();
|
||||||
const actionRef = React.useRef<ActionType>();
|
const actionRef = React.useRef<ActionType>();
|
||||||
|
const {message: messageApi} = App.useApp();
|
||||||
|
|
||||||
// 获取项目列表
|
// 获取项目列表
|
||||||
const fetchProjects = async () => {
|
const fetchProjects = async () => {
|
||||||
@ -42,7 +41,7 @@ const ApplicationList: React.FC = () => {
|
|||||||
setSelectedProjectGroupId(data[0].id);
|
setSelectedProjectGroupId(data[0].id);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('获取项目组列表失败');
|
messageApi.error('获取项目组列表失败');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -53,16 +52,16 @@ const ApplicationList: React.FC = () => {
|
|||||||
const handleDelete = async (id: number) => {
|
const handleDelete = async (id: number) => {
|
||||||
try {
|
try {
|
||||||
await deleteApplication(id);
|
await deleteApplication(id);
|
||||||
message.success('删除成功');
|
messageApi.success('删除成功');
|
||||||
actionRef.current?.reload();
|
actionRef.current?.reload();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('删除失败');
|
messageApi.error('删除失败');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
if (!selectedProjectGroupId) {
|
if (!selectedProjectGroupId) {
|
||||||
message.warning('请先选择项目组');
|
messageApi.warning('请先选择项目组');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setCurrentApplication(undefined);
|
setCurrentApplication(undefined);
|
||||||
@ -79,6 +78,17 @@ const ApplicationList: React.FC = () => {
|
|||||||
actionRef.current?.reload();
|
actionRef.current?.reload();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleModalClose = () => {
|
||||||
|
setModalVisible(false);
|
||||||
|
setCurrentApplication(undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSuccess = () => {
|
||||||
|
setModalVisible(false);
|
||||||
|
setCurrentApplication(undefined);
|
||||||
|
actionRef.current?.reload();
|
||||||
|
};
|
||||||
|
|
||||||
// 获取开发语言信息
|
// 获取开发语言信息
|
||||||
const getLanguageInfo = (language: DevelopmentLanguageTypeEnum) => {
|
const getLanguageInfo = (language: DevelopmentLanguageTypeEnum) => {
|
||||||
switch (language) {
|
switch (language) {
|
||||||
@ -207,19 +217,20 @@ const ApplicationList: React.FC = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
width: 150,
|
width: 180,
|
||||||
key: 'action',
|
key: 'action',
|
||||||
valueType: 'option',
|
valueType: 'option',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
align: 'center',
|
|
||||||
render: (_, record) => [
|
render: (_, record) => [
|
||||||
<Button
|
<Button
|
||||||
key="edit"
|
key="edit"
|
||||||
type="link"
|
type="link"
|
||||||
icon={<EditOutlined/>}
|
|
||||||
onClick={() => handleEdit(record)}
|
onClick={() => handleEdit(record)}
|
||||||
>
|
>
|
||||||
编辑
|
<Space>
|
||||||
|
<EditOutlined/>
|
||||||
|
编辑
|
||||||
|
</Space>
|
||||||
</Button>,
|
</Button>,
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
key="delete"
|
key="delete"
|
||||||
@ -230,22 +241,68 @@ const ApplicationList: React.FC = () => {
|
|||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
danger
|
danger
|
||||||
icon={<DeleteOutlined/>}
|
|
||||||
>
|
>
|
||||||
删除
|
<Space>
|
||||||
|
<DeleteOutlined/>
|
||||||
|
删除
|
||||||
|
</Space>
|
||||||
</Button>
|
</Button>
|
||||||
</Popconfirm>,
|
</Popconfirm>
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<PageContainer
|
||||||
|
header={{
|
||||||
|
title: '应用管理',
|
||||||
|
extra: [
|
||||||
|
<Select
|
||||||
|
key="project-select"
|
||||||
|
value={selectedProjectGroupId}
|
||||||
|
onChange={handleProjectChange}
|
||||||
|
style={{width: 200}}
|
||||||
|
placeholder="请选择项目组"
|
||||||
|
>
|
||||||
|
{projectGroups.map((project) => (
|
||||||
|
<Option key={project.id} value={project.id}>
|
||||||
|
{project.projectGroupName}
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
|
</Select>,
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ProTable<Application>
|
<ProTable<Application>
|
||||||
columns={columns}
|
columns={columns}
|
||||||
actionRef={actionRef}
|
actionRef={actionRef}
|
||||||
scroll={{x: 'max-content'}}
|
scroll={{x: 'max-content'}}
|
||||||
cardBordered
|
cardBordered
|
||||||
|
rowKey="id"
|
||||||
|
search={false}
|
||||||
|
options={{
|
||||||
|
setting: false,
|
||||||
|
density: false,
|
||||||
|
fullScreen: false,
|
||||||
|
reload: false,
|
||||||
|
}}
|
||||||
|
toolbar={{
|
||||||
|
actions: [
|
||||||
|
<Button
|
||||||
|
key="add"
|
||||||
|
type="primary"
|
||||||
|
onClick={handleAdd}
|
||||||
|
icon={<PlusOutlined/>}
|
||||||
|
disabled={!selectedProjectGroupId}
|
||||||
|
>
|
||||||
|
新建应用
|
||||||
|
</Button>
|
||||||
|
],
|
||||||
|
}}
|
||||||
|
pagination={{
|
||||||
|
pageSize: 10,
|
||||||
|
showQuickJumper: true,
|
||||||
|
}}
|
||||||
request={async (params) => {
|
request={async (params) => {
|
||||||
if (!selectedProjectGroupId) {
|
if (!selectedProjectGroupId) {
|
||||||
return {
|
return {
|
||||||
@ -254,71 +311,42 @@ const ApplicationList: React.FC = () => {
|
|||||||
total: 0,
|
total: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const queryParams: ApplicationQuery = {
|
try {
|
||||||
pageSize: params.pageSize,
|
const queryParams: ApplicationQuery = {
|
||||||
pageNum: params.current,
|
pageSize: params.pageSize,
|
||||||
appCode: params.appCode as string,
|
pageNum: params.current,
|
||||||
appName: params.appName as string,
|
projectGroupId: selectedProjectGroupId,
|
||||||
enabled: params.enabled as boolean,
|
appCode: params.appCode as string,
|
||||||
};
|
appName: params.appName as string,
|
||||||
const data = await getApplicationPage(queryParams);
|
enabled: params.enabled as boolean,
|
||||||
return {
|
};
|
||||||
data: data.content || [],
|
const data = await getApplicationPage(queryParams);
|
||||||
success: true,
|
return {
|
||||||
total: data.totalElements || 0,
|
data: data.content || [],
|
||||||
};
|
success: true,
|
||||||
|
total: data.totalElements || 0,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
messageApi.error('获取应用列表失败');
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
success: false,
|
||||||
|
total: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
rowKey="id"
|
|
||||||
search={{
|
|
||||||
labelWidth: 'auto',
|
|
||||||
span: {
|
|
||||||
xs: 24,
|
|
||||||
sm: 12,
|
|
||||||
md: 8,
|
|
||||||
lg: 6,
|
|
||||||
xl: 6,
|
|
||||||
xxl: 6,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
options={{
|
|
||||||
setting: {
|
|
||||||
listsHeight: 400,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
form={{
|
|
||||||
syncToUrl: true,
|
|
||||||
}}
|
|
||||||
pagination={{
|
|
||||||
pageSize: 10,
|
|
||||||
showQuickJumper: true,
|
|
||||||
}}
|
|
||||||
dateFormatter="string"
|
|
||||||
toolBarRender={() => [
|
|
||||||
<Button
|
|
||||||
key="add"
|
|
||||||
type="primary"
|
|
||||||
onClick={handleAdd}
|
|
||||||
icon={<PlusOutlined/>}
|
|
||||||
disabled={!selectedProjectGroupId}
|
|
||||||
>
|
|
||||||
新建应用
|
|
||||||
</Button>,
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{selectedProjectGroupId && (
|
{modalVisible && selectedProjectGroupId && (
|
||||||
<ApplicationModal
|
<ApplicationModal
|
||||||
visible={modalVisible}
|
open={modalVisible}
|
||||||
onCancel={() => setModalVisible(false)}
|
onCancel={handleModalClose}
|
||||||
onSuccess={() => {
|
onSuccess={handleSuccess}
|
||||||
setModalVisible(false);
|
|
||||||
actionRef.current?.reload();
|
|
||||||
}}
|
|
||||||
initialValues={currentApplication}
|
initialValues={currentApplication}
|
||||||
projectGroupId={selectedProjectGroupId}
|
projectGroupId={selectedProjectGroupId}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</PageContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, {useEffect, useState, useCallback} from 'react';
|
import React, {useEffect, useState, useCallback} from 'react';
|
||||||
import {Modal, Form, Select, message, Switch, InputNumber} from 'antd';
|
import {Modal, Form, Select, message, Switch, InputNumber, App} from 'antd';
|
||||||
import type {DeploymentConfig, DeployConfigTemplate} from '../types';
|
import type {DeploymentConfig, DeployConfigTemplate} from '../types';
|
||||||
import {createDeploymentConfig, updateDeploymentConfig, getDeployConfigTemplates} from '../service';
|
import {createDeploymentConfig, updateDeploymentConfig, getDeployConfigTemplates} from '../service';
|
||||||
import {getApplicationList} from '../../../Application/List/service';
|
import {getApplicationList} from '../../../Application/List/service';
|
||||||
@ -33,6 +33,7 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
|
|||||||
const [selectedTemplate, setSelectedTemplate] = useState<DeployConfigTemplate>();
|
const [selectedTemplate, setSelectedTemplate] = useState<DeployConfigTemplate>();
|
||||||
const [buildVariables, setBuildVariables] = useState<Record<string, any>>({});
|
const [buildVariables, setBuildVariables] = useState<Record<string, any>>({});
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const {message: messageApi} = App.useApp();
|
||||||
const isEdit = !!initialValues?.id;
|
const isEdit = !!initialValues?.id;
|
||||||
|
|
||||||
// 获取应用列表
|
// 获取应用列表
|
||||||
@ -41,9 +42,9 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
|
|||||||
const data = await getApplicationList();
|
const data = await getApplicationList();
|
||||||
setApplications(data);
|
setApplications(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('获取应用列表失败');
|
messageApi.error('获取应用列表失败');
|
||||||
}
|
}
|
||||||
}, []);
|
}, [messageApi]);
|
||||||
|
|
||||||
// 获取配置模板
|
// 获取配置模板
|
||||||
const fetchTemplates = useCallback(async () => {
|
const fetchTemplates = useCallback(async () => {
|
||||||
@ -51,9 +52,9 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
|
|||||||
const data = await getDeployConfigTemplates();
|
const data = await getDeployConfigTemplates();
|
||||||
setTemplates(data);
|
setTemplates(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('获取配置模板失败');
|
messageApi.error('获取配置模板失败');
|
||||||
}
|
}
|
||||||
}, []);
|
}, [messageApi]);
|
||||||
|
|
||||||
// 在模态框显示时获取数据
|
// 在模态框显示时获取数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -115,14 +116,14 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
|
|||||||
} else {
|
} else {
|
||||||
await createDeploymentConfig(submitData);
|
await createDeploymentConfig(submitData);
|
||||||
}
|
}
|
||||||
message.success(`${isEdit ? '更新' : '创建'}成功`);
|
messageApi.success(`${isEdit ? '更新' : '创建'}成功`);
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
onSuccess();
|
onSuccess();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
message.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
|
messageApi.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
|
||||||
} else {
|
} else {
|
||||||
message.error(`${isEdit ? '更新' : '创建'}失败`);
|
messageApi.error(`${isEdit ? '更新' : '创建'}失败`);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|||||||
@ -1,34 +1,30 @@
|
|||||||
import React, {useEffect} from 'react';
|
import React, {useState} from 'react';
|
||||||
import {Modal, Form, Input, InputNumber, Select, message} from 'antd';
|
import {Modal, Form, Input, Select, Switch, InputNumber, App} from 'antd';
|
||||||
import type {Environment} from '../types';
|
import type {Environment} from '../types';
|
||||||
import {BuildTypeEnum, DeployTypeEnum} from '../types';
|
import {BuildTypeEnum, DeployTypeEnum} from '../types';
|
||||||
import {createEnvironment, updateEnvironment} from '../service';
|
import {createEnvironment, updateEnvironment} from '../service';
|
||||||
import {getBuildTypeInfo, getDeployTypeInfo} from '../utils';
|
|
||||||
|
|
||||||
interface EnvironmentModalProps {
|
interface EnvironmentModalProps {
|
||||||
visible: boolean;
|
open: boolean;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onSuccess: () => void;
|
onSuccess: () => void;
|
||||||
initialValues?: Environment;
|
initialValues?: Environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
const EnvironmentModal: React.FC<EnvironmentModalProps> = ({
|
const EnvironmentModal: React.FC<EnvironmentModalProps> = ({
|
||||||
visible,
|
open,
|
||||||
onCancel,
|
onCancel,
|
||||||
onSuccess,
|
onSuccess,
|
||||||
initialValues,
|
initialValues,
|
||||||
}) => {
|
}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const {message: messageApi} = App.useApp();
|
||||||
const isEdit = !!initialValues?.id;
|
const isEdit = !!initialValues?.id;
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (visible && initialValues) {
|
|
||||||
form.setFieldsValue(initialValues);
|
|
||||||
}
|
|
||||||
}, [visible, initialValues, form]);
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
|
setLoading(true);
|
||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
await updateEnvironment({
|
await updateEnvironment({
|
||||||
@ -38,30 +34,40 @@ const EnvironmentModal: React.FC<EnvironmentModalProps> = ({
|
|||||||
} else {
|
} else {
|
||||||
await createEnvironment(values);
|
await createEnvironment(values);
|
||||||
}
|
}
|
||||||
message.success(`${isEdit ? '更新' : '创建'}成功`);
|
messageApi.success(`${isEdit ? '更新' : '创建'}成功`);
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
onSuccess();
|
onSuccess();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error(`${isEdit ? '更新' : '创建'}失败`);
|
if (error instanceof Error) {
|
||||||
|
messageApi.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
|
||||||
|
} else {
|
||||||
|
messageApi.error(`${isEdit ? '更新' : '创建'}失败`);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={`${isEdit ? '编辑' : '新建'}环境`}
|
title={`${isEdit ? '编辑' : '新建'}环境`}
|
||||||
open={visible}
|
open={open}
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
onCancel();
|
onCancel();
|
||||||
}}
|
}}
|
||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
width={600}
|
confirmLoading={loading}
|
||||||
|
maskClosable={false}
|
||||||
|
destroyOnClose
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
initialValues={{
|
initialValues={{
|
||||||
|
enabled: true,
|
||||||
sort: 0,
|
sort: 0,
|
||||||
|
...initialValues,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@ -69,10 +75,15 @@ const EnvironmentModal: React.FC<EnvironmentModalProps> = ({
|
|||||||
label="环境编码"
|
label="环境编码"
|
||||||
rules={[
|
rules={[
|
||||||
{required: true, message: '请输入环境编码'},
|
{required: true, message: '请输入环境编码'},
|
||||||
{max: 50, message: '环境编码长度不能超过50个字符'},
|
{max: 50, message: '环境编码不能超过50个字符'},
|
||||||
]}
|
]}
|
||||||
|
tooltip="环境的唯一标识,创建后不可修改"
|
||||||
>
|
>
|
||||||
<Input placeholder="请输入环境编码"/>
|
<Input
|
||||||
|
placeholder="请输入环境编码"
|
||||||
|
disabled={isEdit}
|
||||||
|
maxLength={50}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@ -80,74 +91,75 @@ const EnvironmentModal: React.FC<EnvironmentModalProps> = ({
|
|||||||
label="环境名称"
|
label="环境名称"
|
||||||
rules={[
|
rules={[
|
||||||
{required: true, message: '请输入环境名称'},
|
{required: true, message: '请输入环境名称'},
|
||||||
{max: 50, message: '环境名称长度不能超过50个字符'},
|
{max: 50, message: '环境名称不能超过50个字符'},
|
||||||
]}
|
]}
|
||||||
|
tooltip="环境的显示名称"
|
||||||
>
|
>
|
||||||
<Input placeholder="请输入环境名称"/>
|
<Input
|
||||||
</Form.Item>
|
placeholder="请输入环境名称"
|
||||||
|
maxLength={50}
|
||||||
<Form.Item
|
/>
|
||||||
name="envDesc"
|
|
||||||
label="环境描述"
|
|
||||||
rules={[{max: 200, message: '环境描述长度不能超过200个字符'}]}
|
|
||||||
>
|
|
||||||
<Input.TextArea rows={4} placeholder="请输入环境描述"/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="buildType"
|
name="buildType"
|
||||||
label="构建方式"
|
label="构建类型"
|
||||||
rules={[{required: true, message: '请选择构建方式'}]}
|
rules={[{required: true, message: '请选择构建类型'}]}
|
||||||
|
tooltip="环境的构建类型,创建后不可修改"
|
||||||
>
|
>
|
||||||
<Select placeholder="请选择构建方式">
|
<Select
|
||||||
{Object.values(BuildTypeEnum).map((type) => {
|
placeholder="请选择构建类型"
|
||||||
const typeInfo = getBuildTypeInfo(type);
|
disabled={isEdit}
|
||||||
return (
|
>
|
||||||
<Select.Option key={type} value={type}>
|
<Select.Option value={BuildTypeEnum.LOCAL}>本地构建</Select.Option>
|
||||||
<div style={{
|
<Select.Option value={BuildTypeEnum.REMOTE}>远程构建</Select.Option>
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '4px',
|
|
||||||
}}>
|
|
||||||
<span style={{ color: typeInfo.color }}>{typeInfo.icon}</span>
|
|
||||||
<span style={{ color: typeInfo.color }}>{typeInfo.label}</span>
|
|
||||||
</div>
|
|
||||||
</Select.Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="deployType"
|
name="deployType"
|
||||||
label="部署方式"
|
label="部署类型"
|
||||||
rules={[{required: true, message: '请选择部署方式'}]}
|
rules={[{required: true, message: '请选择部署类型'}]}
|
||||||
|
tooltip="环境的部署类型,创建后不可修改"
|
||||||
>
|
>
|
||||||
<Select placeholder="请选择部署方式">
|
<Select
|
||||||
{Object.values(DeployTypeEnum).map((type) => {
|
placeholder="请选择部署类型"
|
||||||
const typeInfo = getDeployTypeInfo(type);
|
disabled={isEdit}
|
||||||
return (
|
>
|
||||||
<Select.Option key={type} value={type}>
|
<Select.Option value={DeployTypeEnum.KUBERNETES}>Kubernetes</Select.Option>
|
||||||
<div style={{
|
<Select.Option value={DeployTypeEnum.DOCKER}>Docker</Select.Option>
|
||||||
display: 'inline-flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
gap: '4px',
|
|
||||||
}}>
|
|
||||||
<span style={{ color: typeInfo.color }}>{typeInfo.icon}</span>
|
|
||||||
<span style={{ color: typeInfo.color }}>{typeInfo.label}</span>
|
|
||||||
</div>
|
|
||||||
</Select.Option>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="envDesc"
|
||||||
|
label="环境描述"
|
||||||
|
rules={[{max: 200, message: '环境描述不能超过200个字符'}]}
|
||||||
|
tooltip="环境的详细描述信息"
|
||||||
|
>
|
||||||
|
<Input.TextArea
|
||||||
|
placeholder="请输入环境描述"
|
||||||
|
maxLength={200}
|
||||||
|
showCount
|
||||||
|
rows={4}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="enabled"
|
||||||
|
label="状态"
|
||||||
|
valuePropName="checked"
|
||||||
|
tooltip="是否启用该环境"
|
||||||
|
>
|
||||||
|
<Switch checkedChildren="启用" unCheckedChildren="禁用"/>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="sort"
|
name="sort"
|
||||||
label="排序"
|
label="排序"
|
||||||
rules={[{required: true, message: '请输入排序号'}]}
|
tooltip="数字越小越靠前"
|
||||||
>
|
>
|
||||||
<InputNumber min={0} max={999} style={{width: '100%'}}/>
|
<InputNumber min={0} style={{width: '100%'}}/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
import {PageContainer} from '@ant-design/pro-layout';
|
import {PageContainer} from '@ant-design/pro-layout';
|
||||||
import {Button, message, Popconfirm, Tag} from 'antd';
|
import {Button, Space, Popconfirm, Tag, App} from 'antd';
|
||||||
import {PlusOutlined, EditOutlined, DeleteOutlined} from '@ant-design/icons';
|
import {PlusOutlined, EditOutlined, DeleteOutlined} from '@ant-design/icons';
|
||||||
import {getEnvironmentPage, deleteEnvironment} from './service';
|
import {getEnvironmentPage, deleteEnvironment} from './service';
|
||||||
import type {Environment, EnvironmentQueryParams} from './types';
|
import type {Environment, EnvironmentQueryParams} from './types';
|
||||||
@ -14,14 +14,15 @@ const EnvironmentList: React.FC = () => {
|
|||||||
const [modalVisible, setModalVisible] = useState(false);
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
const [currentEnvironment, setCurrentEnvironment] = useState<Environment>();
|
const [currentEnvironment, setCurrentEnvironment] = useState<Environment>();
|
||||||
const actionRef = React.useRef<ActionType>();
|
const actionRef = React.useRef<ActionType>();
|
||||||
|
const {message: messageApi} = App.useApp();
|
||||||
|
|
||||||
const handleDelete = async (id: number) => {
|
const handleDelete = async (id: number) => {
|
||||||
try {
|
try {
|
||||||
await deleteEnvironment(id);
|
await deleteEnvironment(id);
|
||||||
message.success('删除成功');
|
messageApi.success('删除成功');
|
||||||
actionRef.current?.reload();
|
actionRef.current?.reload();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('删除失败');
|
messageApi.error('删除失败');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -35,24 +36,16 @@ const EnvironmentList: React.FC = () => {
|
|||||||
setModalVisible(true);
|
setModalVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderTag = (icon: React.ReactNode, label: string, color: string) => (
|
const handleModalClose = () => {
|
||||||
<div style={{
|
setModalVisible(false);
|
||||||
display: 'inline-flex',
|
setCurrentEnvironment(undefined);
|
||||||
alignItems: 'center',
|
};
|
||||||
padding: '0 7px',
|
|
||||||
fontSize: '14px',
|
const handleSuccess = () => {
|
||||||
lineHeight: '22px',
|
setModalVisible(false);
|
||||||
whiteSpace: 'nowrap',
|
setCurrentEnvironment(undefined);
|
||||||
background: color + '10',
|
actionRef.current?.reload();
|
||||||
border: `1px solid ${color}`,
|
};
|
||||||
borderRadius: '4px',
|
|
||||||
cursor: 'default',
|
|
||||||
gap: '4px',
|
|
||||||
}}>
|
|
||||||
{icon}
|
|
||||||
<span style={{ color }}>{label}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
const columns: ProColumns<Environment>[] = [
|
const columns: ProColumns<Environment>[] = [
|
||||||
{
|
{
|
||||||
@ -73,16 +66,21 @@ const EnvironmentList: React.FC = () => {
|
|||||||
title: '环境描述',
|
title: '环境描述',
|
||||||
dataIndex: 'envDesc',
|
dataIndex: 'envDesc',
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
width: '30%',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '构建方式',
|
title: '构建类型',
|
||||||
dataIndex: 'buildType',
|
dataIndex: 'buildType',
|
||||||
width: 180,
|
width: 120,
|
||||||
render: (buildType) => {
|
render: (buildType) => {
|
||||||
if (!buildType) return '-';
|
|
||||||
const typeInfo = getBuildTypeInfo(buildType as BuildTypeEnum);
|
const typeInfo = getBuildTypeInfo(buildType as BuildTypeEnum);
|
||||||
return renderTag(typeInfo.icon, typeInfo.label, typeInfo.color);
|
return (
|
||||||
|
<Tag color={typeInfo.color}>
|
||||||
|
<Space>
|
||||||
|
{typeInfo.icon}
|
||||||
|
{typeInfo.label}
|
||||||
|
</Space>
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
filters: [
|
filters: [
|
||||||
{text: 'Jenkins构建', value: BuildTypeEnum.JENKINS},
|
{text: 'Jenkins构建', value: BuildTypeEnum.JENKINS},
|
||||||
@ -93,13 +91,19 @@ const EnvironmentList: React.FC = () => {
|
|||||||
filtered: false,
|
filtered: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '部署方式',
|
title: '部署类型',
|
||||||
dataIndex: 'deployType',
|
dataIndex: 'deployType',
|
||||||
width: 180,
|
width: 120,
|
||||||
render: (deployType) => {
|
render: (deployType) => {
|
||||||
if (!deployType) return '-';
|
|
||||||
const typeInfo = getDeployTypeInfo(deployType as DeployTypeEnum);
|
const typeInfo = getDeployTypeInfo(deployType as DeployTypeEnum);
|
||||||
return renderTag(typeInfo.icon, typeInfo.label, typeInfo.color);
|
return (
|
||||||
|
<Tag color={typeInfo.color}>
|
||||||
|
<Space>
|
||||||
|
{typeInfo.icon}
|
||||||
|
{typeInfo.label}
|
||||||
|
</Space>
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
filters: [
|
filters: [
|
||||||
{text: 'Kubernetes集群部署', value: DeployTypeEnum.K8S},
|
{text: 'Kubernetes集群部署', value: DeployTypeEnum.K8S},
|
||||||
@ -109,11 +113,19 @@ const EnvironmentList: React.FC = () => {
|
|||||||
filterMode: 'menu',
|
filterMode: 'menu',
|
||||||
filtered: false,
|
filtered: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: '状态',
|
||||||
|
dataIndex: 'enabled',
|
||||||
|
width: 100,
|
||||||
|
valueEnum: {
|
||||||
|
true: {text: '启用', status: 'Success'},
|
||||||
|
false: {text: '禁用', status: 'Default'},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '排序',
|
title: '排序',
|
||||||
dataIndex: 'sort',
|
dataIndex: 'sort',
|
||||||
width: 80,
|
width: 80,
|
||||||
align: 'center',
|
|
||||||
sorter: true,
|
sorter: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -122,75 +134,63 @@ const EnvironmentList: React.FC = () => {
|
|||||||
key: 'action',
|
key: 'action',
|
||||||
valueType: 'option',
|
valueType: 'option',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
align: 'center',
|
render: (_, record) => [
|
||||||
render: (_, record) => (
|
<Button
|
||||||
<div style={{ display: 'flex', gap: '8px', justifyContent: 'center' }}>
|
key="edit"
|
||||||
|
type="link"
|
||||||
|
onClick={() => handleEdit(record)}
|
||||||
|
>
|
||||||
|
<Space>
|
||||||
|
<EditOutlined/>
|
||||||
|
编辑
|
||||||
|
</Space>
|
||||||
|
</Button>,
|
||||||
|
<Popconfirm
|
||||||
|
key="delete"
|
||||||
|
title="确定要删除该环境吗?"
|
||||||
|
description="删除后将无法恢复,请谨慎操作"
|
||||||
|
onConfirm={() => handleDelete(record.id)}
|
||||||
|
>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
size="small"
|
danger
|
||||||
style={{ padding: 0 }}
|
|
||||||
onClick={() => handleEdit(record)}
|
|
||||||
>
|
>
|
||||||
<EditOutlined /> 编辑
|
<Space>
|
||||||
|
<DeleteOutlined/>
|
||||||
|
删除
|
||||||
|
</Space>
|
||||||
</Button>
|
</Button>
|
||||||
<Popconfirm
|
</Popconfirm>
|
||||||
title="确定要删除该环境吗?"
|
],
|
||||||
description="删除后将无法恢复,请谨慎操作"
|
|
||||||
onConfirm={() => handleDelete(record.id)}
|
|
||||||
>
|
|
||||||
<Button
|
|
||||||
type="link"
|
|
||||||
size="small"
|
|
||||||
danger
|
|
||||||
style={{ padding: 0 }}
|
|
||||||
>
|
|
||||||
<DeleteOutlined /> 删除
|
|
||||||
</Button>
|
|
||||||
</Popconfirm>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<PageContainer>
|
||||||
<ProTable<Environment>
|
<ProTable<Environment>
|
||||||
columns={columns}
|
columns={columns}
|
||||||
actionRef={actionRef}
|
actionRef={actionRef}
|
||||||
scroll={{x: 'max-content'}}
|
scroll={{x: 'max-content'}}
|
||||||
cardBordered
|
cardBordered
|
||||||
request={async (params) => {
|
|
||||||
const queryParams: EnvironmentQueryParams = {
|
|
||||||
pageSize: params.pageSize,
|
|
||||||
pageNum: params.current,
|
|
||||||
envCode: params.envCode as string,
|
|
||||||
envName: params.envName as string,
|
|
||||||
buildType: params.buildType as BuildTypeEnum,
|
|
||||||
deployType: params.deployType as DeployTypeEnum,
|
|
||||||
};
|
|
||||||
const data = await getEnvironmentPage(queryParams);
|
|
||||||
return {
|
|
||||||
data: data.content || [],
|
|
||||||
success: true,
|
|
||||||
total: data.totalElements || 0,
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
search={{
|
search={false}
|
||||||
labelWidth: 'auto',
|
|
||||||
span: {
|
|
||||||
xs: 24,
|
|
||||||
sm: 12,
|
|
||||||
md: 8,
|
|
||||||
lg: 6,
|
|
||||||
xl: 6,
|
|
||||||
xxl: 6,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
options={{
|
options={{
|
||||||
setting: {
|
setting: false,
|
||||||
listsHeight: 400,
|
density: false,
|
||||||
},
|
fullScreen: false,
|
||||||
|
reload: false,
|
||||||
|
}}
|
||||||
|
toolbar={{
|
||||||
|
actions: [
|
||||||
|
<Button
|
||||||
|
key="add"
|
||||||
|
type="primary"
|
||||||
|
onClick={handleAdd}
|
||||||
|
icon={<PlusOutlined/>}
|
||||||
|
>
|
||||||
|
新建环境
|
||||||
|
</Button>
|
||||||
|
],
|
||||||
}}
|
}}
|
||||||
form={{
|
form={{
|
||||||
syncToUrl: true,
|
syncToUrl: true,
|
||||||
@ -199,29 +199,42 @@ const EnvironmentList: React.FC = () => {
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
showQuickJumper: true,
|
showQuickJumper: true,
|
||||||
}}
|
}}
|
||||||
dateFormatter="string"
|
request={async (params) => {
|
||||||
toolBarRender={() => [
|
try {
|
||||||
<Button
|
const queryParams: EnvironmentQueryParams = {
|
||||||
key="add"
|
pageSize: params.pageSize,
|
||||||
type="primary"
|
pageNum: params.current,
|
||||||
onClick={handleAdd}
|
envCode: params.envCode as string,
|
||||||
icon={<PlusOutlined/>}
|
envName: params.envName as string,
|
||||||
>
|
buildType: params.buildType as BuildTypeEnum,
|
||||||
新建环境
|
deployType: params.deployType as DeployTypeEnum,
|
||||||
</Button>,
|
};
|
||||||
]}
|
const data = await getEnvironmentPage(queryParams);
|
||||||
|
return {
|
||||||
|
data: data.content || [],
|
||||||
|
success: true,
|
||||||
|
total: data.totalElements || 0,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
messageApi.error('获取环境列表失败');
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
success: false,
|
||||||
|
total: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<EnvironmentModal
|
{modalVisible && (
|
||||||
visible={modalVisible}
|
<EnvironmentModal
|
||||||
onCancel={() => setModalVisible(false)}
|
open={modalVisible}
|
||||||
onSuccess={() => {
|
onCancel={handleModalClose}
|
||||||
setModalVisible(false);
|
onSuccess={handleSuccess}
|
||||||
actionRef.current?.reload();
|
initialValues={currentEnvironment}
|
||||||
}}
|
/>
|
||||||
initialValues={currentEnvironment}
|
)}
|
||||||
/>
|
</PageContainer>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,87 +1,73 @@
|
|||||||
import React, {useEffect} from 'react';
|
import React, {useState} from 'react';
|
||||||
import {Modal, Form, Input, InputNumber, Radio, message} from 'antd';
|
import {Modal, Form, Input, Select, Switch, InputNumber, App} from 'antd';
|
||||||
import type {ProjectGroup} from '../types';
|
import type {ProjectGroup} from '../types';
|
||||||
import {createProjectGroup, updateProjectGroup} from '../service';
|
|
||||||
import {ProjectGroupTypeEnum} from '../types';
|
import {ProjectGroupTypeEnum} from '../types';
|
||||||
|
import {createProjectGroup, updateProjectGroup} from '../service';
|
||||||
|
|
||||||
interface ProjectGroupModalProps {
|
interface ProjectGroupModalProps {
|
||||||
visible: boolean;
|
open: boolean;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onSuccess: () => void;
|
onSuccess: () => void;
|
||||||
initialValues?: ProjectGroup;
|
initialValues?: ProjectGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ProjectGroupModal: React.FC<ProjectGroupModalProps> = ({
|
const ProjectGroupModal: React.FC<ProjectGroupModalProps> = ({
|
||||||
visible,
|
open,
|
||||||
onCancel,
|
onCancel,
|
||||||
onSuccess,
|
onSuccess,
|
||||||
initialValues,
|
initialValues,
|
||||||
}) => {
|
}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const isEdit = !!initialValues;
|
const [loading, setLoading] = useState(false);
|
||||||
|
const {message: messageApi} = App.useApp();
|
||||||
useEffect(() => {
|
const isEdit = !!initialValues?.id;
|
||||||
if (visible) {
|
|
||||||
if (initialValues) {
|
|
||||||
// 将布尔值转换为字符串
|
|
||||||
form.setFieldsValue({
|
|
||||||
...initialValues,
|
|
||||||
enabled: initialValues.enabled?.toString()
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
form.setFieldsValue({
|
|
||||||
type: ProjectGroupTypeEnum.PROJECT,
|
|
||||||
enabled: 'true',
|
|
||||||
sort: 0
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [visible, initialValues, form]);
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
try {
|
try {
|
||||||
|
setLoading(true);
|
||||||
const values = await form.validateFields();
|
const values = await form.validateFields();
|
||||||
// 将字符串转换回布尔值
|
|
||||||
const submitData = {
|
|
||||||
...values,
|
|
||||||
enabled: values.enabled === 'true'
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isEdit) {
|
if (isEdit) {
|
||||||
await updateProjectGroup({...submitData, id: initialValues?.id});
|
await updateProjectGroup({
|
||||||
message.success('更新成功');
|
...values,
|
||||||
|
id: initialValues.id,
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
await createProjectGroup(submitData);
|
await createProjectGroup(values);
|
||||||
message.success('创建成功');
|
|
||||||
}
|
}
|
||||||
onSuccess();
|
messageApi.success(`${isEdit ? '更新' : '创建'}成功`);
|
||||||
onCancel();
|
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
|
onSuccess();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error(isEdit ? '更新失败' : '创建失败');
|
if (error instanceof Error) {
|
||||||
|
messageApi.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
|
||||||
|
} else {
|
||||||
|
messageApi.error(`${isEdit ? '更新' : '创建'}失败`);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancel = () => {
|
|
||||||
form.resetFields();
|
|
||||||
onCancel();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={isEdit ? '编辑项目组' : '新建项目组'}
|
title={`${isEdit ? '编辑' : '新建'}项目组`}
|
||||||
open={visible}
|
open={open}
|
||||||
|
onCancel={() => {
|
||||||
|
form.resetFields();
|
||||||
|
onCancel();
|
||||||
|
}}
|
||||||
onOk={handleSubmit}
|
onOk={handleSubmit}
|
||||||
onCancel={handleCancel}
|
confirmLoading={loading}
|
||||||
|
maskClosable={false}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
>
|
>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
layout="vertical"
|
layout="vertical"
|
||||||
initialValues={{
|
initialValues={{
|
||||||
type: ProjectGroupTypeEnum.PROJECT,
|
enabled: true,
|
||||||
enabled: 'true',
|
sort: 0,
|
||||||
sort: 0
|
...initialValues,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@ -89,55 +75,76 @@ const ProjectGroupModal: React.FC<ProjectGroupModalProps> = ({
|
|||||||
label="项目组编码"
|
label="项目组编码"
|
||||||
rules={[
|
rules={[
|
||||||
{required: true, message: '请输入项目组编码'},
|
{required: true, message: '请输入项目组编码'},
|
||||||
{pattern: /^[A-Za-z0-9_-]+$/, message: '项目组编码只能包含字母、数字、下划线和连字符'}
|
{max: 50, message: '项目组编码不能超过50个字符'},
|
||||||
]}
|
]}
|
||||||
|
tooltip="项目组的唯一标识,创建后不可修改"
|
||||||
>
|
>
|
||||||
<Input placeholder="请输入项目组编码" disabled={isEdit}/>
|
<Input
|
||||||
|
placeholder="请输入项目组编码"
|
||||||
|
disabled={isEdit}
|
||||||
|
maxLength={50}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="projectGroupName"
|
name="projectGroupName"
|
||||||
label="项目组名称"
|
label="项目组名称"
|
||||||
rules={[{required: true, message: '请输入项目组名称'}]}
|
rules={[
|
||||||
|
{required: true, message: '请输入项目组名称'},
|
||||||
|
{max: 50, message: '项目组名称不能超过50个字符'},
|
||||||
|
]}
|
||||||
|
tooltip="项目组的显示名称"
|
||||||
>
|
>
|
||||||
<Input placeholder="请输入项目组名称"/>
|
<Input
|
||||||
</Form.Item>
|
placeholder="请输入项目组名称"
|
||||||
|
maxLength={50}
|
||||||
<Form.Item
|
/>
|
||||||
name="projectGroupDesc"
|
|
||||||
label="项目组描述"
|
|
||||||
>
|
|
||||||
<Input.TextArea rows={4} placeholder="请输入项目组描述"/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="type"
|
name="type"
|
||||||
label="项目组类型"
|
label="项目组类型"
|
||||||
rules={[{required: true, message: '请选择项目组类型'}]}
|
rules={[{required: true, message: '请选择项目组类型'}]}
|
||||||
|
tooltip="项目组的类型,创建后不可修改"
|
||||||
>
|
>
|
||||||
<Radio.Group>
|
<Select
|
||||||
<Radio value={ProjectGroupTypeEnum.PRODUCT}>产品型</Radio>
|
placeholder="请选择项目组类型"
|
||||||
<Radio value={ProjectGroupTypeEnum.PROJECT}>项目型</Radio>
|
disabled={isEdit}
|
||||||
</Radio.Group>
|
>
|
||||||
|
<Select.Option value={ProjectGroupTypeEnum.PRODUCT}>产品型</Select.Option>
|
||||||
|
<Select.Option value={ProjectGroupTypeEnum.PROJECT}>项目型</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
name="projectGroupDesc"
|
||||||
|
label="项目组描述"
|
||||||
|
rules={[{max: 200, message: '项目组描述不能超过200个字符'}]}
|
||||||
|
tooltip="项目组的详细描述信息"
|
||||||
|
>
|
||||||
|
<Input.TextArea
|
||||||
|
placeholder="请输入项目组描述"
|
||||||
|
maxLength={200}
|
||||||
|
showCount
|
||||||
|
rows={4}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="enabled"
|
name="enabled"
|
||||||
label="项目组状态"
|
label="状态"
|
||||||
rules={[{required: true, message: '请选择项目组状态'}]}
|
valuePropName="checked"
|
||||||
|
tooltip="是否启用该项目组"
|
||||||
>
|
>
|
||||||
<Radio.Group>
|
<Switch checkedChildren="启用" unCheckedChildren="禁用"/>
|
||||||
<Radio value="true">启用</Radio>
|
|
||||||
<Radio value="false">禁用</Radio>
|
|
||||||
</Radio.Group>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="sort"
|
name="sort"
|
||||||
label="排序"
|
label="排序"
|
||||||
rules={[{required: true, message: '请输入排序值'}]}
|
tooltip="数字越小越靠前"
|
||||||
>
|
>
|
||||||
<InputNumber min={0} placeholder="请输入排序值" style={{width: '100%'}}/>
|
<InputNumber min={0} style={{width: '100%'}}/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, {useState} from 'react';
|
import React, {useState} from 'react';
|
||||||
import {PageContainer} from '@ant-design/pro-layout';
|
import {PageContainer} from '@ant-design/pro-layout';
|
||||||
import {Button, message, Popconfirm, Space, Tag, Tooltip} from 'antd';
|
import {Button, Space, Popconfirm, Tag, App} from 'antd';
|
||||||
import {
|
import {
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
EditOutlined,
|
EditOutlined,
|
||||||
@ -20,14 +20,15 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
const [modalVisible, setModalVisible] = useState(false);
|
const [modalVisible, setModalVisible] = useState(false);
|
||||||
const [currentProject, setCurrentProject] = useState<ProjectGroup>();
|
const [currentProject, setCurrentProject] = useState<ProjectGroup>();
|
||||||
const actionRef = React.useRef<ActionType>();
|
const actionRef = React.useRef<ActionType>();
|
||||||
|
const {message: messageApi} = App.useApp();
|
||||||
|
|
||||||
const handleDelete = async (id: number) => {
|
const handleDelete = async (id: number) => {
|
||||||
try {
|
try {
|
||||||
await deleteProjectGroup(id);
|
await deleteProjectGroup(id);
|
||||||
message.success('删除成功');
|
messageApi.success('删除成功');
|
||||||
actionRef.current?.reload();
|
actionRef.current?.reload();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('删除失败');
|
messageApi.error('删除失败');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,6 +42,17 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
setModalVisible(true);
|
setModalVisible(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleModalClose = () => {
|
||||||
|
setModalVisible(false);
|
||||||
|
setCurrentProject(undefined);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSuccess = () => {
|
||||||
|
setModalVisible(false);
|
||||||
|
setCurrentProject(undefined);
|
||||||
|
actionRef.current?.reload();
|
||||||
|
};
|
||||||
|
|
||||||
const columns: ProColumns<ProjectGroup>[] = [
|
const columns: ProColumns<ProjectGroup>[] = [
|
||||||
{
|
{
|
||||||
title: '项目组编码',
|
title: '项目组编码',
|
||||||
@ -97,12 +109,10 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
dataIndex: 'environments',
|
dataIndex: 'environments',
|
||||||
width: 100,
|
width: 100,
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Tooltip title="环境数量">
|
<Space>
|
||||||
<Space>
|
<EnvironmentOutlined/>
|
||||||
<EnvironmentOutlined/>
|
{record?.totalEnvironments || 0}
|
||||||
{record?.totalEnvironments || 0}
|
</Space>
|
||||||
</Space>
|
|
||||||
</Tooltip>
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -110,12 +120,10 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
dataIndex: 'applications',
|
dataIndex: 'applications',
|
||||||
width: 100,
|
width: 100,
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<Tooltip title="项目数量">
|
<Space>
|
||||||
<Space>
|
<TeamOutlined/>
|
||||||
<TeamOutlined/>
|
{record?.totalApplications || 0}
|
||||||
{record?.totalApplications || 0}
|
</Space>
|
||||||
</Space>
|
|
||||||
</Tooltip>
|
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -126,26 +134,20 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
width: 280,
|
width: 180,
|
||||||
key: 'action',
|
key: 'action',
|
||||||
valueType: 'option',
|
valueType: 'option',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
align: 'center',
|
|
||||||
render: (_, record) => [
|
render: (_, record) => [
|
||||||
<Button
|
<Button
|
||||||
key="edit"
|
key="edit"
|
||||||
type="link"
|
type="link"
|
||||||
icon={<EditOutlined/>}
|
|
||||||
onClick={() => handleEdit(record)}
|
onClick={() => handleEdit(record)}
|
||||||
>
|
>
|
||||||
编辑
|
<Space>
|
||||||
</Button>,
|
<EditOutlined/>
|
||||||
<Button
|
编辑
|
||||||
key="bind"
|
</Space>
|
||||||
type="link"
|
|
||||||
icon={<EnvironmentOutlined/>}
|
|
||||||
>
|
|
||||||
环境绑定
|
|
||||||
</Button>,
|
</Button>,
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
key="delete"
|
key="delete"
|
||||||
@ -156,9 +158,11 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
danger
|
danger
|
||||||
icon={<DeleteOutlined/>}
|
|
||||||
>
|
>
|
||||||
删除
|
<Space>
|
||||||
|
<DeleteOutlined/>
|
||||||
|
删除
|
||||||
|
</Space>
|
||||||
</Button>
|
</Button>
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
],
|
],
|
||||||
@ -166,74 +170,75 @@ const ProjectGroupList: React.FC = () => {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<PageContainer>
|
||||||
<ProTable<ProjectGroup>
|
<ProTable<ProjectGroup>
|
||||||
columns={columns}
|
columns={columns}
|
||||||
actionRef={actionRef}
|
actionRef={actionRef}
|
||||||
scroll={{ x: 'max-content' }}
|
scroll={{x: 'max-content'}}
|
||||||
cardBordered
|
cardBordered
|
||||||
request={async (params) => {
|
|
||||||
const queryParams: ProjectGroupQueryParams = {
|
|
||||||
pageSize: params.pageSize,
|
|
||||||
pageNum: params.current,
|
|
||||||
projectGroupName: params.projectGroupName as string,
|
|
||||||
projectGroupCode: params.projectGroupCode as string,
|
|
||||||
enabled: params.enabled as boolean,
|
|
||||||
};
|
|
||||||
const data = await getProjectGroupPage(queryParams);
|
|
||||||
return {
|
|
||||||
data: data.content || [],
|
|
||||||
success: true,
|
|
||||||
total: data.totalElements || 0,
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
search={{
|
search={false}
|
||||||
labelWidth: 'auto',
|
|
||||||
span: {
|
|
||||||
xs: 24,
|
|
||||||
sm: 12,
|
|
||||||
md: 8,
|
|
||||||
lg: 6,
|
|
||||||
xl: 6,
|
|
||||||
xxl: 6,
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
options={{
|
options={{
|
||||||
setting: {
|
setting: false,
|
||||||
listsHeight: 400,
|
density: false,
|
||||||
},
|
fullScreen: false,
|
||||||
|
reload: false,
|
||||||
|
}}
|
||||||
|
toolbar={{
|
||||||
|
actions: [
|
||||||
|
<Button
|
||||||
|
key="add"
|
||||||
|
type="primary"
|
||||||
|
onClick={handleAdd}
|
||||||
|
icon={<PlusOutlined/>}
|
||||||
|
>
|
||||||
|
新建项目组
|
||||||
|
</Button>
|
||||||
|
],
|
||||||
}}
|
}}
|
||||||
form={{
|
form={{
|
||||||
syncToUrl: true,
|
syncToUrl: true,
|
||||||
|
ignoreRules: false,
|
||||||
}}
|
}}
|
||||||
pagination={{
|
pagination={{
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
showQuickJumper: true,
|
showQuickJumper: true,
|
||||||
}}
|
}}
|
||||||
dateFormatter="string"
|
request={async (params) => {
|
||||||
toolBarRender={() => [
|
try {
|
||||||
<Button
|
const queryParams: ProjectGroupQueryParams = {
|
||||||
key="add"
|
pageSize: params.pageSize,
|
||||||
type="primary"
|
pageNum: params.current,
|
||||||
onClick={handleAdd}
|
projectGroupName: params.projectGroupName as string,
|
||||||
icon={<PlusOutlined/>}
|
projectGroupCode: params.projectGroupCode as string,
|
||||||
>
|
enabled: params.enabled as boolean,
|
||||||
新建项目组
|
};
|
||||||
</Button>,
|
const data = await getProjectGroupPage(queryParams);
|
||||||
]}
|
return {
|
||||||
|
data: data.content || [],
|
||||||
|
success: true,
|
||||||
|
total: data.totalElements || 0,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
messageApi.error('获取项目组列表失败');
|
||||||
|
return {
|
||||||
|
data: [],
|
||||||
|
success: false,
|
||||||
|
total: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProjectGroupModal
|
{modalVisible && (
|
||||||
visible={modalVisible}
|
<ProjectGroupModal
|
||||||
onCancel={() => setModalVisible(false)}
|
open={modalVisible}
|
||||||
onSuccess={() => {
|
onCancel={handleModalClose}
|
||||||
setModalVisible(false);
|
onSuccess={handleSuccess}
|
||||||
actionRef.current?.reload();
|
initialValues={currentProject}
|
||||||
}}
|
/>
|
||||||
initialValues={currentProject}
|
)}
|
||||||
/>
|
</PageContainer>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user