feat(componentDeployment): 实现新增实例-线上运行功能

master
钟良源 3 months ago
parent 128d0953b1
commit 44afe3073f

@ -27,3 +27,8 @@ export function downloadEnvConfigFile(id: string) {
export function testEnv(id: string) { export function testEnv(id: string) {
return axios.get(`${urlPrefix}/componentDeployEnv/check?id=${id}`); return axios.get(`${urlPrefix}/componentDeployEnv/check?id=${id}`);
} }
// 主机列表
export function getHostList(params) {
return axios.get(`${urlPrefix}/componentDeployEnv/list`, { params });
}

@ -1,7 +1,9 @@
import React, { useEffect, useState } from 'react' ; import React, { useEffect, useState } from 'react' ;
import { Modal, Form, Select, Grid, Slider, Switch, Input } from '@arco-design/web-react'; import { Modal, Form, Select, Grid, Slider, Switch, Input, Message } from '@arco-design/web-react';
import EditableTable from '@/components/EditableTable'; import EditableTable from '@/components/EditableTable';
import { getComponentClassify } from '@/api/componentClassify'; import { getComponentClassify } from '@/api/componentClassify';
import { getHostList } from '@/api/componentDeployEnv';
import { createInstance } from '@/api/componentInstance';
const FormItem = Form.Item; const FormItem = Form.Item;
const Option = Select.Option; const Option = Select.Option;
@ -75,45 +77,95 @@ const deviceColumns = [
} }
]; ];
const AddModal = ({ visible, setVisible }) => { const AddModal = ({ addItem, visible, setVisible }) => {
const [form] = Form.useForm();
const [currentRunType, setCurrentRunType] = useState('local'); const [currentRunType, setCurrentRunType] = useState('local');
const [envType, setEnvType] = useState([]); // 环境类型 const [envType, setEnvType] = useState([]); // 环境类型
const [tableData, setTableData] = useState([ const [hostOptions, setHostOptions] = useState([]); // 主机
{ const [tableData, setTableData] = useState([]);
key: '1', const [loading, setLoading] = useState(false);
name: 'Jane Doe',
salary: 23000,
email: 'jane.doe@example.com'
}
]);
const getEnvOptions = async () => { const getEnvOptions = async () => {
const res: any = await getComponentClassify('docker-env'); const res: any = await getComponentClassify('docker-env');
if (res.code === 200) setEnvType(res.data); if (res.code === 200) setEnvType(res.data);
}; };
const getHostOptions = async () => {
const res: any = await getHostList({
type: 'docker-env',
componentBaseId: addItem.componentBaseId
});
if (res.code === 200) setHostOptions(res.data);
};
useEffect(() => { useEffect(() => {
getEnvOptions(); if (visible) {
}, []); getHostOptions();
getEnvOptions();
}
else {
// 关闭时重置表单
form.resetFields();
setCurrentRunType('local');
setTableData([]);
}
}, [visible]);
// 处理取消
const handleCancel = () => {
form.resetFields();
setCurrentRunType('local');
setTableData([]);
setVisible(false);
};
// 处理确认
const handleOk = async () => {
if (currentRunType === 'local') {
// TODO: 本地运行逻辑,由用户自己实现
Message.info('本地运行逻辑待实现');
return;
}
// 线上运行 - 校验表单
try {
const values = await form.validate();
// 整理参数
const params = {
deployEnvId: values.deployEnvId,
componentBaseId: addItem.componentBaseId
};
const res: any = await createInstance(params);
console.log('新增实例CB:', res);
Message.info('接口调用逻辑待实现');
} catch (error) {
console.error('表单校验失败:', error);
}
};
return ( return (
<Modal <Modal
title="新增实例" title="新增实例"
visible={visible} visible={visible}
onOk={() => setVisible(false)} onOk={handleOk}
onCancel={() => setVisible(false)} onCancel={handleCancel}
confirmLoading={loading}
autoFocus={false} autoFocus={false}
focusLock={true} focusLock={true}
style={{ width: '75%' }} style={{ width: '35%' }}
> >
<Form autoComplete="off" labelCol={{ flex: 'none' }}> <Form form={form} autoComplete="off">
<Grid.Row gutter={8}> <Grid.Row gutter={8}>
<Grid.Col span={12}> <Grid.Col span={12}>
<FormItem label="部署方式:"> <FormItem label="部署方式:">
<Select <Select
placeholder="请选择" placeholder="请选择"
style={{ width: '60%' }} style={{ width: '60%' }}
defaultValue={currentRunType} value={currentRunType}
onChange={(value) => setCurrentRunType(value)} onChange={(value) => setCurrentRunType(value)}
> >
{runTypes.map((option, index) => ( {runTypes.map((option, index) => (
@ -129,29 +181,47 @@ const AddModal = ({ visible, setVisible }) => {
currentRunType === 'online' && ( currentRunType === 'online' && (
<> <>
<Grid.Row gutter={8}> <Grid.Row gutter={8}>
{/*<Grid.Col span={12}>*/}
{/* <FormItem label="部署环境:" field="tags">*/}
{/* <Select*/}
{/* placeholder="请选择部署环境"*/}
{/* style={{ width: '90%' }}*/}
{/* >*/}
{/* {envType.map((option, index) => (*/}
{/* <Option key={option.id} value={option.id}>*/}
{/* {option.classifyName}*/}
{/* </Option>*/}
{/* ))}*/}
{/* </Select>*/}
{/* </FormItem>*/}
{/*</Grid.Col>*/}
<Grid.Col span={12}> <Grid.Col span={12}>
<FormItem label="部署环境:" field="tags"> <FormItem
<Select label="主机:"
placeholder="请选择部署环境" field="deployEnvId"
style={{ width: '90%' }} required
> rules={[
{envType.map((option, index) => ( {
<Option key={option.id} value={option.id}> validator: (value, cb) => {
{option.classifyName} if (!value) {
</Option> return cb('请选择主机');
))} }
</Select> return cb(null);
</FormItem> }
</Grid.Col> }
<Grid.Col span={12}> ]}
<FormItem label="主机:" field="type"> >
<Select <Select
placeholder="请选择主机" placeholder="请选择主机"
style={{ width: '90%' }} style={{ width: '90%' }}
allowClear={true}
> >
{runTypes.map((option, index) => ( {hostOptions.map((option, index) => (
<Option key={option.value} value={option.value}> <Option key={option.ip} value={option.id}>
{option.label} <div style={{ display: 'flex', justifyContent: 'space-between' }}>
<span>{option.name}</span>
<span style={{ color: '#999', fontSize: 12 }}>{option.ip}</span>
</div>
</Option> </Option>
))} ))}
</Select> </Select>

@ -19,6 +19,7 @@ const CollapseList: React.FC<CollapseListProps> = ({ searchKeyword, runStatus })
const [showOffSaleModal, setShowOffSaleModal] = useState(false); const [showOffSaleModal, setShowOffSaleModal] = useState(false);
const [selectedItem, setSelectedItem] = useState(null); // 选中的折叠面板数据 const [selectedItem, setSelectedItem] = useState(null); // 选中的折叠面板数据
const [expandedItem, setExpandedItem] = useState(null); // 当前展开的折叠面板数据 const [expandedItem, setExpandedItem] = useState(null); // 当前展开的折叠面板数据
const [addItem, setAddItem] = useState(null); // 点击新增实例按钮时记录当前信息
// 获取组件列表 // 获取组件列表
const getList = async () => { const getList = async () => {
@ -73,6 +74,7 @@ const CollapseList: React.FC<CollapseListProps> = ({ searchKeyword, runStatus })
getList(); getList();
}, [searchKeyword, runStatus]); }, [searchKeyword, runStatus]);
// 折叠面板头部
const headerNode = (item) => { const headerNode = (item) => {
const getRunStatus = () => { const getRunStatus = () => {
return runStatusDic.find((v) => v.value === runStatusConstant[item.runStatus]) || { return runStatusDic.find((v) => v.value === runStatusConstant[item.runStatus]) || {
@ -91,10 +93,10 @@ const CollapseList: React.FC<CollapseListProps> = ({ searchKeyword, runStatus })
<Space size={10}> <Space size={10}>
<Tag>{item.componentClassify}</Tag> <Tag>{item.componentClassify}</Tag>
<Tag>{item.arches}</Tag>
<Tag color={getRunStatus().color}>{getRunStatus().label}</Tag> <Tag color={getRunStatus().color}>{getRunStatus().label}</Tag>
<div className={styles['flex-box']}> <div className={styles['flex-box']}>
<img src={'/icons/countIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} /> <img src={'/icons/countIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />
<span style={{ color: '#A2A2AB' }}> :</span>
<span style={{ color: '#A2A2AB' }}>{item.instanceCount}</span> <span style={{ color: '#A2A2AB' }}>{item.instanceCount}</span>
</div> </div>
</Space> </Space>
@ -102,13 +104,17 @@ const CollapseList: React.FC<CollapseListProps> = ({ searchKeyword, runStatus })
); );
}; };
// 折叠面板右侧的额外节点
const extraNode = (item) => { const extraNode = (item) => {
return ( return (
<div className={styles['extra-node']}> <div className={styles['extra-node']}>
<Space size={20}> <Space size={20}>
{/*新增实例*/} {/*新增实例*/}
{item.runStatus === 'RUN' && ( {item.runStatus === 'RUN' && (
<div className={styles['flex-box']} onClick={() => setVisible(true)}> <div className={styles['flex-box']} onClick={() => {
setAddItem(item);
setVisible(true);
}}>
<img src={'/icons/addIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} /> <img src={'/icons/addIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />
<span style={{ color: '#A2A2AB' }}></span> <span style={{ color: '#A2A2AB' }}></span>
</div> </div>
@ -182,6 +188,7 @@ const CollapseList: React.FC<CollapseListProps> = ({ searchKeyword, runStatus })
</div> </div>
<AddModal <AddModal
addItem={addItem}
visible={visible} visible={visible}
setVisible={setVisible} setVisible={setVisible}
/> />

@ -1,11 +1,11 @@
.collapse-list { .collapse-list {
:global(.arco-collapse-item-header-extra) { .flex-box {
.flex-box { display: flex;
display: flex; align-items: center;
align-items: center; }
}
:global(.arco-collapse-item-header-extra) {
.custom-red { .custom-red {
color: #F53F3F; color: #F53F3F;

Loading…
Cancel
Save