This commit is contained in:
asp_ly 2024-12-26 22:44:51 +08:00
parent b7d77c8033
commit dbbabdcca4
2 changed files with 100 additions and 117 deletions

View File

@ -1,4 +1,4 @@
import React, {useEffect, useState} 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} 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';
@ -8,11 +8,12 @@ import {BetaSchemaForm} from '@ant-design/pro-form';
import {convertJsonSchemaToColumns} from '@/utils/jsonSchemaUtils'; import {convertJsonSchemaToColumns} from '@/utils/jsonSchemaUtils';
import './styles.less'; import './styles.less';
import {Editor} from '@/components/Editor'; import {Editor} from '@/components/Editor';
import type {JsonNode} from '@/types/common';
const {Option} = Select; const {Option} = Select;
interface DeploymentConfigModalProps { interface DeploymentConfigModalProps {
visible: boolean; open: boolean;
onCancel: () => void; onCancel: () => void;
onSuccess: () => void; onSuccess: () => void;
initialValues?: DeploymentConfig; initialValues?: DeploymentConfig;
@ -20,7 +21,7 @@ interface DeploymentConfigModalProps {
} }
const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
visible, open,
onCancel, onCancel,
onSuccess, onSuccess,
initialValues, initialValues,
@ -31,39 +32,40 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
const [templates, setTemplates] = useState<DeployConfigTemplate[]>([]); const [templates, setTemplates] = useState<DeployConfigTemplate[]>([]);
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 isEdit = !!initialValues?.id; const isEdit = !!initialValues?.id;
// 获取应用列表 // 获取应用列表
const fetchApplications = async () => { const fetchApplications = useCallback(async () => {
try { try {
const data = await getApplicationList(); const data = await getApplicationList();
setApplications(data); setApplications(data);
} catch (error) { } catch (error) {
message.error('获取应用列表失败'); message.error('获取应用列表失败');
} }
}; }, []);
// 获取配置模板 // 获取配置模板
const fetchTemplates = async () => { const fetchTemplates = useCallback(async () => {
try { try {
const data = await getDeployConfigTemplates(); const data = await getDeployConfigTemplates();
setTemplates(data); setTemplates(data);
} catch (error) { } catch (error) {
message.error('获取配置模板失败'); message.error('获取配置模板失败');
} }
}; }, []);
// 在模态框显示时获取数据 // 在模态框显示时获取数据
useEffect(() => { useEffect(() => {
if (visible) { if (open) {
fetchApplications(); fetchApplications();
fetchTemplates(); fetchTemplates();
} }
}, [visible]); }, [open, fetchApplications, fetchTemplates]);
// 初始化表单数据 // 初始化表单数据
useEffect(() => { useEffect(() => {
if (!visible) return; if (!open) return;
if (initialValues) { if (initialValues) {
form.setFieldsValue(initialValues); form.setFieldsValue(initialValues);
@ -82,9 +84,9 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
setSelectedTemplate(undefined); setSelectedTemplate(undefined);
setBuildVariables({}); setBuildVariables({});
} }
}, [visible, initialValues, envId, form, templates]); }, [open, initialValues, envId, form, templates]);
const handleAppChange = (appId: number) => { const handleAppChange = useCallback((appId: number) => {
const app = applications.find(a => a.id === appId); const app = applications.find(a => a.id === appId);
if (app) { if (app) {
const template = templates.find(t => t.languageType === app.language); const template = templates.find(t => t.languageType === app.language);
@ -94,10 +96,11 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
form.setFieldValue('templateCode', template.code); form.setFieldValue('templateCode', template.code);
} }
} }
}; }, [applications, templates, form]);
const handleSubmit = async () => { const handleSubmit = async () => {
try { try {
setLoading(true);
const values = await form.validateFields(); const values = await form.validateFields();
const submitData = { const submitData = {
...values, ...values,
@ -116,13 +119,19 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
form.resetFields(); form.resetFields();
onSuccess(); onSuccess();
} catch (error) { } catch (error) {
if (error instanceof Error) {
message.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
} else {
message.error(`${isEdit ? '更新' : '创建'}失败`); message.error(`${isEdit ? '更新' : '创建'}失败`);
} }
} finally {
setLoading(false);
}
}; };
// 渲染表单项 // 渲染表单项
const renderFormItems = () => { const renderFormItems = () => {
if (!selectedTemplate?.buildVariablesSchema) return null; if (!selectedTemplate?.buildVariablesSchema?.properties) return null;
const { properties } = selectedTemplate.buildVariablesSchema; const { properties } = selectedTemplate.buildVariablesSchema;
@ -142,10 +151,10 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
defaultLanguage={property.editorConfig.language || 'shell'} defaultLanguage={property.editorConfig.language || 'shell'}
theme={property.editorConfig.theme || 'vs-dark'} theme={property.editorConfig.theme || 'vs-dark'}
value={buildVariables[key] || property.default || ''} value={buildVariables[key] || property.default || ''}
onChange={(value) => setBuildVariables({ onChange={(value: string) => setBuildVariables(prev => ({
...buildVariables, ...prev,
[key]: value || '' [key]: value || ''
})} }))}
options={{ options={{
minimap: { enabled: property.editorConfig.minimap ?? false }, minimap: { enabled: property.editorConfig.minimap ?? false },
fontSize: property.editorConfig.fontSize || 14, fontSize: property.editorConfig.fontSize || 14,
@ -186,15 +195,15 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
columns={convertJsonSchemaToColumns({ columns={convertJsonSchemaToColumns({
type: 'object', type: 'object',
properties: Object.fromEntries( properties: Object.fromEntries(
Object.entries(properties).filter(([_, prop]) => !prop.editorConfig) Object.entries(properties || {}).filter(([_, prop]) => !prop.editorConfig)
), ),
required: selectedTemplate.buildVariablesSchema.required || [] required: selectedTemplate.buildVariablesSchema.required || []
})} })}
initialValues={buildVariables} initialValues={buildVariables}
onValuesChange={(_, values) => setBuildVariables({ onValuesChange={(_, values) => setBuildVariables(prev => ({
...buildVariables, ...prev,
...values ...values
})} }))}
/> />
</> </>
); );
@ -203,7 +212,7 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
return ( return (
<Modal <Modal
title={`${isEdit ? '编辑' : '新建'}部署配置`} title={`${isEdit ? '编辑' : '新建'}部署配置`}
open={visible} open={open}
onCancel={() => { onCancel={() => {
form.resetFields(); form.resetFields();
onCancel(); onCancel();
@ -212,6 +221,8 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
width={800} width={800}
className="deployment-config-modal" className="deployment-config-modal"
maskClosable={false} maskClosable={false}
confirmLoading={loading}
destroyOnClose
> >
<Form <Form
form={form} form={form}
@ -251,6 +262,7 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
name="enabled" name="enabled"
label="状态" label="状态"
valuePropName="checked" valuePropName="checked"
tooltip="是否启用该配置"
> >
<Switch checkedChildren="启用" unCheckedChildren="禁用" /> <Switch checkedChildren="启用" unCheckedChildren="禁用" />
</Form.Item> </Form.Item>
@ -258,15 +270,9 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
<Form.Item <Form.Item
name="sort" name="sort"
label="排序" label="排序"
required
tooltip="数字越小越靠前" tooltip="数字越小越靠前"
> >
<InputNumber <InputNumber min={0} style={{ width: '100%' }} />
min={0}
max={999}
style={{ width: '100%' }}
placeholder="请输入排序号"
/>
</Form.Item> </Form.Item>
</Form> </Form>
</Modal> </Modal>

View File

@ -1,6 +1,6 @@
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, Select} from 'antd'; import {Button, message, Popconfirm, Select, Space} from 'antd';
import {PlusOutlined, EditOutlined, DeleteOutlined} from '@ant-design/icons'; import {PlusOutlined, EditOutlined, DeleteOutlined} from '@ant-design/icons';
import {getDeploymentConfigPage, deleteDeploymentConfig} from './service'; import {getDeploymentConfigPage, deleteDeploymentConfig} from './service';
import {getEnvironmentList} from '../../Environment/List/service'; import {getEnvironmentList} from '../../Environment/List/service';
@ -65,12 +65,15 @@ const DeploymentConfigList: React.FC = () => {
actionRef.current?.reload(); actionRef.current?.reload();
}; };
const renderResourceInfo = (resources?: { cpu?: string; memory?: string }) => { const handleModalClose = () => {
if (!resources?.cpu && !resources?.memory) return '-'; setModalVisible(false);
const items = []; setCurrentConfig(undefined);
if (resources.cpu) items.push(`CPU: ${resources.cpu}`); };
if (resources.memory) items.push(`内存: ${resources.memory}`);
return items.join(' / '); const handleSuccess = () => {
setModalVisible(false);
setCurrentConfig(undefined);
actionRef.current?.reload();
}; };
const columns: ProColumns<DeploymentConfig>[] = [ const columns: ProColumns<DeploymentConfig>[] = [
@ -105,56 +108,31 @@ const DeploymentConfigList: React.FC = () => {
}, },
], ],
}, },
{
title: '部署配置',
children: [
{
title: '副本数',
dataIndex: ['deployConfig', 'replicas'],
width: 100,
align: 'center',
},
{
title: '容器端口',
dataIndex: ['deployConfig', 'containerPort'],
width: 100,
align: 'center',
},
],
},
{ {
title: '状态', title: '状态',
dataIndex: 'enabled', dataIndex: 'enabled',
width: 100, width: 100,
align: 'center',
valueEnum: { valueEnum: {
true: {text: '启用', status: 'Success'}, true: {text: '启用', status: 'Success'},
false: {text: '禁用', status: 'Default'}, false: {text: '禁用', status: 'Default'},
}, },
}, },
{
title: '排序',
dataIndex: 'sort',
width: 80,
align: 'center',
sorter: true,
},
{ {
title: '操作', title: '操作',
width: 180, width: 180,
key: 'action', key: 'action',
valueType: 'option', valueType: 'option',
fixed: 'right', fixed: 'right',
align: 'center', render: (_, record) => [
render: (_, record) => {
const buttons = [
<Button <Button
key="edit" key="edit"
type="link" type="link"
size="small"
onClick={() => handleEdit(record)} onClick={() => handleEdit(record)}
> >
<EditOutlined/> <Space>
<EditOutlined />
</Space>
</Button>, </Button>,
<Popconfirm <Popconfirm
key="delete" key="delete"
@ -164,15 +142,15 @@ const DeploymentConfigList: React.FC = () => {
> >
<Button <Button
type="link" type="link"
size="small"
danger danger
> >
<DeleteOutlined/> <Space>
<DeleteOutlined />
</Space>
</Button> </Button>
</Popconfirm> </Popconfirm>
]; ],
return <div style={{display: 'flex', gap: '8px', justifyContent: 'center'}}>{buttons}</div>;
},
}, },
]; ];
@ -202,6 +180,31 @@ const DeploymentConfigList: React.FC = () => {
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={!selectedEnvId}
>
</Button>
],
}}
pagination={{
pageSize: 10,
showQuickJumper: true,
}}
request={async (params) => { request={async (params) => {
if (!selectedEnvId) { if (!selectedEnvId) {
return { return {
@ -223,39 +226,13 @@ const DeploymentConfigList: React.FC = () => {
total: data.totalElements || 0, total: data.totalElements || 0,
}; };
}} }}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 10,
showQuickJumper: true,
}}
dateFormatter="string"
toolBarRender={() => [
<Button
key="add"
type="primary"
onClick={handleAdd}
icon={<PlusOutlined/>}
disabled={!selectedEnvId}
>
</Button>,
]}
/> />
{selectedEnvId && ( {modalVisible && selectedEnvId && (
<DeploymentConfigModal <DeploymentConfigModal
visible={modalVisible} open={modalVisible}
onCancel={() => setModalVisible(false)} onCancel={handleModalClose}
onSuccess={() => { onSuccess={handleSuccess}
setModalVisible(false);
actionRef.current?.reload();
}}
initialValues={currentConfig} initialValues={currentConfig}
envId={selectedEnvId} envId={selectedEnvId}
/> />