feat(instance): 对接应用实例页面中所需的api

- 完成基础数据渲染
master
钟良源 5 months ago
parent 8a0c58b397
commit 904f1da2ea

@ -0,0 +1,25 @@
import axios from 'axios';
import { apiResData } from '@/api/interface/index';
// 公共路径
const urlPrefix = '/api/v1/bpms-workbench';
// 获取应用实例列表
export function getInstances(data: any) {
return axios.post<apiResData>(`${urlPrefix}/appIns/page`, data);
}
// 获取应用实例节点数据
export function getNodeData(appId: string) {
return axios.get<apiResData>(`${urlPrefix}/appIns/${appId}/nodeData`);
}
// 获取应用实例数据
export function getInstanceDefinition(id: any) {
return axios.get<apiResData>(`${urlPrefix}/appIns/${id}/render`);
}
// 获取应用实例资源
export function getInstanceResData(id: any) {
return axios.get<apiResData>(`${urlPrefix}/appIns/${id}/res`);
}

@ -0,0 +1,106 @@
import axios from 'axios';
import { apiResData, queryParams, applicationModel, publishApi, paramsT } from '@/api/interface/index';
// 公共路径
const urlPrefix = '/api/v1/bpms-workbench';
const runPrefix = '/api/v1/bpms-runtime';
// 个人分页
export function getMyAppList(data: queryParams) {
return axios.post<apiResData>(`${urlPrefix}/apps/minePage`, data);
}
// 公共分页
export function getPubAppList(data: queryParams) {
return axios.post<apiResData>(`${urlPrefix}/apps/publicPage`, data);
}
// 协调分页
export function getTeamAppList(data: queryParams) {
return axios.post<apiResData>(`${urlPrefix}/apps/teamPage`, data);
}
// 根据场景id分页
export function getAppListBySceneId(data: queryParams) {
return axios.post<apiResData>(`${urlPrefix}/apps/page`, data);
}
// 新增应用
export function addApp(data: applicationModel) {
return axios.post(`${urlPrefix}/apps`, data);
}
// 编辑应用
export function editApp(data: applicationModel) {
return axios.put(`${urlPrefix}/apps`, data);
}
// 删除应用
export function deleteApp(id: string) {
return axios.delete(`${urlPrefix}/apps/${id}`);
}
// 复制应用
export function copyApp(data: any) {
return axios.post(`${urlPrefix}/apps/copy`, data);
}
// 导入应用
export function importApp(data: any) {
return axios.post(`${urlPrefix}/apps/import`, data);
}
// 导出应用
export function exportApp(data: any) {
return axios({
method: 'post',
url: `${urlPrefix}/apps/export`,
responseType: 'blob',
data: data
});
}
// 运行主流程
export function runMainFlow(data: any) {
return axios.post<apiResData>(`${runPrefix}/apps/run`, data);
}
// 运行子流程
export function runSubFlow(data: any) {
return axios.post<apiResData>(`${runPrefix}/apps/runSubflow`, data);
}
// 重运行
export function reRunApp(data: any) {
return axios.post<apiResData>(`${runPrefix}/apps/rerun`, data);
}
// 暂停
export function pauseApp(data: any) {
return axios.post<apiResData>(`${runPrefix}/apps/${data.id}/pause`);
}
// 恢复
export function resumeApp(data: any) {
return axios.post<apiResData>(`${runPrefix}/apps/${data.id}/resume`);
}
// 停止
export function stopApp(data: any) {
return axios.post<apiResData>(`${runPrefix}/apps/${data.id}/stop`);
}
// APi发布
export function apiPublish(data: publishApi) {
return axios.post<paramsT>(`${urlPrefix}/apps/apiPublish`, data);
}
// 获取api信息
export function getPublishApi(appId: string) {
return axios.get<paramsT>(`${urlPrefix}/apps/getPublishApi/${appId}`);
}
// 刷新Api
export function refreshToken(data: publishApi) {
return axios.post<paramsT>(`${urlPrefix}/apps/apiTokenRefresh`, data);
}

