feat(componentDeployment): 新增组件部署功能并优化UI交互

- 实现组件上架/下架功能,支持启停线上实例
- 新增环境类型选择器,从API动态获取环境配置
- 优化折叠列表样式,增强状态标签视觉反馈
- 添加搜索与状态筛选功能,提升组件查找效率
- 完善实例管理表格,支持分页加载与状态展示
- 引入模态框确认机制,防止误操作导致服务中断
- 调整页面布局结构,适配不同屏幕尺寸显示效果
master
钟良源 3 months ago
parent ececda16a7
commit 8a6f7183b3

@ -7,3 +7,13 @@ const urlPrefix = '/api/v1/bpms-workbench';
export function getDeployList(params) { export function getDeployList(params) {
return axios.get(`${urlPrefix}/componentDeploy/list`, { params }); return axios.get(`${urlPrefix}/componentDeploy/list`, { params });
} }
// 组件上架
export function componentOnSale(params) {
return axios.get(`${urlPrefix}/componentDeploy/start`, { params });
}
// 组件下架
export function componentOffSale(params) {
return axios.get(`${urlPrefix}/componentDeploy/stop`, { params });
}

@ -0,0 +1,34 @@
import axios from 'axios';
// 公共路径
const urlPrefix = '/api/v1/bpms-workbench';
// 新增实例
export function createInstance(params) {
return axios.post(`${urlPrefix}/componentInstance/create`, { params });
}
// 停止实例
export function stopInstance(params) {
return axios.get(`${urlPrefix}/componentInstance/stop`, { params });
}
// 启动实例
export function startInstance(params) {
return axios.get(`${urlPrefix}/componentInstance/start`, { params });
}
// 刷新实例依赖
export function refreshInstanceDependency(params) {
return axios.get(`${urlPrefix}/componentInstance/refreshDeps`, { params });
}
// 组件实例日志
export function getInstanceLog(params) {
return axios.get(`${urlPrefix}/componentInstance/logs`, { params });
}
// 组件实例列表
export function getInstanceList(params, identifier) {
return axios.get(`${urlPrefix}/componentInstance/list/${identifier}`, { params });
}

