This commit is contained in:
dengqichen 2024-12-27 09:54:04 +08:00
parent 959ff9cc3b
commit 578e375f10
8 changed files with 102 additions and 99 deletions

View File

@ -1,15 +1,13 @@
import React from 'react';
import { RouterProvider } from 'react-router-dom';
import { ConfigProvider, App as AntdApp } from 'antd';
import { ConfigProvider } from 'antd';
import zhCN from 'antd/locale/zh_CN';
import router from './router';
const App: React.FC = () => {
return (
<ConfigProvider locale={zhCN}>
<AntdApp>
<RouterProvider router={router} />
</AntdApp>
<RouterProvider router={router} />
</ConfigProvider>
);
};

View File

@ -1,5 +1,5 @@
import React, {useState} from 'react';
import {Modal, Form, Input, Select, Switch, InputNumber, App} from 'antd';
import {Modal, Form, Input, Select, Switch, InputNumber, message} from 'antd';
import type {Application} from '../types';
import {DevelopmentLanguageTypeEnum} from '../types';
import {createApplication, updateApplication} from '../service';
@ -21,7 +21,6 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
}) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const {message: messageApi} = App.useApp();
const isEdit = !!initialValues?.id;
const handleSubmit = async () => {
@ -39,14 +38,14 @@ const ApplicationModal: React.FC<ApplicationModalProps> = ({
projectGroupId,
});
}
messageApi.success(`${isEdit ? '更新' : '创建'}成功`);
message.success(`${isEdit ? '更新' : '创建'}成功`);
form.resetFields();
onSuccess();
} catch (error) {
if (error instanceof Error) {
messageApi.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
message.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
} else {
messageApi.error(`${isEdit ? '更新' : '创建'}失败`);
message.error(`${isEdit ? '更新' : '创建'}失败`);
}
} finally {
setLoading(false);

View File

@ -1,5 +1,5 @@
import React, {useEffect, useState, useCallback} from 'react';
import {Modal, Form, Select, message, Switch, InputNumber, App} from 'antd';
import {Modal, Form, Select, message, Switch, InputNumber, Input} from 'antd';
import type {DeploymentConfig, DeployConfigTemplate} from '../types';
import {createDeploymentConfig, updateDeploymentConfig, getDeployConfigTemplates} from '../service';
import {getApplicationList} from '../../../Application/List/service';
@ -31,9 +31,8 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
const [applications, setApplications] = useState<Application[]>([]);
const [templates, setTemplates] = useState<DeployConfigTemplate[]>([]);
const [selectedTemplate, setSelectedTemplate] = useState<DeployConfigTemplate>();
const [buildVariables, setBuildVariables] = useState<Record<string, any>>({});
const [buildVariables, setBuildVariables] = useState<JsonNode>({});
const [loading, setLoading] = useState(false);
const {message: messageApi} = App.useApp();
const isEdit = !!initialValues?.id;
// 获取应用列表
@ -42,9 +41,9 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
const data = await getApplicationList();
setApplications(data);
} catch (error) {
messageApi.error('获取应用列表失败');
message.error('获取应用列表失败');
}
}, [messageApi]);
}, []);
// 获取配置模板
const fetchTemplates = useCallback(async () => {
@ -52,9 +51,9 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
const data = await getDeployConfigTemplates();
setTemplates(data);
} catch (error) {
messageApi.error('获取配置模板失败');
message.error('获取配置模板失败');
}
}, [messageApi]);
}, []);
// 在模态框显示时获取数据
useEffect(() => {
@ -69,8 +68,13 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
if (!open) return;
if (initialValues) {
form.setFieldsValue(initialValues);
const template = templates.find(t => t.code === initialValues.templateCode);
// 设置基础字段
form.setFieldsValue({
applicationId: initialValues.applicationId,
enabled: initialValues.enabled
});
const template = templates.find(t => t.buildType === initialValues.buildType && t.languageType === initialValues.languageType);
if (template) {
setSelectedTemplate(template);
setBuildVariables(initialValues.buildVariables || {});
@ -78,34 +82,49 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
} else {
form.resetFields();
form.setFieldsValue({
envId,
enabled: true,
sort: 0,
enabled: true
});
setSelectedTemplate(undefined);
setBuildVariables({});
}
}, [open, initialValues, envId, form, templates]);
}, [open, initialValues, form, templates]);
const handleAppChange = useCallback((appId: number) => {
const app = applications.find(a => a.id === appId);
const handleAppChange = useCallback((applicationId: number) => {
const app = applications.find(a => a.id === applicationId);
if (app) {
const template = templates.find(t => t.languageType === app.language);
if (template) {
setSelectedTemplate(template);
setBuildVariables({});
form.setFieldValue('templateCode', template.code);
}
}
}, [applications, templates, form]);
}, [applications, templates]);
const handleSubmit = async () => {
try {
setLoading(true);
const values = await form.validateFields();
// 获取选中的应用信息
const selectedApp = applications.find(app => app.id === values.applicationId);
if (!selectedApp) {
throw new Error('请选择应用');
}
// 获取对应的模板
const template = templates.find(t => t.languageType === selectedApp.language);
if (!template) {
throw new Error('未找到匹配的配置模板');
}
// 构建提交数据
const submitData = {
...values,
buildVariables,
environmentId: envId,
applicationId: values.applicationId,
buildType: template.buildType,
languageType: selectedApp.language,
buildVariables, // 动态表单的值都在这里
enabled: values.enabled
};
if (isEdit) {
@ -116,14 +135,14 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
} else {
await createDeploymentConfig(submitData);
}
messageApi.success(`${isEdit ? '更新' : '创建'}成功`);
message.success(`${isEdit ? '更新' : '创建'}成功`);
form.resetFields();
onSuccess();
} catch (error) {
if (error instanceof Error) {
messageApi.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
message.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
} else {
messageApi.error(`${isEdit ? '更新' : '创建'}失败`);
message.error(`${isEdit ? '更新' : '创建'}失败`);
}
} finally {
setLoading(false);
@ -152,9 +171,9 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
defaultLanguage={property.editorConfig.language || 'shell'}
theme={property.editorConfig.theme || 'vs-dark'}
value={buildVariables[key] || property.default || ''}
onChange={(value: string) => setBuildVariables(prev => ({
onChange={(value) => setBuildVariables(prev => ({
...prev,
[key]: value || ''
[key]: value
}))}
options={{
minimap: { enabled: property.editorConfig.minimap ?? false },
@ -187,25 +206,24 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
}
/>
</Form.Item>
) : null
) : (
<Form.Item
key={key}
label={property.title || key}
required={selectedTemplate.buildVariablesSchema.required?.includes(key)}
tooltip={property.description}
>
<Input
value={buildVariables[key] || property.default || ''}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setBuildVariables(prev => ({
...prev,
[key]: e.target.value
}))}
placeholder={`请输入${property.title || key}`}
/>
</Form.Item>
)
))}
{/* 其他配置项 */}
<BetaSchemaForm
layoutType="Embed"
columns={convertJsonSchemaToColumns({
type: 'object',
properties: Object.fromEntries(
Object.entries(properties || {}).filter(([_, prop]) => !prop.editorConfig)
),
required: selectedTemplate.buildVariablesSchema.required || []
})}
initialValues={buildVariables}
onValuesChange={(_, values) => setBuildVariables(prev => ({
...prev,
...values
}))}
/>
</>
);
};
@ -235,7 +253,7 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
>
{/* 应用选择 */}
<Form.Item
name="appId"
name="applicationId"
label="应用"
required
tooltip="选择要部署的应用"
@ -267,14 +285,6 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
>
<Switch checkedChildren="启用" unCheckedChildren="禁用" />
</Form.Item>
<Form.Item
name="sort"
label="排序"
tooltip="数字越小越靠前"
>
<InputNumber min={0} style={{ width: '100%' }} />
</Form.Item>
</Form>
</Modal>
);