@ -1,4 +1,4 @@
import React from 'react'; import React, { useState, useEffect } from 'react';
import styles from './style/index.module.less'; import styles from './style/index.module.less';
import CustomCard from '@/components/CustomCard'; import CustomCard from '@/components/CustomCard';
import Overview from './overview'; import Overview from './overview';
@ -13,6 +13,9 @@ import {
IconEye IconEye
} from '@arco-design/web-react/icon'; } from '@arco-design/web-react/icon';
import { formatInstanceStatus, formatInstanceType, formatTimestamp } from '@/utils/common'; import { formatInstanceStatus, formatInstanceType, formatTimestamp } from '@/utils/common';
import { getInstances } from '@/api/appIns';
import { getOverviewApp } from '@/api/overview';
import { getMyAppList } from '@/api/apps';
const Option = Select.Option; const Option = Select.Option;
@ -78,66 +81,6 @@ const columns: TableColumnProps[] = [
} }
]; ];
const data = [
{
'appId': '1951085958320037889',
'appResHistoryId': '1951157955455545345',
'createBy': '1123598821738675201',
'createTime': 1754028849000,
'description': '',
'duration': 0,
'endTime': 0,
'id': '1951164528214003713',
'name': '复制:复制:轮胎装配流程',
'nodeNum': 35,
'progress': 14,
'runningNum': 5,
'startTime': 1754028849067,
'state': 'RUNNING',
'type': 'MANUAL',
'updateBy': '1123598821738675201',
'updateTime': 1754028849000
},
{
'appId': '1951085958320037889',
'appResHistoryId': '1951157955455545345',
'createBy': '1123598821738675201',
'createTime': 1754028826000,
'description': '',
'duration': 0,
'endTime': 0,
'id': '1951164430486720513',
'name': '复制:复制:轮胎装配流程',
'nodeNum': 35,
'progress': 14,
'runningNum': 5,
'startTime': 1754028825767,
'state': 'RUNNING',
'type': 'MANUAL',
'updateBy': '1123598821738675201',
'updateTime': 1754028826000
},
{
'appId': '1951085958320037889',
'appResHistoryId': '1951157955455545345',
'createBy': '1123598821738675201',
'createTime': 1754028784000,
'description': '',
'duration': 0,
'endTime': 0,
'id': '1951164255143841793',
'name': '复制:复制:轮胎装配流程',
'nodeNum': 35,
'progress': 14,
'runningNum': 5,
'startTime': 1754028783957,
'state': 'RUNNING',
'type': 'MANUAL',
'updateBy': '1123598821738675201',
'updateTime': 1754028784000
}
];
function checkInstance(instance) { function checkInstance(instance) {
console.log('instance:', instance); console.log('instance:', instance);
} }
@ -161,65 +104,158 @@ function getIcon(type) {
} }
} }
function Selector() { const Instance = () => {
const cities = ['Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen', 'Chengdu', 'Wuhan']; const [instanceData, setInstanceData] = useState({
return ( list: [],
<Select placeholder="输入搜索应用" style={{ width: 200 }} allowClear showSearch> totalCount: 0,
{cities.map((option, index) => ( totalPage: 0,
<Option key={option} disabled={index === 3} value={option}> currentPage: 1,
{option} pageSize: 10
</Option> });
))} const [searchOptions, setSearchOptions] = useState([]);
</Select> const [overviewData, setOverviewData] = useState({});
); const [searchParams, setSearchParams] = useState({
} appId: '',
state: '',
type: '',
durationDesc: false
});
function RunStatus() {
const cities = ['Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen', 'Chengdu', 'Wuhan'];
return (
<Select placeholder="无" style={{ width: 154 }} allowClear>
{cities.map((option, index) => (
<Option key={option} disabled={index === 3} value={option}>
{option}
</Option>
))}
</Select>
);
}
function Type() { const Selector = () => {
const cities = ['Beijing', 'Shanghai', 'Guangzhou', 'Shenzhen', 'Chengdu', 'Wuhan']; return (
return ( <Select placeholder="输入搜索应用" style={{ width: 200 }} allowClear showSearch>
<Select placeholder="无" style={{ width: 154 }} allowClear> {searchOptions.map((option, index) => (
{cities.map((option, index) => ( <Option key={option.id} value={option.name}>
<Option key={option} disabled={index === 3} value={option}> {option.name}
{option} </Option>
</Option> ))}
))} </Select>
</Select> );
); };
}
const RunStatus = () => {
const stateList = [
{
label: '暂停',
value: 'PAUSED'
},
{
label: '中止',
value: 'KILL'
},
{
label: '运行中',
value: 'RUNNING'
},
{
label: '停止',
value: 'STOPPED'
},
{
label: '失败',
value: 'FAILURE'
},
{
label: '成功',
value: 'SUCCESS'
}
];
return (
<Select placeholder="无" style={{ width: 154 }} allowClear>
{stateList.map((option, index) => (
<Option key={option.value} value={option.value}>
{option.label}
</Option>
))}
</Select>
);
};
const Type = () => {
const typeDict = [
// {
// label: 'HOOK',
// value: 'HOOK',
// },
{
label: '定时任务',
value: 'TIMER'
},
{
label: '运行应用',
value: 'MANUAL'
},
{
label: '运行子流程',
value: 'MANUAL_SUB'
}
];
return (
<Select placeholder="无" style={{ width: 154 }} allowClear>
{typeDict.map((option, index) => (
<Option key={option.value} value={option.value}>
{option.label}
</Option>
))}
</Select>
);
};
// 获取实例列表和概览数据
const fetchData = async (params: any = {}) => {
const requestParams: any = {
appId: searchParams.appId,
state: searchParams.state,
type: searchParams.type,
currPage: params.currPage || instanceData.currentPage,
pageSize: params.pageSize || instanceData.pageSize,
total: 0,
durationDesc: searchParams.durationDesc
};
if (!requestParams.state) delete requestParams.state;
if (!requestParams.type) delete requestParams.type;
if (!requestParams.appId) delete requestParams.appId;
function generateData() { const res: any = await getInstances(requestParams);
const newData = []; if (res.code === 200) {
for (let i = 0; i < 11; i++) { setInstanceData({
data.forEach((item, index) => { ...res.data,
newData.push({ currentPage: params.currPage || instanceData.currentPage,
...item, pageSize: params.pageSize || instanceData.pageSize
key: `${item.appId}-${i}` // 确保key唯一
}); });
}
const overviewData: any = await getOverviewApp(requestParams.appId);
if (overviewData.code === 200) setOverviewData(overviewData.data);
};
const getSearchOptions = async () => {
const res: any = await getMyAppList({
currPage: 1,
pageSize: 999
}); });
} if (res.code === 200) setSearchOptions(res.data.list);
return newData; };
}
useEffect(() => {
fetchData();
getSearchOptions();
}, []);
const handlePageChange = (page: number) => {
fetchData({ currPage: page });
};
const handlePageSizeChange = (pageSize: number) => {
fetchData({ pageSize, currPage: 1 });
};
function Instance() {
const newData = generateData();
return ( return (
<> <>
<div className={styles['instanceContainer']}> <div className={styles['instanceContainer']}>
<CustomCard> <CustomCard>
<Overview></Overview> <Overview overviewData={overviewData} />
<Space <Space
size={50} size={50}
style={{ marginTop: '20px', marginBottom: '30px' }} style={{ marginTop: '20px', marginBottom: '30px' }}
@ -241,11 +277,23 @@ function Instance() {
<Switch /> <Switch />
</div> </div>
</Space> </Space>
<Table columns={columns} data={newData} /> <Table
columns={columns}
data={instanceData.list}
pagination={{
total: instanceData.totalCount,
current: instanceData.currentPage,
pageSize: instanceData.pageSize,
showTotal: true,
sizeOptions: [10, 20, 30, 50],
onChange: handlePageChange,
onPageSizeChange: handlePageSizeChange
}}
/>
</CustomCard> </CustomCard>
</div> </div>
</> </>
); );
} };
export default Instance; export default Instance;

@ -10,6 +10,7 @@ import IconCalendar from './assets/calendar.svg';
import IconComments from './assets/comments.svg'; import IconComments from './assets/comments.svg';
import IconContent from './assets/content.svg'; import IconContent from './assets/content.svg';
import IconIncrease from './assets/increase.svg'; import IconIncrease from './assets/increase.svg';
import { formatSeconds } from '@/utils/common';
const { Row, Col } = Grid; const { Row, Col } = Grid;
@ -40,31 +41,19 @@ function StatisticItem(props: StatisticItemType) {
} }
type DataType = { type DataType = {
allContents?: string; avgTime?: number;
liveContents?: string; runningNum?: number;
increaseComments?: string; successNum?: number;
growthRate?: string; failureNum?: number;
down?: boolean;
}; };
function Overview() { const Overview = ({ overviewData }) => {
const [data, setData] = useState<DataType>({}); const [data, setData] = useState<DataType>({});
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(false);
const fetchData = () => {
setLoading(true);
setData({
allContents: '1',
liveContents: '1,397',
increaseComments: '1,837',
growthRate: '650'
});
setLoading(false);
};
useEffect(() => { useEffect(() => {
fetchData(); setData(overviewData);
}, []); }, [overviewData]);
return ( return (
<Card> <Card>
@ -73,9 +62,9 @@ function Overview() {
<StatisticItem <StatisticItem
icon={<IconIncrease />} icon={<IconIncrease />}
title="实例平均处理时间" title="实例平均处理时间"
count={data.allContents} count={data.avgTime < 1000 ? data.avgTime : Math.floor(data.avgTime / 1000 / 60)}
loading={loading} loading={loading}
unit="分" unit={data.avgTime >= 1000 ? '分' + formatSeconds(`${data.avgTime / 1000}`).split('分')[1] || formatSeconds(`${data.avgTime / 1000}`) : '毫秒'}
/> />
</Col> </Col>
<Divider type="vertical" className={styles.divider} /> <Divider type="vertical" className={styles.divider} />
@ -83,7 +72,7 @@ function Overview() {
<StatisticItem <StatisticItem
icon={<IconCalendar />} icon={<IconCalendar />}
title="运行中" title="运行中"
count={data.liveContents} count={data.runningNum}
loading={loading} loading={loading}
unit="个" unit="个"
/> />
@ -93,7 +82,7 @@ function Overview() {
<StatisticItem <StatisticItem
icon={<IconContent />} icon={<IconContent />}
title="成功数" title="成功数"
count={data.increaseComments} count={data.successNum}
loading={loading} loading={loading}
unit="个" unit="个"
/> />
@ -103,7 +92,7 @@ function Overview() {
<StatisticItem <StatisticItem
icon={<IconComments />} icon={<IconComments />}
title="失败数" title="失败数"
count={data.growthRate} count={data.failureNum}
loading={loading} loading={loading}
unit="个" unit="个"
/> />
@ -111,6 +100,6 @@ function Overview() {
</Row> </Row>
</Card> </Card>
); );
} };
export default Overview; export default Overview;

@ -96,6 +96,10 @@ export function formatInstanceType(value: string): string {
switch (value) { switch (value) {
case 'MANUAL': case 'MANUAL':
return '运行应用'; return '运行应用';
case 'MANUAL_SUB':
return '运行子流程';
case 'TIMER':
return '定时任务';
default: default:
return value; return value;
} }
@ -117,6 +121,8 @@ export function formatInstanceStatus(value: string): string {
return '已删除'; return '已删除';
case 'FAILED': case 'FAILED':
return '失败'; return '失败';
case 'SUCCESS':
return '成功';
default: default:
return value; return value;
} }
@ -159,3 +165,35 @@ export function isJSON(str: any): boolean {
return false; return false;
} }
} }
// 秒数转化为时分秒,返回中文字符串
export function formatSeconds(value: string) {
let secondTime = parseInt(value, 10); // 秒
let minuteTime = 0; // 分
let hourTime = 0; // 小时
if (secondTime > 59) {
// 如果秒数大于60将秒数转换成整数
// 获取分钟除以60取整数得到整数分钟
minuteTime = parseInt(`${secondTime / 60}`, 10);
// 获取秒数,秒数取余,得到整数秒数
secondTime = parseInt(`${secondTime % 60}`, 10);
// 如果分钟大于60将分钟转换成小时
if (minuteTime > 59) {
// 获取小时获取分钟除以60得到整数小时
hourTime = parseInt(`${minuteTime / 60}`, 10);
// 获取小时后取余的分获取分钟除以60取余的分
minuteTime = parseInt(`${minuteTime % 60}`, 10);
}
}
let result = '';
if (secondTime > 0) {
result = `${parseInt(`${secondTime}`, 10)}`;
}
if (minuteTime > 0) {
result = `${parseInt(`${minuteTime}`, 10)}${result}`;
}
if (hourTime > 0) {
result = `${parseInt(`${hourTime}`, 10)}小时${result}`;
}
return result;
}
Loading…
Cancel
Save