|
|
import React, { useEffect, useState } from 'react';
|
|
|
import {
|
|
|
Collapse,
|
|
|
Space,
|
|
|
Tag,
|
|
|
Button,
|
|
|
Table,
|
|
|
TableColumnProps,
|
|
|
Modal,
|
|
|
Dropdown,
|
|
|
Menu,
|
|
|
Pagination,
|
|
|
Message
|
|
|
} from '@arco-design/web-react';
|
|
|
import { IconDown, IconToBottom, IconEye } from '@arco-design/web-react/icon';
|
|
|
import styles from './style/collapseList.module.less';
|
|
|
import ListNode from '@/pages/componentDevelopment/componentDeployment/listNode';
|
|
|
import AddModal from '@/pages/componentDevelopment/componentDeployment/addModal';
|
|
|
import { componentOnSale, componentOffSale, getDeployList } from '@/api/componentDeploy';
|
|
|
import { runStatusConstant, runStatusDic } from '@/const/isdp/componentDeploy';
|
|
|
|
|
|
const CollapseItem = Collapse.Item;
|
|
|
|
|
|
interface CollapseListProps {
|
|
|
searchKeyword?: string;
|
|
|
runStatus?: string;
|
|
|
}
|
|
|
|
|
|
const CollapseList: React.FC<CollapseListProps> = ({ searchKeyword, runStatus }) => {
|
|
|
const [collapses, setCollapses] = useState([]);
|
|
|
const [visible, setVisible] = useState(false);
|
|
|
const [showOffSaleModal, setShowOffSaleModal] = useState(false);
|
|
|
const [selectedItem, setSelectedItem] = useState(null); // 选中的折叠面板数据
|
|
|
const [expandedItem, setExpandedItem] = useState(null); // 当前展开的折叠面板数据
|
|
|
const [addItem, setAddItem] = useState(null); // 点击新增实例按钮时记录当前信息
|
|
|
|
|
|
// 分页相关状态
|
|
|
const [current, setCurrent] = useState(1);
|
|
|
const [pageSize, setPageSize] = useState(10);
|
|
|
const [total, setTotal] = useState(0);
|
|
|
|
|
|
// 获取组件列表
|
|
|
const getList = async (page = current, size = pageSize) => {
|
|
|
const params: any = {
|
|
|
current: page,
|
|
|
size: size
|
|
|
};
|
|
|
|
|
|
// 添加搜索关键词
|
|
|
if (searchKeyword) {
|
|
|
params.name = searchKeyword;
|
|
|
}
|
|
|
|
|
|
// 添加运行状态筛选
|
|
|
if (runStatus) {
|
|
|
params.runStatus = runStatus;
|
|
|
}
|
|
|
|
|
|
const res: any = await getDeployList(params);
|
|
|
if (res.code === 200) {
|
|
|
setCollapses(res.data.list.reverse());
|
|
|
setTotal(res.data.total || res.data.totalCount);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 分页变化处理
|
|
|
const handlePageChange = (page: number, size: number) => {
|
|
|
setCurrent(page);
|
|
|
setPageSize(size);
|
|
|
getList(page, size);
|
|
|
};
|
|
|
|
|
|
// 上架组件
|
|
|
const componentOnSaleHandler = async (value) => {
|
|
|
const res: any = await componentOnSale({ identifier: value.identifier });
|
|
|
if (res.code === 200) {
|
|
|
Message.success({
|
|
|
content: '上架成功'
|
|
|
});
|
|
|
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) {
|
|
|
Message.success({ content: '下架成功' });
|
|
|
getList();
|
|
|
setShowOffSaleModal(false);
|
|
|
}
|
|
|
else {
|
|
|
Modal.error({
|
|
|
title: '下架失败',
|
|
|
content: res.message
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 查看组件
|
|
|
const handleViewComponent = (item: any) => {
|
|
|
// 先触发跳转事件
|
|
|
const navigateEvent = new CustomEvent('navigateToTab', {
|
|
|
detail: {
|
|
|
path: 'componentList'
|
|
|
}
|
|
|
});
|
|
|
document.dispatchEvent(navigateEvent);
|
|
|
|
|
|
// 延迟触发搜索事件,确保页面已经切换
|
|
|
setTimeout(() => {
|
|
|
const searchEvent = new CustomEvent('componentListSearch', {
|
|
|
detail: {
|
|
|
searchKeyword: item.name
|
|
|
}
|
|
|
});
|
|
|
window.dispatchEvent(searchEvent);
|
|
|
}, 100);
|
|
|
};
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
setCurrent(1); // 搜索条件变化时重置到第一页
|
|
|
getList(1, pageSize);
|
|
|
}, [searchKeyword, runStatus]);
|
|
|
|
|
|
// 折叠面板头部
|
|
|
const headerNode = (item) => {
|
|
|
const getRunStatus = () => {
|
|
|
return runStatusDic.find((v) => v.value === runStatusConstant[item.runStatus]) || {
|
|
|
color: 'gray',
|
|
|
label: '未知'
|
|
|
};
|
|
|
};
|
|
|
|
|
|
return (
|
|
|
<div className={styles['header-node']}>
|
|
|
<Space size={7} style={{ marginRight: 50 }}>
|
|
|
<img src="https://picsum.photos/200/300"
|
|
|
style={{ width: 50, height: 50, borderRadius: 6, overflow: 'hidden' }} />
|
|
|
<div>{item.name}</div>
|
|
|
</Space>
|
|
|
|
|
|
<Space size={10}>
|
|
|
<Tag>{item.componentClassify}</Tag>
|
|
|
<Tag>{item.codeLanguage}</Tag>
|
|
|
<Tag color={getRunStatus().color}>{getRunStatus().label}</Tag>
|
|
|
<div className={styles['flex-box']}>
|
|
|
<img src={'/icons/countIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />
|
|
|
<span style={{ color: '#A2A2AB' }}> 实例数:</span>
|
|
|
<span style={{ color: '#A2A2AB' }}>{item.instanceCount}</span>
|
|
|
</div>
|
|
|
</Space>
|
|
|
</div>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
// 折叠面板右侧的额外节点
|
|
|
const extraNode = (item) => {
|
|
|
return (
|
|
|
<div className={styles['extra-node']}>
|
|
|
<Space size={20}>
|
|
|
{/*新增实例*/}
|
|
|
{item.runStatus === 'RUN' && (
|
|
|
<div className={styles['flex-box']} onClick={() => {
|
|
|
setAddItem(item);
|
|
|
setVisible(true);
|
|
|
}}>
|
|
|
<img src={'/icons/addIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />
|
|
|
<span style={{ color: '#A2A2AB' }}>新增实例</span>
|
|
|
</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>
|
|
|
)}
|
|
|
{/*更多操作*/}
|
|
|
<Dropdown
|
|
|
droplist={
|
|
|
<Menu>
|
|
|
<Menu.Item key="viewComponent" onClick={() => handleViewComponent(item)}>
|
|
|
<span style={{ color: '#3491FA' }}>
|
|
|
<IconEye />
|
|
|
查看组件
|
|
|
</span>
|
|
|
</Menu.Item>
|
|
|
</Menu>
|
|
|
}
|
|
|
position="br"
|
|
|
>
|
|
|
<div className={styles['flex-box']} style={{ cursor: 'pointer' }}>
|
|
|
<img src={'/icons/moreIcon.png'} style={{ width: 16, height: 16, marginRight: 5 }} />
|
|
|
<span style={{ color: '#A2A2AB' }}>更多操作</span>
|
|
|
<IconDown style={{ fontSize: 12, marginLeft: 4, color: '#A2A2AB' }} />
|
|
|
</div>
|
|
|
</Dropdown>
|
|
|
</Space>
|
|
|
</div>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
return (
|
|
|
<>
|
|
|
<div className={styles['collapse-list']}>
|
|
|
<Collapse
|
|
|
expandIconPosition={'right'}
|
|
|
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) => (
|
|
|
<CollapseItem
|
|
|
key={item.identifier}
|
|
|
header={headerNode(item)}
|
|
|
name={index.toString()}
|
|
|
extra={extraNode(item)}
|
|
|
>
|
|
|
<ListNode componentData={item} />
|
|
|
</CollapseItem>
|
|
|
))}
|
|
|
</Collapse>
|
|
|
|
|
|
{/* 分页组件 */}
|
|
|
{total > 0 && (
|
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 16 }}>
|
|
|
<Pagination
|
|
|
current={current}
|
|
|
pageSize={pageSize}
|
|
|
total={total}
|
|
|
// showTotal
|
|
|
pageSizeChangeResetCurrent
|
|
|
onChange={(page) => handlePageChange(page, pageSize)}
|
|
|
/>
|
|
|
</div>
|
|
|
)}
|
|
|
</div>
|
|
|
|
|
|
<AddModal
|
|
|
addItem={addItem}
|
|
|
visible={visible}
|
|
|
setVisible={setVisible}
|
|
|
onSuccess={getList}
|
|
|
/>
|
|
|
|
|
|
<Modal
|
|
|
title={'下架组件'}
|
|
|
visible={showOffSaleModal}
|
|
|
style={{ width: '45%' }}
|
|
|
onCancel={() => {
|
|
|
setSelectedItem(null);
|
|
|
setShowOffSaleModal(false);
|
|
|
}}
|
|
|
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>
|
|
|
</>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
export default CollapseList; |