View File

@ -1,6 +1,6 @@
import React, {useState, useEffect} from 'react';
import {PageContainer} from '@ant-design/pro-layout';
import {Button, message, Popconfirm, Select, Space, App} from 'antd';
import {Button, message, Popconfirm, Select, Space} from 'antd';
import {PlusOutlined, EditOutlined, DeleteOutlined} from '@ant-design/icons';
import {getDeploymentConfigPage, deleteDeploymentConfig} from './service';
import {getEnvironmentList} from '../../Environment/List/service';
@ -18,7 +18,6 @@ const DeploymentConfigList: React.FC = () => {
const [modalVisible, setModalVisible] = useState(false);
const [currentConfig, setCurrentConfig] = useState<DeploymentConfig>();
const actionRef = React.useRef<ActionType>();
const {message: messageApi} = App.useApp();
// 获取环境列表
const fetchEnvironments = async () => {
@ -29,7 +28,7 @@ const DeploymentConfigList: React.FC = () => {
setSelectedEnvId(data[0].id);
}
} catch (error) {
messageApi.error('获取环境列表失败');
message.error('获取环境列表失败');
}
};
@ -40,16 +39,16 @@ const DeploymentConfigList: React.FC = () => {
const handleDelete = async (id: number) => {
try {
await deleteDeploymentConfig(id);
messageApi.success('删除成功');
message.success('删除成功');
actionRef.current?.reload();
} catch (error) {
messageApi.error('删除失败');
message.error('删除失败');
}
};
const handleAdd = () => {
if (!selectedEnvId) {
messageApi.warning('请先选择环境');
message.warning('请先选择环境');
return;
}
setCurrentConfig(undefined);
@ -228,7 +227,7 @@ const DeploymentConfigList: React.FC = () => {
total: data.totalElements || 0,
};
} catch (error) {
messageApi.error('获取部署配置列表失败');
message.error('获取部署配置列表失败');
return {
data: [],
success: false,

View File

@ -2,8 +2,7 @@ import request from '@/utils/request';
import type {DeploymentConfig, CreateDeploymentConfigRequest, UpdateDeploymentConfigRequest, DeploymentConfigQueryParams, DeployConfigTemplate} from './types';
import type {Page} from '@/types/base';
const BASE_URL = '/api/v1/deployment-configs';
const TEMPLATE_URL = '/api/v1/deploy-app-config';
const BASE_URL = '/api/v1/deploy-app-config';
// 获取部署配置分页列表
export const getDeploymentConfigPage = (params: DeploymentConfigQueryParams) =>
@ -26,9 +25,9 @@ export const getDeploymentConfig = (id: number) =>
request.get<DeploymentConfig>(`${BASE_URL}/${id}`);
// 获取环境下的所有部署配置
export const getDeploymentConfigsByEnv = (envId: number) =>
request.get<DeploymentConfig[]>(`${BASE_URL}/env/${envId}`);
export const getDeploymentConfigsByEnv = (environmentId: number) =>
request.get<DeploymentConfig[]>(`${BASE_URL}/env/${environmentId}`);
// 获取部署配置模板列表
export const getDeployConfigTemplates = () =>
request.get<DeployConfigTemplate[]>(`${TEMPLATE_URL}/defined`);
request.get<DeployConfigTemplate[]>(`${BASE_URL}/defined`);

View File

@ -16,26 +16,24 @@ export interface DeployConfigTemplate {
// 部署配置基础信息
export interface DeploymentConfig extends BaseResponse {
tenantCode: string;
envId: number;
environmentId: number;
environment: Environment;
appId: number;
applicationId: number;
application: Application;
templateCode: string;
buildVariables: Record<string, any>;
buildType: BuildTypeEnum;
languageType: DevelopmentLanguageTypeEnum;
buildVariables: JsonNode;
enabled: boolean;
sort: number;
}
// 创建部署配置请求参数
export interface CreateDeploymentConfigRequest extends BaseRequest {
tenantCode: string;
envId: number;
appId: number;
templateCode: string;
buildVariables: Record<string, any>;
environmentId: number;
applicationId: number;
buildType: BuildTypeEnum;
languageType: DevelopmentLanguageTypeEnum;
buildVariables: JsonNode;
enabled: boolean;
sort: number;
}
// 更新部署配置请求参数
@ -45,7 +43,7 @@ export interface UpdateDeploymentConfigRequest extends CreateDeploymentConfigReq
// 分页查询参数
export interface DeploymentConfigQueryParams extends BaseQuery {
envId?: number;
appId?: number;
environmentId?: number;
applicationId?: number;
enabled?: boolean;
}

View File

@ -1,5 +1,5 @@
import React, {useState} from 'react';
import {Modal, Form, Input, Select, Switch, InputNumber, App} from 'antd';
import {Modal, Form, Input, Select, Switch, InputNumber, message} from 'antd';
import type {Environment} from '../types';
import {BuildTypeEnum, DeployTypeEnum} from '../types';
import {createEnvironment, updateEnvironment} from '../service';
@ -19,7 +19,6 @@ const EnvironmentModal: React.FC<EnvironmentModalProps> = ({
}) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const {message: messageApi} = App.useApp();
const isEdit = !!initialValues?.id;
const handleSubmit = async () => {
@ -34,14 +33,14 @@ const EnvironmentModal: React.FC<EnvironmentModalProps> = ({
} else {
await createEnvironment(values);
}
messageApi.success(`${isEdit ? '更新' : '创建'}成功`);
message.success(`${isEdit ? '更新' : '创建'}成功`);
form.resetFields();
onSuccess();
} catch (error) {
if (error instanceof Error) {
messageApi.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
message.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
} else {
messageApi.error(`${isEdit ? '更新' : '创建'}失败`);
message.error(`${isEdit ? '更新' : '创建'}失败`);
}
} finally {
setLoading(false);
@ -111,8 +110,9 @@ const EnvironmentModal: React.FC<EnvironmentModalProps> = ({
placeholder="请选择构建类型"
disabled={isEdit}
>
<Select.Option value={BuildTypeEnum.LOCAL}></Select.Option>
<Select.Option value={BuildTypeEnum.REMOTE}></Select.Option>
<Select.Option value={BuildTypeEnum.JENKINS}>Jenkins</Select.Option>
<Select.Option value={BuildTypeEnum.GITLAB_RUNNER}>GitLab Runner</Select.Option>
<Select.Option value={BuildTypeEnum.GITHUB_ACTION}>GitHub Action</Select.Option>
</Select>
</Form.Item>
@ -126,8 +126,9 @@ const EnvironmentModal: React.FC<EnvironmentModalProps> = ({
placeholder="请选择部署类型"
disabled={isEdit}
>
<Select.Option value={DeployTypeEnum.KUBERNETES}>Kubernetes</Select.Option>
<Select.Option value={DeployTypeEnum.K8S}>Kubernetes</Select.Option>
<Select.Option value={DeployTypeEnum.DOCKER}>Docker</Select.Option>
<Select.Option value={DeployTypeEnum.VM}></Select.Option>
</Select>
</Form.Item>

View File

@ -1,5 +1,5 @@
import React, {useState} from 'react';
import {Modal, Form, Input, Select, Switch, InputNumber, App} from 'antd';
import {Modal, Form, Input, Select, Switch, InputNumber, message} from 'antd';
import type {ProjectGroup} from '../types';
import {ProjectGroupTypeEnum} from '../types';
import {createProjectGroup, updateProjectGroup} from '../service';
@ -19,7 +19,6 @@ const ProjectGroupModal: React.FC<ProjectGroupModalProps> = ({
}) => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const {message: messageApi} = App.useApp();
const isEdit = !!initialValues?.id;
const handleSubmit = async () => {
@ -34,14 +33,14 @@ const ProjectGroupModal: React.FC<ProjectGroupModalProps> = ({
} else {
await createProjectGroup(values);
}
messageApi.success(`${isEdit ? '更新' : '创建'}成功`);
message.success(`${isEdit ? '更新' : '创建'}成功`);
form.resetFields();
onSuccess();
} catch (error) {
if (error instanceof Error) {
messageApi.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
message.error(`${isEdit ? '更新' : '创建'}失败: ${error.message}`);
} else {
messageApi.error(`${isEdit ? '更新' : '创建'}失败`);
message.error(`${isEdit ? '更新' : '创建'}失败`);
}
} finally {
setLoading(false);