This commit is contained in:
dengqichen 2024-12-27 11:25:11 +08:00
parent ea634518ad
commit e4816ed308

View File

@ -1,14 +1,13 @@
import React, {useEffect, useState, useCallback} from 'react'; import React, {useEffect, useState, useCallback} from 'react';
import {Modal, Form, Select, message, Switch, InputNumber, Input} from 'antd'; import {Modal, Form, Select, message, Switch, InputNumber, Input, Space, Button} from 'antd';
import {FullscreenOutlined} from '@ant-design/icons';
import type {DeploymentConfig, DeployConfigTemplate, CreateDeploymentConfigRequest} from '../types'; import type {DeploymentConfig, DeployConfigTemplate, CreateDeploymentConfigRequest} 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';
import type {Application} from '../../../Application/List/types'; import type {Application} from '../../../Application/List/types';
import {BetaSchemaForm} from '@ant-design/pro-form';
import {convertJsonSchemaToColumns} from '@/utils/jsonSchemaUtils';
import './styles.less';
import {Editor} from '@/components/Editor'; import {Editor} from '@/components/Editor';
import type {JsonNode} from '@/types/common'; import type {JsonNode} from '@/types/common';
import './styles.less';
const {Option} = Select; const {Option} = Select;
@ -33,6 +32,10 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
const [selectedTemplate, setSelectedTemplate] = useState<DeployConfigTemplate>(); const [selectedTemplate, setSelectedTemplate] = useState<DeployConfigTemplate>();
const [buildVariables, setBuildVariables] = useState<JsonNode>({}); const [buildVariables, setBuildVariables] = useState<JsonNode>({});
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [fullscreenEditor, setFullscreenEditor] = useState<{
key: string;
title: string;
} | null>(null);
const isEdit = !!initialValues?.id; const isEdit = !!initialValues?.id;
// 获取应用列表 // 获取应用列表
@ -114,7 +117,7 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
// 获取对应的模板 // 获取对应的模板
const template = templates.find(t => t.languageType === selectedApp.language); const template = templates.find(t => t.languageType === selectedApp.language);
if (!template) { if (!template) {
throw new Error('未找到匹配配置模板'); throw new Error('未找到匹配<EFBFBD><EFBFBD><EFBFBD>配置模板');
} }
// 构建提交数据 // 构建提交数据
@ -165,146 +168,202 @@ const DeploymentConfigModal: React.FC<DeploymentConfigModalProps> = ({
})); }));
}; };
// 渲染表单项
const renderFormItems = () => {
if (!selectedTemplate?.buildVariablesSchema?.properties) return null;
const { properties } = selectedTemplate.buildVariablesSchema;
return (
<>
{/* 遍历所有字段,对有 editorConfig 的字段使用富文本编辑器 */}
{Object.entries(properties).map(([key, property]) => (
property.editorConfig ? (
<Form.Item
key={key}
label={property.title || key}
required={selectedTemplate.buildVariablesSchema.required?.includes(key)}
tooltip={property.description}
>
<Editor
height="300px"
defaultLanguage={property.editorConfig.language || 'shell'}
theme={property.editorConfig.theme || 'vs-dark'}
value={buildVariables[key] || property.default || ''}
onChange={(value) => handleEditorChange(key, value)}
options={{
minimap: { enabled: property.editorConfig.minimap ?? false },
fontSize: property.editorConfig.fontSize || 14,
lineNumbers: property.editorConfig.lineNumbers ? 'on' : 'off',
wordWrap: property.editorConfig.wordWrap ? 'on' : 'off',
tabSize: property.editorConfig.tabSize || 2,
scrollBeyondLastLine: false,
automaticLayout: true,
folding: property.editorConfig.folding ?? true,
autoClosingBrackets: 'always',
autoClosingQuotes: 'always',
formatOnPaste: true,
formatOnType: true,
suggestOnTriggerCharacters: property.editorConfig.autoComplete ?? true,
renderWhitespace: 'boundary',
}}
loading={
<div style={{
padding: '8px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '300px',
background: '#1e1e1e',
color: '#fff'
}}>
...
</div>
}
/>
</Form.Item>
) : (
<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>) => handleInputChange(key, e.target.value)}
placeholder={`请输入${property.title || key}`}
/>
</Form.Item>
)
))}
</>
);
};
return ( return (
<Modal <>
title={`${isEdit ? '编辑' : '新建'}部署配置`} <Modal
open={open} title={`${isEdit ? '编辑' : '新建'}部署配置`}
onCancel={() => { open={open}
form.resetFields(); onCancel={() => {
onCancel(); form.resetFields();
}} onCancel();
onOk={handleSubmit} }}
width={800} onOk={handleSubmit}
className="deployment-config-modal" width={800}
maskClosable={false} className="deployment-config-modal"
confirmLoading={loading} maskClosable={false}
destroyOnClose confirmLoading={loading}
style={{ top: 50, paddingBottom: 0 }} destroyOnClose
styles={{ style={{ top: 50 }}
body: { styles={{
height: 'calc(100vh - 250px)', body: {
overflowY: 'auto', height: 'calc(100vh - 250px)',
padding: '24px' overflowY: 'auto',
} padding: '24px'
}} }
>
<Form
form={form}
layout="vertical"
initialValues={{
enabled: true,
sort: 0,
}} }}
> >
{/* 应用选择 */} <Form
<Form.Item form={form}
name="applicationId" layout="vertical"
label="应用" initialValues={{
required enabled: true,
tooltip="选择要部署的应用" sort: 0,
}}
> >
<Select {/* 应用选择 */}
placeholder="请选择应用" <Form.Item
onChange={handleAppChange} name="applicationId"
disabled={isEdit} label="应用"
showSearch required
optionFilterProp="children" tooltip="选择要部署的应用"
> >
{applications.map((app) => ( <Select
<Option key={app.id} value={app.id}> placeholder="请选择应用"
{app.appName} onChange={handleAppChange}
</Option> disabled={isEdit}
))} showSearch
</Select> optionFilterProp="children"
</Form.Item> >
{applications.map((app) => (
<Option key={app.id} value={app.id}>
{app.appName}
</Option>
))}
</Select>
</Form.Item>
{/* 动态构建配置 */} {/* 动态构建配置 */}
{renderFormItems()} {selectedTemplate?.buildVariablesSchema?.properties && (
Object.entries(selectedTemplate.buildVariablesSchema.properties).map(([key, property]) => {
if (property.editorConfig) {
return (
<Form.Item
key={key}
label={
<Space>
{property.title || key}
<Button
type="text"
icon={<FullscreenOutlined />}
onClick={() => setFullscreenEditor({
key,
title: property.title || key
})}
/>
</Space>
}
required={selectedTemplate.buildVariablesSchema.required?.includes(key)}
tooltip={property.description}
>
<Editor
height="300px"
defaultLanguage={property.editorConfig.language || 'shell'}
theme={property.editorConfig.theme || 'vs-dark'}
value={buildVariables[key] || property.default || ''}
onChange={(value) => handleEditorChange(key, value)}
options={{
minimap: { enabled: property.editorConfig.minimap ?? false },
fontSize: property.editorConfig.fontSize || 14,
lineNumbers: property.editorConfig.lineNumbers ? 'on' : 'off',
wordWrap: property.editorConfig.wordWrap ? 'on' : 'off',
tabSize: property.editorConfig.tabSize || 2,
scrollBeyondLastLine: false,
automaticLayout: true,
folding: property.editorConfig.folding ?? true,
autoClosingBrackets: 'always',
autoClosingQuotes: 'always',
formatOnPaste: true,
formatOnType: true,
suggestOnTriggerCharacters: property.editorConfig.autoComplete ?? true,
renderWhitespace: 'boundary',
}}
loading={
<div style={{
padding: '8px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '300px',
background: '#1e1e1e',
color: '#fff'
}}>
...
</div>
}
/>
</Form.Item>
);
}
{/* 状态和排序 */} return (
<Form.Item <Form.Item
name="enabled" key={key}
label="状态" label={property.title || key}
valuePropName="checked" required={selectedTemplate.buildVariablesSchema.required?.includes(key)}
tooltip="是否启用该配置" tooltip={property.description}
>
<Input
value={buildVariables[key] || property.default || ''}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleInputChange(key, e.target.value)}
placeholder={`请输入${property.title || key}`}
/>
</Form.Item>
);
})
)}
{/* 状态和排序 */}
<Form.Item
name="enabled"
label="状态"
valuePropName="checked"
tooltip="是否启用该配置"
>
<Switch checkedChildren="启用" unCheckedChildren="禁用" />
</Form.Item>
</Form>
</Modal>
{/* 全屏编辑器模态框 */}
{fullscreenEditor && selectedTemplate?.buildVariablesSchema?.properties && (
<Modal
title={fullscreenEditor.title}
open={true}
onCancel={() => setFullscreenEditor(null)}
footer={null}
width="100vw"
styles={{
body: { padding: 0 },
mask: { backgroundColor: 'rgba(0, 0, 0, 0.65)' },
content: {
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
margin: 0,
padding: 0,
width: '100vw',
height: '100vh'
}
}}
> >
<Switch checkedChildren="启用" unCheckedChildren="禁用" /> <Editor
</Form.Item> height="calc(100vh - 55px)"
</Form> defaultLanguage={selectedTemplate.buildVariablesSchema.properties[fullscreenEditor.key]?.editorConfig?.language || 'shell'}
</Modal> theme="vs-dark"
value={buildVariables[fullscreenEditor.key] || ''}
onChange={(value) => handleEditorChange(fullscreenEditor.key, value)}
options={{
minimap: { enabled: true },
fontSize: 14,
lineNumbers: 'on',
wordWrap: 'on',
tabSize: 2,
scrollBeyondLastLine: false,
automaticLayout: true,
folding: true,
autoClosingBrackets: 'always',
autoClosingQuotes: 'always',
formatOnPaste: true,
formatOnType: true,
suggestOnTriggerCharacters: true,
renderWhitespace: 'boundary',
}}
/>
</Modal>
)}
</>
); );
}; };