@ -1,6 +1,7 @@
import React, { 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 } from '@arco-design/web-react';
import EditableTable from '@/components/EditableTable'; import EditableTable from '@/components/EditableTable';
import { getComponentClassify } from '@/api/componentClassify';
const FormItem = Form.Item; const FormItem = Form.Item;
const Option = Select.Option; const Option = Select.Option;
@ -76,6 +77,7 @@ const deviceColumns = [
const AddModal = ({ visible, setVisible }) => { const AddModal = ({ visible, setVisible }) => {
const [currentRunType, setCurrentRunType] = useState('local'); const [currentRunType, setCurrentRunType] = useState('local');
const [envType, setEnvType] = useState([]); // 环境类型
const [tableData, setTableData] = useState([ const [tableData, setTableData] = useState([
{ {
key: '1', key: '1',
@ -85,6 +87,15 @@ const AddModal = ({ visible, setVisible }) => {
} }
]); ]);
const getEnvOptions = async () => {
const res: any = await getComponentClassify('docker-env');
if (res.code === 200) setEnvType(res.data);
};
useEffect(() => {
getEnvOptions();
}, []);
return ( return (
<Modal <Modal
title="新增实例" title="新增实例"
@ -124,9 +135,9 @@ const AddModal = ({ visible, setVisible }) => {
placeholder="请选择部署环境" placeholder="请选择部署环境"
style={{ width: '90%' }} style={{ width: '90%' }}
> >
{runTypes.map((option, index) => ( {envType.map((option, index) => (
<Option key={option.value} value={option.value}> <Option key={option.id} value={option.id}>
{option.label} {option.classifyName}
</Option> </Option>
))} ))}
</Select> </Select>
@ -147,136 +158,136 @@ const AddModal = ({ visible, setVisible }) => {
</FormItem> </FormItem>
</Grid.Col> </Grid.Col>
</Grid.Row> </Grid.Row>
<Grid.Row gutter={8}> {/*<Grid.Row gutter={8}>*/}
<Grid.Col span={12}> {/* <Grid.Col span={12}>*/}
<FormItem label="CPU核数" field="a"> {/* <FormItem label="CPU核数" field="a">*/}
<Slider {/* <Slider*/}
defaultValue={1} {/* defaultValue={1}*/}
min={1} {/* min={1}*/}
max={4} {/* max={4}*/}
step={1} {/* step={1}*/}
showTicks={true} {/* showTicks={true}*/}
marks={{ {/* marks={{*/}
1: '1核', {/* 1: '1核',*/}
2: '', {/* 2: '',*/}
3: '', {/* 3: '',*/}
4: '4核' {/* 4: '4核'*/}
}} {/* }}*/}
style={{ {/* style={{*/}
width: '90%', {/* width: '90%',*/}
whiteSpace: 'nowrap' {/* whiteSpace: 'nowrap'*/}
}} {/* }}*/}
/> {/* />*/}
</FormItem> {/* </FormItem>*/}
</Grid.Col> {/* </Grid.Col>*/}
<Grid.Col span={12}> {/* <Grid.Col span={12}>*/}
<FormItem label="是否使用GPU" field="b"> {/* <FormItem label="是否使用GPU" field="b">*/}
<Switch checkedText="ON" uncheckedText="OFF" /> {/* <Switch checkedText="ON" uncheckedText="OFF" />*/}
</FormItem> {/* </FormItem>*/}
</Grid.Col> {/* </Grid.Col>*/}
</Grid.Row> {/*</Grid.Row>*/}
<FormItem label="最大内存:"> {/*<FormItem label="最大内存:">*/}
<Slider {/* <Slider*/}
defaultValue={2048} {/* defaultValue={2048}*/}
min={64} {/* min={64}*/}
max={4069} {/* max={4069}*/}
step={64} {/* step={64}*/}
marks={{ {/* marks={{*/}
64: '64MB', {/* 64: '64MB',*/}
1024: '1GB', {/* 1024: '1GB',*/}
2048: '2GB', {/* 2048: '2GB',*/}
4069: '4GB' {/* 4069: '4GB'*/}
}} {/* }}*/}
showInput={{ {/* showInput={{*/}
hideControl: false, {/* hideControl: false,*/}
suffix: 'MB', {/* suffix: 'MB',*/}
style: { {/* style: {*/}
width: 100 {/* width: 100*/}
} {/* }*/}
}} {/* }}*/}
style={{ width: '100%' }} {/* style={{ width: '100%' }}*/}
/> {/* />*/}
</FormItem> {/*</FormItem>*/}
<Grid.Row gutter={8}> {/*<Grid.Row gutter={8}>*/}
<Grid.Col span={8}> {/* <Grid.Col span={8}>*/}
<FormItem label="网络模式:" field="tags"> {/* <FormItem label="网络模式:" field="tags">*/}
<Select {/* <Select*/}
placeholder="请选择网络模式" {/* placeholder="请选择网络模式"*/}
style={{ width: '90%' }} {/* style={{ width: '90%' }}*/}
> {/* >*/}
{runTypes.map((option, index) => ( {/* {runTypes.map((option, index) => (*/}
<Option key={option.value} value={option.value}> {/* <Option key={option.value} value={option.value}>*/}
{option.label} {/* {option.label}*/}
</Option> {/* </Option>*/}
))} {/* ))}*/}
</Select> {/* </Select>*/}
</FormItem> {/* </FormItem>*/}
</Grid.Col> {/* </Grid.Col>*/}
<Grid.Col span={8}> {/* <Grid.Col span={8}>*/}
<FormItem label="网卡:" field="type"> {/* <FormItem label="网卡:" field="type">*/}
<Select {/* <Select*/}
placeholder="请选择网卡" {/* placeholder="请选择网卡"*/}
style={{ width: '90%' }} {/* style={{ width: '90%' }}*/}
> {/* >*/}
{runTypes.map((option, index) => ( {/* {runTypes.map((option, index) => (*/}
<Option key={option.value} value={option.value}> {/* <Option key={option.value} value={option.value}>*/}
{option.label} {/* {option.label}*/}
</Option> {/* </Option>*/}
))} {/* ))}*/}
</Select> {/* </Select>*/}
</FormItem> {/* </FormItem>*/}
</Grid.Col> {/* </Grid.Col>*/}
<Grid.Col span={8}> {/* <Grid.Col span={8}>*/}
<FormItem label="IP" field="type"> {/* <FormItem label="IP" field="type">*/}
<Input style={{ width: '90%' }} allowClear placeholder="请输入IP" /> {/* <Input style={{ width: '90%' }} allowClear placeholder="请输入IP" />*/}
</FormItem> {/* </FormItem>*/}
</Grid.Col> {/* </Grid.Col>*/}
</Grid.Row> {/*</Grid.Row>*/}
<FormItem label="端口映射:"> {/*<FormItem label="端口映射:">*/}
<EditableTable {/* <EditableTable*/}
columns={portColumns} {/* columns={portColumns}*/}
data={tableData} {/* data={tableData}*/}
onDataChange={(newData) => setTableData(newData)} {/* onDataChange={(newData) => setTableData(newData)}*/}
showAddButton={true} {/* showAddButton={true}*/}
addButtonText="添加行" {/* addButtonText="添加行"*/}
showDeleteButton={true} {/* showDeleteButton={true}*/}
deleteButtonText="删除" {/* deleteButtonText="删除"*/}
tableProps={{ {/* tableProps={{*/}
pagination: { pageSize: 5 }, {/* pagination: { pageSize: 5 },*/}
scroll: { y: 400 } {/* scroll: { y: 400 }*/}
}} {/* }}*/}
/> {/* />*/}
</FormItem> {/*</FormItem>*/}
<FormItem label="目录挂载:"> {/*<FormItem label="目录挂载:">*/}
<EditableTable {/* <EditableTable*/}
columns={directoryColumns} {/* columns={directoryColumns}*/}
data={tableData} {/* data={tableData}*/}
onDataChange={(newData) => setTableData(newData)} {/* onDataChange={(newData) => setTableData(newData)}*/}
showAddButton={true} {/* showAddButton={true}*/}
addButtonText="添加行" {/* addButtonText="添加行"*/}
showDeleteButton={true} {/* showDeleteButton={true}*/}
deleteButtonText="删除" {/* deleteButtonText="删除"*/}
tableProps={{ {/* tableProps={{*/}
pagination: { pageSize: 5 }, {/* pagination: { pageSize: 5 },*/}
scroll: { y: 400 } {/* scroll: { y: 400 }*/}
}} {/* }}*/}
/> {/* />*/}
</FormItem> {/*</FormItem>*/}
<FormItem label="设备挂载:"> {/*<FormItem label="设备挂载:">*/}
<EditableTable {/* <EditableTable*/}
columns={deviceColumns} {/* columns={deviceColumns}*/}
data={tableData} {/* data={tableData}*/}
onDataChange={(newData) => setTableData(newData)} {/* onDataChange={(newData) => setTableData(newData)}*/}
showAddButton={true} {/* showAddButton={true}*/}
addButtonText="添加行" {/* addButtonText="添加行"*/}
showDeleteButton={true} {/* showDeleteButton={true}*/}
deleteButtonText="删除" {/* deleteButtonText="删除"*/}
tableProps={{ {/* tableProps={{*/}
pagination: { pageSize: 5 }, {/* pagination: { pageSize: 5 },*/}
scroll: { y: 400 } {/* scroll: { y: 400 }*/}
}} {/* }}*/}
/> {/* />*/}
</FormItem> {/*</FormItem>*/}
</> </>
) )
} }

@ -1,29 +1,77 @@
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Collapse, Space, Tag, Button, Table, TableColumnProps } from '@arco-design/web-react'; import { Collapse, Space, Tag, Button, Table, TableColumnProps, Modal } from '@arco-design/web-react';
import styles from './style/collapseList.module.less'; import styles from './style/collapseList.module.less';
import ListNode from '@/pages/componentDevelopment/componentDeployment/listNode'; import ListNode from '@/pages/componentDevelopment/componentDeployment/listNode';
import AddModal from '@/pages/componentDevelopment/componentDeployment/addModal'; import AddModal from '@/pages/componentDevelopment/componentDeployment/addModal';
import { getDeployList } from '@/api/componentDeploy'; import { componentOnSale, componentOffSale, getDeployList } from '@/api/componentDeploy';
import { runStatusConstant, runStatusDic } from '@/const/isdp/componentDeploy'; import { runStatusConstant, runStatusDic } from '@/const/isdp/componentDeploy';
const CollapseItem = Collapse.Item; const CollapseItem = Collapse.Item;
const CollapseList = () => { interface CollapseListProps {
searchKeyword?: string;
runStatus?: string;
}
const CollapseList: React.FC<CollapseListProps> = ({ searchKeyword, runStatus }) => {
const [collapses, setCollapses] = useState([]); const [collapses, setCollapses] = useState([]);
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [showOffSaleModal, setShowOffSaleModal] = useState(false);
const [selectedItem, setSelectedItem] = useState(null); // 选中的折叠面板数据
const [expandedItem, setExpandedItem] = useState(null); // 当前展开的折叠面板数据
// 获取组件列表
const getList = async () => { const getList = async () => {
const params = { const params: any = {
current: 1, current: 1,
size: 10 size: 10
}; };
// 添加搜索关键词
if (searchKeyword) {
params.name = searchKeyword;
}
// 添加运行状态筛选
if (runStatus) {
params.runStatus = runStatus;
}
const res: any = await getDeployList(params); const res: any = await getDeployList(params);
if (res.code === 200) setCollapses(res.data.records); if (res.code === 200) setCollapses(res.data.records);
}; };
// 上架组件
const componentOnSaleHandler = async (value) => {
const res: any = await componentOnSale({ identifier: value.identifier });
if (res.code === 200) getList();
else {
Modal.error({
title: '上架失败',
content: res.message
});
}
};
// 下架组件
const componentOffSaleHandler = async (stopInstance: boolean) => {
const res: any = await componentOffSale({ identifier: selectedItem.identifier, stopInstance });
if (res.code === 200) {
getList();
setShowOffSaleModal(false);
}
else {
Modal.error({
title: '下架失败',
content: res.message
});
}
};
useEffect(() => { useEffect(() => {
getList(); getList();
}, []); }, [searchKeyword, runStatus]);
const headerNode = (item) => { const headerNode = (item) => {
const getRunStatus = () => { const getRunStatus = () => {
@ -54,26 +102,42 @@ const CollapseList = () => {
); );
}; };
const extraNode = () => { const extraNode = (item) => {
return ( return (
<div className={styles['extra-node']}> <div className={styles['extra-node']}>
<Space size={20}> <Space size={20}>
{/*<div className={styles['flex-box']}>*/} {/*新增实例*/}
{/* <img src={'/icons/compileIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />*/} {item.runStatus === 'RUN' && (
{/* <span style={{ color: '#A2A2AB' }}>未编译</span>*/} <div className={styles['flex-box']} onClick={() => setVisible(true)}>
{/*</div>*/} <img src={'/icons/addIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />
{/*<div className={styles['flex-box']}>*/} <span style={{ color: '#A2A2AB' }}></span>
{/* <img src={'/icons/recompileIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />*/} </div>
{/* <span style={{ color: '#A2A2AB' }}>重新编译</span>*/} )}
{/*</div>*/} {/*环境配置*/}
<div className={styles['flex-box']} onClick={() => setVisible(true)}> <div className={styles['flex-box']} onClick={() => setVisible(true)}>
<img src={'/icons/addIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} /> <img src={'/icons/envIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />
<span style={{ color: '#A2A2AB' }}></span> <span style={{ color: '#A2A2AB' }}></span>
</div>
<div className={styles['flex-box']}>
<img src={'/icons/removedIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />
<span style={{ color: '#A2A2AB' }}></span>
</div> </div>
{/*下架组件*/}
{item.runStatus === 'RUN' && (
<div className={`${styles['flex-box']} ${styles['custom-red']}`} onClick={() => {
setSelectedItem(item);
setShowOffSaleModal(true);
}}>
<img src={'/icons/removedIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />
<span></span>
</div>
)}
{/*上架组件*/}
{item.runStatus === 'STOP' && (
<div className={`${styles['flex-box']} ${styles['custom-blue']}`}
onClick={() => componentOnSaleHandler(item)}>
<img src={'/icons/removedIcon.png'}
style={{ width: 16, height: 16, marginRight: 5, transform: 'rotate(180deg)' }} />
<span></span>
</div>
)}
{/*更多操作*/}
<div className={styles['flex-box']}> <div className={styles['flex-box']}>
<img src={'/icons/moreIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} /> <img src={'/icons/moreIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />
<span style={{ color: '#A2A2AB' }}></span> <span style={{ color: '#A2A2AB' }}></span>
@ -89,15 +153,29 @@ const CollapseList = () => {
<Collapse <Collapse
expandIconPosition={'right'} expandIconPosition={'right'}
bordered={false} bordered={false}
onChange={(key, keys, e) => {
// 当展开某个折叠面板时,记录当前展开的 item 数据
if (keys && keys.length > 0) {
// 获取最后一个展开的 key当前操作的 key
const expandedKey = keys[keys.length - 1];
const expandedIndex = parseInt(expandedKey, 10);
const currentItem = collapses[expandedIndex];
setExpandedItem(currentItem);
}
else {
// 所有面板都折叠时,清空 expandedItem
setExpandedItem(null);
}
}}
> >
{collapses.map((item, index) => ( {collapses.map((item, index) => (
<CollapseItem <CollapseItem
key={item.identifier} key={item.identifier}
header={headerNode(item)} header={headerNode(item)}
name="1" name={index.toString()}
extra={extraNode()} extra={extraNode(item)}
> >
<ListNode /> <ListNode componentData={item} />
</CollapseItem> </CollapseItem>
))} ))}
</Collapse> </Collapse>
@ -107,6 +185,33 @@ const CollapseList = () => {
visible={visible} visible={visible}
setVisible={setVisible} setVisible={setVisible}
/> />
<Modal
title={'下架组件'}
visible={showOffSaleModal}
style={{ width: '45%' }}
onCancel={() => {
setSelectedItem(null);
}}
footer={[
<Button key="cancel" onClick={() => setShowOffSaleModal(false)}>
</Button>,
<Button key="offshelf" type="primary" onClick={() => {
componentOffSaleHandler(false);
}}>
</Button>,
<Button key="stopAndOffshelf" type="primary" status="danger" onClick={() => {
componentOffSaleHandler(true);
}}>
线
</Button>
]}
>
<p></p>
<p> 线使线</p>
</Modal>
</> </>
); );
}; };

@ -1,21 +1,36 @@
import React from 'react'; import React, { useState } from 'react';
import styles from './style/index.module.less'; import styles from './style/index.module.less';
import { Button, Input, Radio, Space } from '@arco-design/web-react'; import { Button, Input, Radio, Space } from '@arco-design/web-react';
import { IconSearch } from '@arco-design/web-react/icon'; import { IconSearch } from '@arco-design/web-react/icon';
import CollapseList from './collapseList'; import CollapseList from './collapseList';
import { startStatusConstant } from '@/const/isdp/componentDeploy';
const ComponentDeployment = () => { const ComponentDeployment = () => {
const [searchKeyword, setSearchKeyword] = useState('');
const [selectedStatus, setSelectedStatus] = useState<string | undefined>(undefined);
// 状态选项配置
const statusOptions = [
{ label: '全部', value: undefined },
{ label: '启用中', value: "RUN" },
{ label: '已下架', value: "STOP" }
];
return ( return (
<div className={styles['component-deployment']}> <div className={styles['component-deployment']}>
<div className={styles['header']}> <div className={styles['header']}>
<Radio.Group defaultValue={'Beijing'} name="button-radio-group"> <Radio.Group
{['全部', '启用中', '已下架'].map((item) => { value={selectedStatus}
onChange={(value) => setSelectedStatus(value)}
name="button-radio-group"
>
{statusOptions.map((item) => {
return ( return (
<Radio key={item} value={item}> <Radio key={item.label} value={item.value}>
{({ checked }) => { {({ checked }) => {
return ( return (
<Button tabIndex={-1} key={item} shape="round" type={checked ? 'primary' : 'default'}> <Button tabIndex={-1} key={item.label} shape="round" type={checked ? 'primary' : 'default'}>
{item} {item.label}
</Button> </Button>
); );
}} }}
@ -29,6 +44,11 @@ const ComponentDeployment = () => {
prefix={<IconSearch />} prefix={<IconSearch />}
placeholder={'搜索'} placeholder={'搜索'}
style={{ width: 236 }} style={{ width: 236 }}
value={searchKeyword}
onChange={(value) => setSearchKeyword(value)}
onPressEnter={() => {
// 触发搜索
}}
/> />
<Button <Button
type="primary" type="primary"
@ -38,8 +58,8 @@ const ComponentDeployment = () => {
</Button> </Button>
</Space> </Space>
</div> </div>
<div className="content"> <div className={styles['content']}>
<CollapseList></CollapseList> <CollapseList searchKeyword={searchKeyword} runStatus={selectedStatus} />
</div> </div>
</div> </div>
); );

@ -1,39 +1,72 @@
import React from "react"; import React, { useEffect, useState } from 'react';
import { Button, Space, Table, TableColumnProps } from '@arco-design/web-react'; import { Button, Space, Table, TableColumnProps } from '@arco-design/web-react';
import styles from '@/pages/componentDevelopment/componentDeployment/style/collapseList.module.less'; import styles from '@/pages/componentDevelopment/componentDeployment/style/collapseList.module.less';
import { getInstanceList } from '@/api/componentInstance';
const ListNode = () => { interface ListNodeProps {
componentData: any; // 组件数据
}
const ListNode: React.FC<ListNodeProps> = ({ componentData }) => {
const [data, setData] = useState([]);
const [loading, setLoading] = useState(false);
// 获取实例列表
const fetchInstanceList = async () => {
if (!componentData?.identifier) return;
setLoading(true);
try {
const params = {
current: 1,
size: 10
};
const res: any = await getInstanceList(params, componentData.identifier);
if (res.code === 200) {
setData(res.data.records || []);
}
} catch (error) {
console.error('获取实例列表失败:', error);
} finally {
setLoading(false);
}
};
// 监听 componentData 变化,调用接口
useEffect(() => {
fetchInstanceList();
}, [componentData]);
const columns: TableColumnProps[] = [ const columns: TableColumnProps[] = [
{ {
title: '#', title: '#',
dataIndex: 'key', dataIndex: 'key',
align: 'center' align: 'center',
render: (col, record, index) => index + 1
}, },
{ {
title: '组件标识', title: '组件标识',
dataIndex: 'name', dataIndex: 'identifier',
align: 'center' align: 'center'
}, },
{ {
title: '实例名称', title: '实例名称',
dataIndex: 'salary', dataIndex: 'name',
align: 'center' align: 'center'
}, },
{ {
title: '运行类型', title: '运行类型',
dataIndex: 'address', dataIndex: 'runType',
align: 'center' align: 'center'
}, },
{ {
title: '运行状态', title: '运行状态',
dataIndex: 'email', dataIndex: 'runStatus',
align: 'center' align: 'center'
}, },
{ {
title: '创建时间', title: '创建时间',
dataIndex: 'email', dataIndex: 'createTime',
align: 'center' align: 'center'
}, },
{ {
@ -43,8 +76,6 @@ const ListNode = () => {
render: (col, record, index) => ( render: (col, record, index) => (
<div className={styles['table-handle-box']}> <div className={styles['table-handle-box']}>
<Space size={20}> <Space size={20}>
<Button type="text"></Button>
<Button type="text"></Button>
<Button type="text"></Button> <Button type="text"></Button>
<Button type="text"></Button> <Button type="text"></Button>
<Button type="text" <Button type="text"
@ -67,46 +98,16 @@ const ListNode = () => {
) )
} }
]; ];
const data = [
{
key: '1',
name: 'Jane Doe',
salary: 23000,
address: '32 Park Road, London',
email: 'jane.doe@example.com'
},
{
key: '2',
name: 'Alisa Ross',
salary: 25000,
address: '35 Park Road, London',
email: 'alisa.ross@example.com'
},
{
key: '3',
name: 'Kevin Sandra',
salary: 22000,
address: '31 Park Road, London',
email: 'kevin.sandra@example.com'
},
{
key: '4',
name: 'Ed Hellen',
salary: 17000,
address: '42 Park Road, London',
email: 'ed.hellen@example.com'
},
{
key: '5',
name: 'William Smith',
salary: 27000,
address: '62 Park Road, London',
email: 'william.smith@example.com'
}
];
return ( return (
<Table pagination={false} border={false} columns={columns} data={data} /> <Table
) loading={loading}
} pagination={false}
border={false}
columns={columns}
data={data}
/>
);
};
export default ListNode; export default ListNode;

@ -1,4 +1,36 @@
.collapse-list { .collapse-list {
:global(.arco-collapse-item-header-extra) {
.flex-box {
display: flex;
align-items: center;
}
.custom-red {
color: #F53F3F;
img {
filter: brightness(0) saturate(100%) invert(38%) sepia(85%) saturate(3091%) hue-rotate(342deg) brightness(99%) contrast(93%);
}
span {
color: #F53F3F;
}
}
.custom-blue {
color: #3491FA;
img {
filter: brightness(0) saturate(100%) invert(48%) sepia(98%) saturate(1672%) hue-rotate(195deg) brightness(101%) contrast(98%);
}
span {
color: #3491FA;
}
}
}
:global(.arco-collapse-item-content-box) { :global(.arco-collapse-item-content-box) {
padding: 0; padding: 0;
} }
@ -13,10 +45,6 @@
margin-right: 20px; margin-right: 20px;
} }
.flex-box {
display: flex;
align-items: center;
}
.table-handle-box { .table-handle-box {
:global(.arco-btn) { :global(.arco-btn) {

@ -1,7 +1,9 @@
.component-deployment { .component-deployment {
height: 98%; height: 100%;
background-color: #ffffff; background-color: #ffffff;
padding: 17px 19px 0 24px; padding: 17px 19px 0 24px;
display: flex;
flex-direction: column;
.header { .header {
display: flex; display: flex;
@ -9,5 +11,13 @@
padding-bottom: 15px; padding-bottom: 15px;
border-bottom: 1px solid #ebebeb; border-bottom: 1px solid #ebebeb;
margin-bottom: 25px; margin-bottom: 25px;
flex-shrink: 0;
}
.content {
flex: 1;
overflow: auto;
min-height: 0;
padding-bottom: 150px;
} }
} }
Loading…
Cancel
Save