diff --git a/src/api/componentDeploy.ts b/src/api/componentDeploy.ts index 5fcef26..aa4952d 100644 --- a/src/api/componentDeploy.ts +++ b/src/api/componentDeploy.ts @@ -6,4 +6,14 @@ const urlPrefix = '/api/v1/bpms-workbench'; // 部署列表 export function getDeployList(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 }); } \ No newline at end of file diff --git a/src/api/componentInstance.ts b/src/api/componentInstance.ts new file mode 100644 index 0000000..b468761 --- /dev/null +++ b/src/api/componentInstance.ts @@ -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 }); +} \ No newline at end of file diff --git a/src/pages/componentDevelopment/componentDeployment/addModal.tsx b/src/pages/componentDevelopment/componentDeployment/addModal.tsx index 6f5a24e..4223b41 100644 --- a/src/pages/componentDevelopment/componentDeployment/addModal.tsx +++ b/src/pages/componentDevelopment/componentDeployment/addModal.tsx @@ -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 EditableTable from '@/components/EditableTable'; +import { getComponentClassify } from '@/api/componentClassify'; const FormItem = Form.Item; const Option = Select.Option; @@ -76,6 +77,7 @@ const deviceColumns = [ const AddModal = ({ visible, setVisible }) => { const [currentRunType, setCurrentRunType] = useState('local'); + const [envType, setEnvType] = useState([]); // 环境类型 const [tableData, setTableData] = useState([ { 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 ( { placeholder="请选择部署环境" style={{ width: '90%' }} > - {runTypes.map((option, index) => ( - ))} @@ -147,136 +158,136 @@ const AddModal = ({ visible, setVisible }) => { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - setTableData(newData)} - showAddButton={true} - addButtonText="添加行" - showDeleteButton={true} - deleteButtonText="删除" - tableProps={{ - pagination: { pageSize: 5 }, - scroll: { y: 400 } - }} - /> - - - setTableData(newData)} - showAddButton={true} - addButtonText="添加行" - showDeleteButton={true} - deleteButtonText="删除" - tableProps={{ - pagination: { pageSize: 5 }, - scroll: { y: 400 } - }} - /> - - - setTableData(newData)} - showAddButton={true} - addButtonText="添加行" - showDeleteButton={true} - deleteButtonText="删除" - tableProps={{ - pagination: { pageSize: 5 }, - scroll: { y: 400 } - }} - /> - + {/**/} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/**/} + {/**/} + {/* */} + {/**/} + {/**/} + {/* */} + {/* */} + {/* */} + {/* {runTypes.map((option, index) => (*/} + {/* */} + {/* ))}*/} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* {runTypes.map((option, index) => (*/} + {/* */} + {/* ))}*/} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} + {/**/} + {/**/} + {/* setTableData(newData)}*/} + {/* showAddButton={true}*/} + {/* addButtonText="添加行"*/} + {/* showDeleteButton={true}*/} + {/* deleteButtonText="删除"*/} + {/* tableProps={{*/} + {/* pagination: { pageSize: 5 },*/} + {/* scroll: { y: 400 }*/} + {/* }}*/} + {/* />*/} + {/**/} + {/**/} + {/* setTableData(newData)}*/} + {/* showAddButton={true}*/} + {/* addButtonText="添加行"*/} + {/* showDeleteButton={true}*/} + {/* deleteButtonText="删除"*/} + {/* tableProps={{*/} + {/* pagination: { pageSize: 5 },*/} + {/* scroll: { y: 400 }*/} + {/* }}*/} + {/* />*/} + {/**/} + {/**/} + {/* setTableData(newData)}*/} + {/* showAddButton={true}*/} + {/* addButtonText="添加行"*/} + {/* showDeleteButton={true}*/} + {/* deleteButtonText="删除"*/} + {/* tableProps={{*/} + {/* pagination: { pageSize: 5 },*/} + {/* scroll: { y: 400 }*/} + {/* }}*/} + {/* />*/} + {/**/} ) } diff --git a/src/pages/componentDevelopment/componentDeployment/collapseList.tsx b/src/pages/componentDevelopment/componentDeployment/collapseList.tsx index 218a019..cf68d3e 100644 --- a/src/pages/componentDevelopment/componentDeployment/collapseList.tsx +++ b/src/pages/componentDevelopment/componentDeployment/collapseList.tsx @@ -1,29 +1,77 @@ 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 ListNode from '@/pages/componentDevelopment/componentDeployment/listNode'; 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'; const CollapseItem = Collapse.Item; -const CollapseList = () => { +interface CollapseListProps { + searchKeyword?: string; + runStatus?: string; +} + +const CollapseList: React.FC = ({ 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 getList = async () => { - const params = { + const params: any = { current: 1, size: 10 }; + + // 添加搜索关键词 + if (searchKeyword) { + params.name = searchKeyword; + } + + // 添加运行状态筛选 + if (runStatus) { + params.runStatus = runStatus; + } + const res: any = await getDeployList(params); 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(() => { getList(); - }, []); + }, [searchKeyword, runStatus]); const headerNode = (item) => { const getRunStatus = () => { @@ -54,26 +102,42 @@ const CollapseList = () => { ); }; - const extraNode = () => { + const extraNode = (item) => { return (
- {/*
*/} - {/* */} - {/* 未编译*/} - {/*
*/} - {/*
*/} - {/* */} - {/* 重新编译*/} - {/*
*/} + {/*新增实例*/} + {item.runStatus === 'RUN' && ( +
setVisible(true)}> + + 新增实例 +
+ )} + {/*环境配置*/}
setVisible(true)}> - - 新增实例 -
-
- - 下架组件 + + 环境配置
+ {/*下架组件*/} + {item.runStatus === 'RUN' && ( +
{ + setSelectedItem(item); + setShowOffSaleModal(true); + }}> + + 下架组件 +
+ )} + {/*上架组件*/} + {item.runStatus === 'STOP' && ( +
componentOnSaleHandler(item)}> + + 上架组件 +
+ )} + {/*更多操作*/}
更多操作 @@ -89,15 +153,29 @@ const CollapseList = () => { { + // 当展开某个折叠面板时,记录当前展开的 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) => ( - + ))} @@ -107,6 +185,33 @@ const CollapseList = () => { visible={visible} setVisible={setVisible} /> + + { + setSelectedItem(null); + }} + footer={[ + , + , + + ]} + > +

下架后该组件状态为编码中,不可继续新增实例等。

+

该组件存在线上部署的实例,可继续使用原有的代码逻辑继续运行,是否需要同步停止所有线上实例?

+
); }; diff --git a/src/pages/componentDevelopment/componentDeployment/index.tsx b/src/pages/componentDevelopment/componentDeployment/index.tsx index 17157b8..f51f61f 100644 --- a/src/pages/componentDevelopment/componentDeployment/index.tsx +++ b/src/pages/componentDevelopment/componentDeployment/index.tsx @@ -1,21 +1,36 @@ -import React from 'react'; +import React, { useState } from 'react'; import styles from './style/index.module.less'; import { Button, Input, Radio, Space } from '@arco-design/web-react'; import { IconSearch } from '@arco-design/web-react/icon'; import CollapseList from './collapseList'; +import { startStatusConstant } from '@/const/isdp/componentDeploy'; const ComponentDeployment = () => { + const [searchKeyword, setSearchKeyword] = useState(''); + const [selectedStatus, setSelectedStatus] = useState(undefined); + + // 状态选项配置 + const statusOptions = [ + { label: '全部', value: undefined }, + { label: '启用中', value: "RUN" }, + { label: '已下架', value: "STOP" } + ]; + return (
- - {['全部', '启用中', '已下架'].map((item) => { + setSelectedStatus(value)} + name="button-radio-group" + > + {statusOptions.map((item) => { return ( - + {({ checked }) => { return ( - ); }} @@ -29,6 +44,11 @@ const ComponentDeployment = () => { prefix={} placeholder={'搜索'} style={{ width: 236 }} + value={searchKeyword} + onChange={(value) => setSearchKeyword(value)} + onPressEnter={() => { + // 触发搜索 + }} />
-
- +
+
); }; -export default ComponentDeployment; \ No newline at end of file +export default ComponentDeployment; diff --git a/src/pages/componentDevelopment/componentDeployment/listNode.tsx b/src/pages/componentDevelopment/componentDeployment/listNode.tsx index 757f55a..dd91cf5 100644 --- a/src/pages/componentDevelopment/componentDeployment/listNode.tsx +++ b/src/pages/componentDevelopment/componentDeployment/listNode.tsx @@ -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 styles from '@/pages/componentDevelopment/componentDeployment/style/collapseList.module.less'; +import { getInstanceList } from '@/api/componentInstance'; -const ListNode = () => { +interface ListNodeProps { + componentData: any; // 组件数据 +} + +const ListNode: React.FC = ({ 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[] = [ { title: '#', dataIndex: 'key', - align: 'center' + align: 'center', + render: (col, record, index) => index + 1 }, { title: '组件标识', - dataIndex: 'name', + dataIndex: 'identifier', align: 'center' }, { title: '实例名称', - dataIndex: 'salary', + dataIndex: 'name', align: 'center' }, { title: '运行类型', - dataIndex: 'address', + dataIndex: 'runType', align: 'center' }, { title: '运行状态', - dataIndex: 'email', + dataIndex: 'runStatus', align: 'center' }, { title: '创建时间', - dataIndex: 'email', + dataIndex: 'createTime', align: 'center' }, { @@ -43,8 +76,6 @@ const ListNode = () => { render: (col, record, index) => (
- -