1
This commit is contained in:
parent
6235f0e09b
commit
3b9a65bcc8
@ -0,0 +1,420 @@
|
|||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import {Modal, Button, message} from 'antd';
|
||||||
|
import { FullscreenOutlined, FullscreenExitOutlined } from '@ant-design/icons';
|
||||||
|
import type {DeploymentConfig} from '../types';
|
||||||
|
import './styles.less';
|
||||||
|
import {FormButtonGroup, FormItem, Select, Submit, FormGrid, Input, ArrayTable} from '@formily/antd-v5'
|
||||||
|
import {createForm, Field, FieldDataSource, onFormInit} from '@formily/core'
|
||||||
|
import {createSchemaField, FormProvider, ISchema} from '@formily/react'
|
||||||
|
import {action} from '@formily/reactive'
|
||||||
|
import request from '@/utils/request';
|
||||||
|
import Editor from '@/components/Editor';
|
||||||
|
|
||||||
|
// 定义 ScriptEditor 组件
|
||||||
|
const ScriptEditor: React.FC<any> = (props) => {
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleEscKey = (event: KeyboardEvent) => {
|
||||||
|
if (event.key === 'Escape' && isFullscreen) {
|
||||||
|
setIsFullscreen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('keydown', handleEscKey);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('keydown', handleEscKey);
|
||||||
|
};
|
||||||
|
}, [isFullscreen]);
|
||||||
|
|
||||||
|
const toggleFullscreen = () => {
|
||||||
|
setIsFullscreen(!isFullscreen);
|
||||||
|
};
|
||||||
|
|
||||||
|
const editorStyle = isFullscreen ? {
|
||||||
|
position: 'fixed',
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 0,
|
||||||
|
zIndex: 1000,
|
||||||
|
backgroundColor: '#1e1e1e'
|
||||||
|
} : {};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ position: 'relative', height: isFullscreen ? '100vh' : '240px', ...editorStyle }}>
|
||||||
|
<Editor {...props} height={isFullscreen ? '100vh' : '240px'} />
|
||||||
|
<div style={{
|
||||||
|
position: 'absolute',
|
||||||
|
top: '10px',
|
||||||
|
right: '10px',
|
||||||
|
zIndex: 1001,
|
||||||
|
display: 'flex',
|
||||||
|
gap: '8px'
|
||||||
|
}}>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
|
||||||
|
onClick={toggleFullscreen}
|
||||||
|
style={{ color: '#fff' }}
|
||||||
|
>
|
||||||
|
{isFullscreen ? '退出全屏' : '全屏'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
interface DeploymentConfigModalProps {
|
||||||
|
open: boolean;
|
||||||
|
onCancel: () => void;
|
||||||
|
onSuccess: () => void;
|
||||||
|
initialValues?: DeploymentConfig;
|
||||||
|
envId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义字段映射接口
|
||||||
|
interface FieldMapping {
|
||||||
|
label?: string;
|
||||||
|
value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
|
||||||
|
open,
|
||||||
|
onCancel,
|
||||||
|
onSuccess,
|
||||||
|
initialValues,
|
||||||
|
envId,
|
||||||
|
}) => {
|
||||||
|
|
||||||
|
// 通用的异步数据源加载方法
|
||||||
|
const useAsyncDataSource = (url: string | null, mapping: FieldMapping = {}) => (field: Field) => {
|
||||||
|
if (!url) {
|
||||||
|
field.dataSource = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { label = 'name', value = 'id' } = mapping;
|
||||||
|
field.loading = true;
|
||||||
|
request.get(url)
|
||||||
|
.then(action.bound?.((response) => {
|
||||||
|
field.dataSource = response.map((item: any) => ({
|
||||||
|
label: item[label],
|
||||||
|
value: item[value]
|
||||||
|
}));
|
||||||
|
field.loading = false;
|
||||||
|
}))
|
||||||
|
.catch(action.bound?.((error) => {
|
||||||
|
console.error(`Failed to load data from ${url}:`, error);
|
||||||
|
field.dataSource = [];
|
||||||
|
field.loading = false;
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
const SchemaField = createSchemaField({
|
||||||
|
components: {
|
||||||
|
Select,
|
||||||
|
FormItem,
|
||||||
|
FormGrid,
|
||||||
|
Input,
|
||||||
|
ArrayTable,
|
||||||
|
ScriptEditor
|
||||||
|
},
|
||||||
|
scope: {
|
||||||
|
useAsyncDataSource
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 创建表单实例
|
||||||
|
const form = createForm()
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
jenkinsConfig: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'FormGrid',
|
||||||
|
'x-component-props': {
|
||||||
|
maxColumns: 3,
|
||||||
|
minColumns: 3,
|
||||||
|
columnGap: 24
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
externalSystemId: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Jenkins系统',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-decorator-props': {
|
||||||
|
labelCol: 24,
|
||||||
|
wrapperCol: 24,
|
||||||
|
layout: 'vertical',
|
||||||
|
colon: false,
|
||||||
|
labelAlign: 'left'
|
||||||
|
},
|
||||||
|
'x-component': 'Select',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
width: '100%'
|
||||||
|
},
|
||||||
|
placeholder: '请选择三方系统',
|
||||||
|
allowClear: true
|
||||||
|
},
|
||||||
|
'x-reactions': ["{{useAsyncDataSource('/api/v1/external-system/list?type=JENKINS', { label: 'name' })}}"],
|
||||||
|
},
|
||||||
|
viewId: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Jenkins视图',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-decorator-props': {
|
||||||
|
labelCol: 24,
|
||||||
|
wrapperCol: 24,
|
||||||
|
layout: 'vertical',
|
||||||
|
colon: false,
|
||||||
|
labelAlign: 'left'
|
||||||
|
},
|
||||||
|
'x-component': 'Select',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
width: '100%'
|
||||||
|
},
|
||||||
|
placeholder: '请选择Jenkins视图',
|
||||||
|
disabled: '{{!$form.values.externalSystemId}}',
|
||||||
|
allowClear: true
|
||||||
|
},
|
||||||
|
'x-reactions': {
|
||||||
|
dependencies: ['externalSystemId'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
value: undefined
|
||||||
|
},
|
||||||
|
run: '{{useAsyncDataSource($deps[0] ? `/api/v1/jenkins-view/list?externalSystemId=${$deps[0]}` : null, { label: "viewName" })($self)}}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
jobId: {
|
||||||
|
type: 'string',
|
||||||
|
title: 'Jenkins作业',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-decorator-props': {
|
||||||
|
labelCol: 24,
|
||||||
|
wrapperCol: 24,
|
||||||
|
layout: 'vertical',
|
||||||
|
colon: false,
|
||||||
|
labelAlign: 'left'
|
||||||
|
},
|
||||||
|
'x-component': 'Select',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
width: '100%'
|
||||||
|
},
|
||||||
|
placeholder: '请选择Jenkins作业',
|
||||||
|
disabled: '{{!$form.values.viewId}}',
|
||||||
|
allowClear: true
|
||||||
|
},
|
||||||
|
'x-reactions': {
|
||||||
|
dependencies: ['externalSystemId', 'viewId'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
value: undefined
|
||||||
|
},
|
||||||
|
run: '{{useAsyncDataSource(($deps[0] && $deps[1]) ? `/api/v1/jenkins-job/list?externalSystemId=${$deps[0]}&viewId=${$deps[1]}` : null, { label: "jobName" })($self)}}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
envConfig: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'FormGrid',
|
||||||
|
'x-component-props': {
|
||||||
|
maxColumns: 1,
|
||||||
|
minColumns: 1
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
envs: {
|
||||||
|
type: 'array',
|
||||||
|
title: '环境变量',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-decorator-props': {
|
||||||
|
labelCol: 24,
|
||||||
|
wrapperCol: 24,
|
||||||
|
layout: 'vertical',
|
||||||
|
colon: false,
|
||||||
|
labelAlign: 'left'
|
||||||
|
},
|
||||||
|
'x-component': 'ArrayTable',
|
||||||
|
'x-component-props': {
|
||||||
|
pagination: { pageSize: 10 },
|
||||||
|
scroll: { x: '100%' },
|
||||||
|
style: {
|
||||||
|
minHeight: '160px',
|
||||||
|
maxHeight: '240px',
|
||||||
|
overflow: 'auto'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
key: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': { title: '键', width: '40%' },
|
||||||
|
properties: {
|
||||||
|
key: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-validator': [
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入环境变量名'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: '^[a-zA-Z][a-zA-Z0-9_]*$',
|
||||||
|
message: '只能包含字母、数字和下划线,且必须以字母开头'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: '请输入环境变量名',
|
||||||
|
allowClear: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': { title: '值', width: '40%' },
|
||||||
|
properties: {
|
||||||
|
value: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-validator': {
|
||||||
|
required: true,
|
||||||
|
message: '请输入环境变量值'
|
||||||
|
},
|
||||||
|
'x-component-props': {
|
||||||
|
placeholder: '请输入环境变量值',
|
||||||
|
allowClear: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
column3: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': {
|
||||||
|
title: '操作',
|
||||||
|
dataIndex: 'operations',
|
||||||
|
width: '20%',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Remove'
|
||||||
|
},
|
||||||
|
moveUp: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.MoveUp'
|
||||||
|
},
|
||||||
|
moveDown: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.MoveDown'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
add: {
|
||||||
|
type: 'void',
|
||||||
|
title: '添加环境变量',
|
||||||
|
'x-component': 'ArrayTable.Addition'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
script: {
|
||||||
|
type: 'string',
|
||||||
|
title: '脚本内容',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-decorator-props': {
|
||||||
|
labelCol: 24,
|
||||||
|
wrapperCol: 24,
|
||||||
|
layout: 'vertical',
|
||||||
|
colon: false,
|
||||||
|
labelAlign: 'left',
|
||||||
|
style: {
|
||||||
|
marginBottom: '16px'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'x-component': 'ScriptEditor',
|
||||||
|
'x-component-props': {
|
||||||
|
language: 'shell',
|
||||||
|
theme: 'vs-dark',
|
||||||
|
options: {
|
||||||
|
minimap: {
|
||||||
|
enabled: true,
|
||||||
|
scale: 2,
|
||||||
|
showSlider: "mouseover",
|
||||||
|
renderCharacters: false
|
||||||
|
},
|
||||||
|
scrollBeyondLastLine: false,
|
||||||
|
fontSize: 14,
|
||||||
|
lineNumbers: 'on',
|
||||||
|
automaticLayout: true,
|
||||||
|
tabSize: 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async () => {
|
||||||
|
try {
|
||||||
|
const values = await form.submit()
|
||||||
|
console.log('表单提交的值:', values)
|
||||||
|
console.log('Schema:', schema)
|
||||||
|
console.log('FORMILY:', JSON.stringify(schema, null, 2))
|
||||||
|
onSuccess?.()
|
||||||
|
form.reset()
|
||||||
|
} catch (e) {
|
||||||
|
console.error('表单提交出错:', e)
|
||||||
|
message.error('提交失败,请检查表单数据是否正确')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
title="部署配置"
|
||||||
|
open={open}
|
||||||
|
onCancel={onCancel}
|
||||||
|
width={800}
|
||||||
|
centered
|
||||||
|
footer={[
|
||||||
|
<Button key="cancel" onClick={onCancel}>
|
||||||
|
取消
|
||||||
|
</Button>,
|
||||||
|
<Button key="submit" type="primary" onClick={handleSubmit}>
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
bodyStyle={{
|
||||||
|
padding: '24px',
|
||||||
|
maxHeight: '80vh',
|
||||||
|
overflow: 'auto'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormProvider form={form}>
|
||||||
|
<SchemaField schema={schema}/>
|
||||||
|
</FormProvider>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DeploymentConfigModal;
|
||||||
@ -1,419 +1,147 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, {useEffect, useState} from 'react';
|
||||||
import {Modal, Button, message} from 'antd';
|
import {
|
||||||
import { FullscreenOutlined, FullscreenExitOutlined } from '@ant-design/icons';
|
Dialog,
|
||||||
import type {DeploymentConfig} from '../types';
|
DialogContent,
|
||||||
import './styles.less';
|
DialogHeader,
|
||||||
import {FormButtonGroup, FormItem, Select, Submit, FormGrid, Input, ArrayTable} from '@formily/antd-v5'
|
DialogTitle,
|
||||||
import {createForm, Field, FieldDataSource, onFormInit} from '@formily/core'
|
DialogFooter,
|
||||||
import {createSchemaField, FormProvider, ISchema} from '@formily/react'
|
} from "@/components/ui/dialog";
|
||||||
import {action} from '@formily/reactive'
|
import {Button} from "@/components/ui/button";
|
||||||
import request from '@/utils/request';
|
import {
|
||||||
import Editor from '@/components/Editor';
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectItem,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
} from "@/components/ui/select";
|
||||||
|
import {useForm} from "react-hook-form";
|
||||||
|
import {getApplicationList} from '../../../Application/List/service';
|
||||||
|
import {getExternalSystemList} from '../service';
|
||||||
|
import type {ExternalSystem} from '@/pages/Deploy/External/types';
|
||||||
|
|
||||||
// 定义 ScriptEditor 组件
|
interface Application {
|
||||||
const ScriptEditor: React.FC<any> = (props) => {
|
id: number;
|
||||||
const [isFullscreen, setIsFullscreen] = useState(false);
|
appName: string;
|
||||||
|
}
|
||||||
useEffect(() => {
|
|
||||||
const handleEscKey = (event: KeyboardEvent) => {
|
|
||||||
if (event.key === 'Escape' && isFullscreen) {
|
|
||||||
setIsFullscreen(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
document.addEventListener('keydown', handleEscKey);
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener('keydown', handleEscKey);
|
|
||||||
};
|
|
||||||
}, [isFullscreen]);
|
|
||||||
|
|
||||||
const toggleFullscreen = () => {
|
|
||||||
setIsFullscreen(!isFullscreen);
|
|
||||||
};
|
|
||||||
|
|
||||||
const editorStyle = isFullscreen ? {
|
|
||||||
position: 'fixed',
|
|
||||||
top: 0,
|
|
||||||
left: 0,
|
|
||||||
right: 0,
|
|
||||||
bottom: 0,
|
|
||||||
zIndex: 1000,
|
|
||||||
backgroundColor: '#1e1e1e'
|
|
||||||
} : {};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div style={{ position: 'relative', height: isFullscreen ? '100vh' : '240px', ...editorStyle }}>
|
|
||||||
<Editor {...props} height={isFullscreen ? '100vh' : '240px'} />
|
|
||||||
<div style={{
|
|
||||||
position: 'absolute',
|
|
||||||
top: '10px',
|
|
||||||
right: '10px',
|
|
||||||
zIndex: 1001,
|
|
||||||
display: 'flex',
|
|
||||||
gap: '8px'
|
|
||||||
}}>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={isFullscreen ? <FullscreenExitOutlined /> : <FullscreenOutlined />}
|
|
||||||
onClick={toggleFullscreen}
|
|
||||||
style={{ color: '#fff' }}
|
|
||||||
>
|
|
||||||
{isFullscreen ? '退出全屏' : '全屏'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface DeploymentConfigModalProps {
|
interface DeploymentConfigModalProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onSuccess: () => void;
|
onSuccess: () => void;
|
||||||
initialValues?: DeploymentConfig;
|
|
||||||
envId: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 定义字段映射接口
|
const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({open, onCancel, onSuccess}) => {
|
||||||
interface FieldMapping {
|
const [applications, setApplications] = useState<Application[]>([]);
|
||||||
label?: string;
|
const [externalSystems, setExternalSystems] = useState<ExternalSystem[]>([]);
|
||||||
value?: string;
|
const form = useForm({
|
||||||
}
|
defaultValues: {
|
||||||
|
applicationId: undefined,
|
||||||
const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
|
externalSystemId: undefined,
|
||||||
open,
|
|
||||||
onCancel,
|
|
||||||
onSuccess,
|
|
||||||
initialValues,
|
|
||||||
envId,
|
|
||||||
}) => {
|
|
||||||
|
|
||||||
// 通用的异步数据源加载方法
|
|
||||||
const useAsyncDataSource = (url: string | null, mapping: FieldMapping = {}) => (field: Field) => {
|
|
||||||
if (!url) {
|
|
||||||
field.dataSource = [];
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const { label = 'name', value = 'id' } = mapping;
|
useEffect(() => {
|
||||||
field.loading = true;
|
if (open) {
|
||||||
request.get(url)
|
// 获取应用列表
|
||||||
.then(action.bound?.((response) => {
|
getApplicationList().then(data => {
|
||||||
field.dataSource = response.map((item: any) => ({
|
setApplications(data);
|
||||||
label: item[label],
|
});
|
||||||
value: item[value]
|
// 获取外部系统列表
|
||||||
}));
|
getExternalSystemList('JENKINS').then(data => {
|
||||||
field.loading = false;
|
setExternalSystems(data);
|
||||||
}))
|
});
|
||||||
.catch(action.bound?.((error) => {
|
|
||||||
console.error(`Failed to load data from ${url}:`, error);
|
|
||||||
field.dataSource = [];
|
|
||||||
field.loading = false;
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
|
|
||||||
const SchemaField = createSchemaField({
|
|
||||||
components: {
|
|
||||||
Select,
|
|
||||||
FormItem,
|
|
||||||
FormGrid,
|
|
||||||
Input,
|
|
||||||
ArrayTable,
|
|
||||||
ScriptEditor
|
|
||||||
},
|
|
||||||
scope: {
|
|
||||||
useAsyncDataSource
|
|
||||||
}
|
}
|
||||||
})
|
}, [open]);
|
||||||
|
|
||||||
// 创建表单实例
|
const handleSubmit = form.handleSubmit((values) => {
|
||||||
const form = createForm()
|
console.log('表单提交的值:', values);
|
||||||
|
onSuccess?.();
|
||||||
const schema: ISchema = {
|
});
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
jenkinsConfig: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'FormGrid',
|
|
||||||
'x-component-props': {
|
|
||||||
maxColumns: 3,
|
|
||||||
minColumns: 3,
|
|
||||||
columnGap: 24
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
externalSystemId: {
|
|
||||||
type: 'string',
|
|
||||||
title: 'Jenkins系统',
|
|
||||||
required: true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-decorator-props': {
|
|
||||||
labelCol: 24,
|
|
||||||
wrapperCol: 24,
|
|
||||||
layout: 'vertical',
|
|
||||||
colon: false,
|
|
||||||
labelAlign: 'left'
|
|
||||||
},
|
|
||||||
'x-component': 'Select',
|
|
||||||
'x-component-props': {
|
|
||||||
style: {
|
|
||||||
width: '100%'
|
|
||||||
},
|
|
||||||
placeholder: '请选择三方系统',
|
|
||||||
allowClear: true
|
|
||||||
},
|
|
||||||
'x-reactions': ["{{useAsyncDataSource('/api/v1/external-system/list?type=JENKINS', { label: 'name' })}}"],
|
|
||||||
},
|
|
||||||
viewId: {
|
|
||||||
type: 'string',
|
|
||||||
title: 'Jenkins视图',
|
|
||||||
required: true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-decorator-props': {
|
|
||||||
labelCol: 24,
|
|
||||||
wrapperCol: 24,
|
|
||||||
layout: 'vertical',
|
|
||||||
colon: false,
|
|
||||||
labelAlign: 'left'
|
|
||||||
},
|
|
||||||
'x-component': 'Select',
|
|
||||||
'x-component-props': {
|
|
||||||
style: {
|
|
||||||
width: '100%'
|
|
||||||
},
|
|
||||||
placeholder: '请选择Jenkins视图',
|
|
||||||
disabled: '{{!$form.values.externalSystemId}}',
|
|
||||||
allowClear: true
|
|
||||||
},
|
|
||||||
'x-reactions': {
|
|
||||||
dependencies: ['externalSystemId'],
|
|
||||||
fulfill: {
|
|
||||||
state: {
|
|
||||||
value: undefined
|
|
||||||
},
|
|
||||||
run: '{{useAsyncDataSource($deps[0] ? `/api/v1/jenkins-view/list?externalSystemId=${$deps[0]}` : null, { label: "viewName" })($self)}}'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
jobId: {
|
|
||||||
type: 'string',
|
|
||||||
title: 'Jenkins作业',
|
|
||||||
required: true,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-decorator-props': {
|
|
||||||
labelCol: 24,
|
|
||||||
wrapperCol: 24,
|
|
||||||
layout: 'vertical',
|
|
||||||
colon: false,
|
|
||||||
labelAlign: 'left'
|
|
||||||
},
|
|
||||||
'x-component': 'Select',
|
|
||||||
'x-component-props': {
|
|
||||||
style: {
|
|
||||||
width: '100%'
|
|
||||||
},
|
|
||||||
placeholder: '请选择Jenkins作业',
|
|
||||||
disabled: '{{!$form.values.viewId}}',
|
|
||||||
allowClear: true
|
|
||||||
},
|
|
||||||
'x-reactions': {
|
|
||||||
dependencies: ['externalSystemId', 'viewId'],
|
|
||||||
fulfill: {
|
|
||||||
state: {
|
|
||||||
value: undefined
|
|
||||||
},
|
|
||||||
run: '{{useAsyncDataSource(($deps[0] && $deps[1]) ? `/api/v1/jenkins-job/list?externalSystemId=${$deps[0]}&viewId=${$deps[1]}` : null, { label: "jobName" })($self)}}'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
|
||||||
envConfig: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'FormGrid',
|
|
||||||
'x-component-props': {
|
|
||||||
maxColumns: 1,
|
|
||||||
minColumns: 1
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
envs: {
|
|
||||||
type: 'array',
|
|
||||||
title: '环境变量',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-decorator-props': {
|
|
||||||
labelCol: 24,
|
|
||||||
wrapperCol: 24,
|
|
||||||
layout: 'vertical',
|
|
||||||
colon: false,
|
|
||||||
labelAlign: 'left'
|
|
||||||
},
|
|
||||||
'x-component': 'ArrayTable',
|
|
||||||
'x-component-props': {
|
|
||||||
pagination: { pageSize: 10 },
|
|
||||||
scroll: { x: '100%' },
|
|
||||||
style: {
|
|
||||||
minHeight: '160px',
|
|
||||||
maxHeight: '240px',
|
|
||||||
overflow: 'auto'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
items: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
key: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayTable.Column',
|
|
||||||
'x-component-props': { title: '键', width: '40%' },
|
|
||||||
properties: {
|
|
||||||
key: {
|
|
||||||
type: 'string',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
'x-validator': [
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入环境变量名'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
pattern: '^[a-zA-Z][a-zA-Z0-9_]*$',
|
|
||||||
message: '只能包含字母、数字和下划线,且必须以字母开头'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'x-component-props': {
|
|
||||||
placeholder: '请输入环境变量名',
|
|
||||||
allowClear: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
value: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayTable.Column',
|
|
||||||
'x-component-props': { title: '值', width: '40%' },
|
|
||||||
properties: {
|
|
||||||
value: {
|
|
||||||
type: 'string',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
'x-validator': {
|
|
||||||
required: true,
|
|
||||||
message: '请输入环境变量值'
|
|
||||||
},
|
|
||||||
'x-component-props': {
|
|
||||||
placeholder: '请输入环境变量值',
|
|
||||||
allowClear: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
column3: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayTable.Column',
|
|
||||||
'x-component-props': {
|
|
||||||
title: '操作',
|
|
||||||
dataIndex: 'operations',
|
|
||||||
width: '20%',
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
remove: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayTable.Remove'
|
|
||||||
},
|
|
||||||
moveUp: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayTable.MoveUp'
|
|
||||||
},
|
|
||||||
moveDown: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'ArrayTable.MoveDown'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
properties: {
|
|
||||||
add: {
|
|
||||||
type: 'void',
|
|
||||||
title: '添加环境变量',
|
|
||||||
'x-component': 'ArrayTable.Addition'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
script: {
|
|
||||||
type: 'string',
|
|
||||||
title: '脚本内容',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-decorator-props': {
|
|
||||||
labelCol: 24,
|
|
||||||
wrapperCol: 24,
|
|
||||||
layout: 'vertical',
|
|
||||||
colon: false,
|
|
||||||
labelAlign: 'left',
|
|
||||||
style: {
|
|
||||||
marginBottom: '16px'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'x-component': 'ScriptEditor',
|
|
||||||
'x-component-props': {
|
|
||||||
language: 'shell',
|
|
||||||
theme: 'vs-dark',
|
|
||||||
options: {
|
|
||||||
minimap: {
|
|
||||||
enabled: true,
|
|
||||||
scale: 2,
|
|
||||||
showSlider: "mouseover",
|
|
||||||
renderCharacters: false
|
|
||||||
},
|
|
||||||
scrollBeyondLastLine: false,
|
|
||||||
fontSize: 14,
|
|
||||||
lineNumbers: 'on',
|
|
||||||
automaticLayout: true,
|
|
||||||
tabSize: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
|
||||||
try {
|
|
||||||
const values = await form.submit()
|
|
||||||
console.log('表单提交的值:', values)
|
|
||||||
console.log('Schema:', schema)
|
|
||||||
console.log('FORMILY:', JSON.stringify(schema, null, 2))
|
|
||||||
onSuccess?.()
|
|
||||||
form.reset()
|
|
||||||
} catch (e) {
|
|
||||||
console.error('表单提交出错:', e)
|
|
||||||
message.error('提交失败,请检查表单数据是否正确')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Dialog open={open} onOpenChange={(open) => !open && onCancel()}>
|
||||||
title="部署配置"
|
<DialogContent className="sm:max-w-[600px]">
|
||||||
open={open}
|
<DialogHeader>
|
||||||
onCancel={onCancel}
|
<DialogTitle>部署配置</DialogTitle>
|
||||||
width={800}
|
</DialogHeader>
|
||||||
centered
|
<Form {...form}>
|
||||||
footer={[
|
<form onSubmit={handleSubmit} className="space-y-4">
|
||||||
<Button key="cancel" onClick={onCancel}>
|
<div className="grid grid-cols-2 gap-4">
|
||||||
取消
|
<FormField
|
||||||
</Button>,
|
control={form.control}
|
||||||
<Button key="submit" type="primary" onClick={handleSubmit}>
|
name="applicationId"
|
||||||
确定
|
render={({field}) => (
|
||||||
</Button>
|
<FormItem>
|
||||||
]}
|
<FormLabel>应用选择</FormLabel>
|
||||||
bodyStyle={{
|
<Select
|
||||||
padding: '24px',
|
onValueChange={(value) => field.onChange(Number(value))}
|
||||||
maxHeight: '80vh',
|
value={field.value?.toString()}
|
||||||
overflow: 'auto'
|
>
|
||||||
}}
|
<FormControl>
|
||||||
>
|
<SelectTrigger>
|
||||||
<FormProvider form={form}>
|
<SelectValue placeholder="请选择应用" />
|
||||||
<SchemaField schema={schema}/>
|
</SelectTrigger>
|
||||||
</FormProvider>
|
</FormControl>
|
||||||
</Modal>
|
<SelectContent>
|
||||||
|
{applications.map((app) => (
|
||||||
|
<SelectItem key={app.id} value={String(app.id)}>
|
||||||
|
{app.appName}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="externalSystemId"
|
||||||
|
render={({field}) => (
|
||||||
|
<FormItem>
|
||||||
|
<FormLabel>三方系统</FormLabel>
|
||||||
|
<Select
|
||||||
|
onValueChange={(value) => field.onChange(Number(value))}
|
||||||
|
value={field.value?.toString()}
|
||||||
|
>
|
||||||
|
<FormControl>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue placeholder="请选择三方系统" />
|
||||||
|
</SelectTrigger>
|
||||||
|
</FormControl>
|
||||||
|
<SelectContent>
|
||||||
|
{externalSystems.map((system) => (
|
||||||
|
<SelectItem key={system.id} value={String(system.id)}>
|
||||||
|
{system.name}
|
||||||
|
</SelectItem>
|
||||||
|
))}
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<FormMessage />
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
<DialogFooter>
|
||||||
|
<Button variant="outline" onClick={onCancel}>
|
||||||
|
取消
|
||||||
|
</Button>
|
||||||
|
<Button onClick={form.handleSubmit(handleSubmit)}>
|
||||||
|
确定
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import request from '@/utils/request';
|
import request from '@/utils/request';
|
||||||
import type {DeploymentConfig, CreateDeploymentConfigRequest, UpdateDeploymentConfigRequest, DeploymentConfigQueryParams, DeployConfigTemplate} from './types';
|
import type {DeploymentConfig, CreateDeploymentConfigRequest, UpdateDeploymentConfigRequest, DeploymentConfigQueryParams, DeployConfigTemplate} from './types';
|
||||||
import type {Page} from '@/types/base';
|
import type {Page} from '@/types/base';
|
||||||
|
import type {ExternalSystem} from '@/pages/Deploy/External/types';
|
||||||
|
|
||||||
const BASE_URL = '/api/v1/deploy-app-config';
|
const BASE_URL = '/api/v1/deploy-app-config';
|
||||||
|
|
||||||
@ -31,3 +32,7 @@ export const getDeploymentConfigsByEnv = (environmentId: number) =>
|
|||||||
// 获取部署配置模板列表
|
// 获取部署配置模板列表
|
||||||
export const getDeployConfigTemplates = () =>
|
export const getDeployConfigTemplates = () =>
|
||||||
request.get<DeployConfigTemplate[]>(`${BASE_URL}/defined`);
|
request.get<DeployConfigTemplate[]>(`${BASE_URL}/defined`);
|
||||||
|
|
||||||
|
// 获取外部系统列表
|
||||||
|
export const getExternalSystemList = (type: string) =>
|
||||||
|
request.get<ExternalSystem[]>('/api/v1/external-system/list', {params: {type}});
|
||||||
Loading…
Reference in New Issue
Block a user