You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
8.3 KiB
TypeScript

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

import React, { useState, useEffect } from 'react';
import { Modal, Button, Input, Message, Tooltip } from '@arco-design/web-react';
import { IconQuestionCircle, IconCopy, IconDelete, IconPlus } from '@arco-design/web-react/icon';
import styles from './style/envConfigModal.module.less';
import { getComponentEnvConfig, saveComponentEnvConfig } from '@/api/componentInstance';
interface EnvConfigModalProps {
language: string;
visible: boolean;
instanceId: string;
onCancel: () => void;
onSuccess?: () => void;
}
interface ConfigItem {
name: string;
key: string;
value: string;
desc: string;
unmodifiable?: boolean;
isCustom?: boolean; // 标记是否为用户自定义添加的
}
const EnvConfigModal: React.FC<EnvConfigModalProps> = ({
language,
visible,
instanceId,
onCancel,
onSuccess
}) => {
const [loading, setLoading] = useState(false);
const [saveLoading, setSaveLoading] = useState(false);
const [configData, setConfigData] = useState<any>(null);
const [configList, setConfigList] = useState<ConfigItem[]>([]);
useEffect(() => {
if (visible && instanceId) {
fetchEnvConfig();
}
}, [visible, instanceId]);
const fetchEnvConfig = async () => {
try {
setLoading(true);
const res: any = await getComponentEnvConfig(instanceId);
if (res.code === 200) {
setConfigData(res.data);
setConfigList(res.data.config || []);
}
else {
Message.error(res.msg || '获取环境配置失败');
}
} catch (error) {
console.error('获取环境配置失败:', error);
Message.error('获取环境配置失败');
} finally {
setLoading(false);
}
};
const handleConfigChange = (index: number, field: keyof ConfigItem, value: string) => {
const newConfigList: any = [...configList];
newConfigList[index][field] = value;
setConfigList(newConfigList);
};
// 添加新配置行
const handleAddConfig = () => {
const newConfig: ConfigItem = {
name: '',
key: '',
value: '',
desc: '',
isCustom: true
};
setConfigList([...configList, newConfig]);
};
// 删除配置行
const handleDeleteConfig = (index: number) => {
const newConfigList = configList.filter((_, i) => i !== index);
setConfigList(newConfigList);
};
const handleCopyCommand = () => {
navigator.clipboard.writeText(configData.javaCommand);
Message.success('复制成功');
};
const handleSave = async () => {
try {
setSaveLoading(true);
const params = {
...configData,
config: configList
};
const res: any = await saveComponentEnvConfig(instanceId, params);
if (res.code === 200) {
Message.success('保存成功');
onSuccess?.();
onCancel();
}
else {
Message.error(res.msg || '保存失败');
}
} catch (error) {
console.error('保存失败:', error);
Message.error('保存失败');
} finally {
setSaveLoading(false);
}
};
return (
<Modal
title="环境配置"
visible={visible}
onCancel={onCancel}
style={{ width: 1000 }}
footer={
<div style={{ display: 'flex', justifyContent: 'flex-end', gap: 12 }}>
<Button onClick={onCancel}></Button>
<Button type="primary" onClick={handleSave} loading={saveLoading}>
</Button>
</div>
}
>
<div className={styles['env-config-modal']}>
{loading ? (
<div className={styles['loading-state']}>
<div className={styles['loading-spinner']}></div>
<p>...</p>
</div>
) : (
<>
{/* 命令展示 */}
{configData?.javaCommand && (
<div className={styles['command-section']}>
<div className={styles['command-header']}>
<Button
type="text"
size="mini"
icon={<IconCopy />}
onClick={handleCopyCommand}
>
</Button>
</div>
<div className={styles['command-content']}>
{language.includes('Python') ? configData.pythonCommand : configData.javaCommand}
</div>
<div className={styles['command-hint']}>
&#34;&#34;
</div>
</div>
)}
{/* 配置表格 */}
<div className={styles['config-table']}>
<div className={styles['table-header']}>
<div className={styles['col-index']}>#</div>
<div className={styles['col-name']}>
<span className={styles['required']}>*</span>
</div>
<div className={styles['col-key']}>
<span className={styles['required']}>*</span>
key
</div>
<div className={styles['col-value']}></div>
<div className={styles['col-desc']}></div>
<div className={styles['col-action']}></div>
</div>
<div className={styles['table-body']}>
{configList.map((item, index) => (
<div key={index} className={styles['table-row']}>
<div className={styles['col-index']}>{index + 1}</div>
<div className={styles['col-name']}>
<Input
value={item.name}
onChange={(value) => handleConfigChange(index, 'name', value)}
placeholder="请输入启动名称"
size="small"
/>
</div>
<div className={styles['col-key']}>
<Input
value={item.key}
onChange={(value) => handleConfigChange(index, 'key', value)}
placeholder="请输入参数名"
size="small"
/>
</div>
<div className={styles['col-value']}>
<Input
value={item.value}
onChange={(value) => handleConfigChange(index, 'value', value)}
placeholder="请输入配置值"
size="small"
/>
</div>
<div className={styles['col-desc']}>
<Input
value={item.desc}
onChange={(value) => handleConfigChange(index, 'desc', value)}
placeholder="请输入描述说明"
size="small"
/>
</div>
<div className={styles['col-action']}>
{item.isCustom && (
<Button
type="text"
status="danger"
icon={<IconDelete />}
onClick={() => handleDeleteConfig(index)}
size="small"
>
</Button>
)}
</div>
</div>
))}
</div>
{/* 添加新配置按钮 */}
<div className={styles['add-config-btn']}>
<Button
type="dashed"
icon={<IconPlus />}
onClick={handleAddConfig}
long
>
</Button>
</div>
</div>
</>
)}
</div>
</Modal>
);
};
export default EnvConfigModal;