feat: 实验对比添加上拉加载更多
This commit is contained in:
parent
4c24faafe9
commit
42ce67062f
|
@ -0,0 +1 @@
|
|||
save-prefix=~
|
|
@ -60,7 +60,7 @@
|
|||
"@antv/hierarchy": "^0.6.12",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"@umijs/route-utils": "^4.0.1",
|
||||
"antd": "^5.4.4",
|
||||
"antd": "~5.21.4",
|
||||
"classnames": "^2.3.2",
|
||||
"crypto-js": "^4.2.0",
|
||||
"echarts": "^5.5.0",
|
||||
|
@ -111,7 +111,7 @@
|
|||
"umi-presets-pro": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
"node": ">=16.14.0"
|
||||
},
|
||||
"create-umi": {
|
||||
"ignoreScript": [
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 15 KiB |
|
@ -20,7 +20,7 @@
|
|||
height: 40px;
|
||||
padding: 0 30px;
|
||||
font-size: @font-size-content;
|
||||
border-radius: 10px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.ant-btn-default {
|
||||
border-color: transparent;
|
||||
|
|
|
@ -168,7 +168,7 @@
|
|||
height: 40px;
|
||||
padding: 0 30px;
|
||||
font-size: @font-size-content;
|
||||
border-radius: 10px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
.ant-btn-default {
|
||||
border-color: transparent;
|
||||
|
|
|
@ -14,10 +14,30 @@
|
|||
|
||||
&__table {
|
||||
height: calc(100% - 60px);
|
||||
padding: 20px 30px 0;
|
||||
padding: 20px 30px;
|
||||
background-color: white;
|
||||
border-radius: 10px;
|
||||
|
||||
&__footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-top: 20px;
|
||||
color: @text-color-secondary;
|
||||
font-size: 12px;
|
||||
background-color: white;
|
||||
|
||||
div {
|
||||
flex: 1;
|
||||
height: 1px;
|
||||
background-color: @border-color-base;
|
||||
}
|
||||
|
||||
p {
|
||||
flex: none;
|
||||
margin: 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.ant-table-container {
|
||||
border: none !important;
|
||||
|
@ -34,6 +54,13 @@
|
|||
border-left: none !important;
|
||||
}
|
||||
}
|
||||
.ant-table-tbody-virtual::after {
|
||||
border-bottom: none !important;
|
||||
}
|
||||
.ant-table-footer {
|
||||
padding: 0;
|
||||
border: none !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
// import { useCacheState } from '@/hooks/pageCacheState';
|
||||
/*
|
||||
* @Author: 赵伟
|
||||
* @Date: 2024-10-10 09:55:12
|
||||
* @Description: 实验对比
|
||||
*/
|
||||
|
||||
import { useDomSize } from '@/hooks';
|
||||
import {
|
||||
getExpEvaluateInfosReq,
|
||||
getExpMetricsReq,
|
||||
|
@ -8,7 +14,6 @@ import { to } from '@/utils/promise';
|
|||
import tableCellRender, { TableCellValueType } from '@/utils/table';
|
||||
import { useSearchParams } from '@umijs/max';
|
||||
import { App, Button, Table, /* TablePaginationConfig,*/ TableProps, Tooltip } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import ExperimentStatusCell from '../components/ExperimentStatusCell';
|
||||
import { ComparisonType, comparisonConfig } from './config';
|
||||
|
@ -26,40 +31,57 @@ type TableData = {
|
|||
params: Record<string, number>;
|
||||
};
|
||||
|
||||
const pageSize = 30;
|
||||
|
||||
// function Footer() {
|
||||
// return (
|
||||
// <div className={styles['experiment-comparison__table__footer']}>
|
||||
// <div></div>
|
||||
// <p>我是有底线的</p>
|
||||
// <div></div>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
function ExperimentComparison() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const comparisonType = searchParams.get('type') as ComparisonType;
|
||||
const experimentId = searchParams.get('id');
|
||||
const [tableData, setTableData] = useState<TableData[]>([]);
|
||||
// const [cacheState, setCacheState] = useCacheState();
|
||||
// const [total, setTotal] = useState(0);
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||
// const [loading, setLoading] = useState(false);
|
||||
const { message } = App.useApp();
|
||||
const config = useMemo(() => comparisonConfig[comparisonType], [comparisonType]);
|
||||
// const [pagination, setPagination] = useState<TablePaginationConfig>(
|
||||
// cacheState?.pagination ?? {
|
||||
// current: 1,
|
||||
// pageSize: 10,
|
||||
// },
|
||||
// );
|
||||
const [tableRef, { width: tableWidth, height: tableHeight }] = useDomSize<HTMLDivElement>(
|
||||
0,
|
||||
0,
|
||||
[],
|
||||
);
|
||||
const [loadCompleted, setLoadCompleted] = useState(false);
|
||||
const [loading, setLoading] = useState(false); // 避免误触发加载更多
|
||||
|
||||
useEffect(() => {
|
||||
getComparisonData();
|
||||
}, [experimentId]);
|
||||
|
||||
// 获取对比数据列表
|
||||
const getComparisonData = async () => {
|
||||
// setLoading(true);
|
||||
const getComparisonData = async (offset: string = '') => {
|
||||
const request =
|
||||
comparisonType === ComparisonType.Train ? getExpTrainInfosReq : getExpEvaluateInfosReq;
|
||||
const [res] = await to(request(experimentId, { offset: '', limit: 50 }));
|
||||
// setLoading(false);
|
||||
const [res] = await to(request(experimentId, { offset: offset, limit: pageSize }));
|
||||
if (res && res.data) {
|
||||
// const { content = [], totalElements = 0 } = res.data;
|
||||
setTableData(res.data);
|
||||
// setTotal(totalElements);
|
||||
setTableData((prev) => [...prev, ...res.data]);
|
||||
if (res.data.length === 0) {
|
||||
setLoadCompleted(true);
|
||||
const ele = document.getElementsByClassName('ant-table-body')[0];
|
||||
if (ele) {
|
||||
const div = document.createElement('div');
|
||||
div.className = styles['experiment-comparison__table__footer'];
|
||||
div.innerHTML = '<div></div><p>我是有底线的</p><div></div>';
|
||||
ele.appendChild(div);
|
||||
}
|
||||
}
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
// 获取对比 url
|
||||
|
@ -80,17 +102,10 @@ function ExperimentComparison() {
|
|||
getExpMetrics();
|
||||
};
|
||||
|
||||
// 分页切换
|
||||
// const handleTableChange: TableProps['onChange'] = (pagination, filters, sorter, { action }) => {
|
||||
// if (action === 'paginate') {
|
||||
// setPagination(pagination);
|
||||
// }
|
||||
// // console.log(pagination, filters, sorter, action);
|
||||
// };
|
||||
|
||||
// 选择行
|
||||
const rowSelection: TableProps['rowSelection'] = {
|
||||
type: 'checkbox',
|
||||
columnWidth: 48,
|
||||
fixed: 'left',
|
||||
selectedRowKeys,
|
||||
onChange: (selectedRowKeys: React.Key[]) => {
|
||||
|
@ -98,7 +113,20 @@ function ExperimentComparison() {
|
|||
},
|
||||
};
|
||||
|
||||
const columns: TableProps<TableData>['columns'] = useMemo(() => {
|
||||
const handleTableScroll = (e: React.UIEvent<HTMLDivElement, UIEvent>) => {
|
||||
const target = e.target as HTMLDivElement;
|
||||
|
||||
const { scrollTop, scrollHeight, clientHeight } = target;
|
||||
|
||||
// 实现自动加载更多
|
||||
if (!loadCompleted && !loading && scrollHeight - scrollTop - clientHeight <= 0) {
|
||||
const last = tableData[tableData.length - 1];
|
||||
setLoading(true);
|
||||
getComparisonData(last?.run_id);
|
||||
}
|
||||
};
|
||||
|
||||
const columns: TableProps['columns'] = useMemo(() => {
|
||||
const first: TableData | undefined = tableData[0];
|
||||
return [
|
||||
{
|
||||
|
@ -192,29 +220,15 @@ function ExperimentComparison() {
|
|||
可视化对比
|
||||
</Button>
|
||||
</div>
|
||||
<div
|
||||
className={classNames(
|
||||
'vertical-scroll-table-no-page',
|
||||
styles['experiment-comparison__table'],
|
||||
)}
|
||||
>
|
||||
<div className={styles['experiment-comparison__table']} ref={tableRef}>
|
||||
<Table
|
||||
dataSource={tableData}
|
||||
columns={columns}
|
||||
rowSelection={rowSelection}
|
||||
scroll={{ y: 'calc(100% - 110px)', x: '100%' }}
|
||||
scroll={{ y: tableHeight - 150, x: tableWidth - 60 }}
|
||||
pagination={false}
|
||||
bordered={true}
|
||||
virtual
|
||||
// onScroll={handleTableScroll}
|
||||
// loading={loading}
|
||||
// pagination={{
|
||||
// ...pagination,
|
||||
// total: total,
|
||||
// showSizeChanger: true,
|
||||
// showQuickJumper: true,
|
||||
// }}
|
||||
// onChange={handleTableChange}
|
||||
onScroll={handleTableScroll}
|
||||
rowKey="run_id"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -126,7 +126,7 @@ function AddExperimentModal({
|
|||
<Button key="cancel" onClick={onCancel}>
|
||||
取消
|
||||
</Button>,
|
||||
<Button key="submit" type="primary" onClick={() => handleRun(false)}>
|
||||
<Button key="submit" type={isAdd ? 'primary' : 'default'} onClick={() => handleRun(false)}>
|
||||
确定
|
||||
</Button>,
|
||||
];
|
||||
|
|
|
@ -47,13 +47,11 @@
|
|||
|
||||
&__robot-img {
|
||||
position: fixed;
|
||||
right: 30px;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
bottom: 90px;
|
||||
z-index: 99;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
background-color: white;
|
||||
border-radius: 10px;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -188,4 +188,227 @@ declare namespace API {
|
|||
filter?: string;
|
||||
sorter?: string;
|
||||
};
|
||||
type CurrentUser = UserInfo & {
|
||||
signature?: string;
|
||||
title?: string;
|
||||
group?: string;
|
||||
tags?: { key?: string; label?: string }[];
|
||||
notifyCount?: number;
|
||||
unreadCount?: number;
|
||||
country?: string;
|
||||
access?: string;
|
||||
geographic?: {
|
||||
province?: { label?: string; key?: string };
|
||||
city?: { label?: string; key?: string };
|
||||
};
|
||||
address?: string;
|
||||
phone?: string;
|
||||
roleNames?: {
|
||||
roleName?: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
type ErrorResponse = {
|
||||
/** 业务约定的错误码 */
|
||||
errorCode: string;
|
||||
/** 业务上的错误信息 */
|
||||
errorMessage?: string;
|
||||
/** 业务上的请求是否成功 */
|
||||
success?: boolean;
|
||||
};
|
||||
|
||||
type FakeCaptcha = {
|
||||
code?: number;
|
||||
status?: string;
|
||||
};
|
||||
|
||||
type getFakeCaptchaParams = {
|
||||
/** 手机号 */
|
||||
phone?: string;
|
||||
};
|
||||
|
||||
type LoginParams = {
|
||||
username?: string;
|
||||
password?: string;
|
||||
uuid?: string;
|
||||
autoLogin?: boolean;
|
||||
type?: string;
|
||||
};
|
||||
|
||||
type LoginResult = {
|
||||
code: number;
|
||||
msg?: string;
|
||||
type?: string;
|
||||
data?: {
|
||||
access_token?: string;
|
||||
expires_in?: number;
|
||||
};
|
||||
};
|
||||
|
||||
type NoticeIconItem = {
|
||||
id?: string;
|
||||
extra?: string;
|
||||
key?: string;
|
||||
read?: boolean;
|
||||
avatar?: string;
|
||||
title?: string;
|
||||
status?: string;
|
||||
datetime?: string;
|
||||
description?: string;
|
||||
type?: NoticeIconItemType;
|
||||
};
|
||||
|
||||
type NoticeIconItemType = 'notification' | 'message' | 'event';
|
||||
|
||||
type NoticeIconList = {
|
||||
data?: NoticeIconItem[];
|
||||
/** 列表的内容总数 */
|
||||
total?: number;
|
||||
success?: boolean;
|
||||
};
|
||||
|
||||
type PageParams = {
|
||||
current?: number;
|
||||
pageSize?: number;
|
||||
};
|
||||
|
||||
type RuleList = {
|
||||
data?: RuleListItem[];
|
||||
/** 列表的内容总数 */
|
||||
total?: number;
|
||||
success?: boolean;
|
||||
};
|
||||
|
||||
type RuleListItem = {
|
||||
key?: number;
|
||||
disabled?: boolean;
|
||||
href?: string;
|
||||
avatar?: string;
|
||||
name?: string;
|
||||
owner?: string;
|
||||
desc?: string;
|
||||
callNo?: number;
|
||||
status?: number;
|
||||
updatedAt?: string;
|
||||
createdAt?: string;
|
||||
progress?: number;
|
||||
};
|
||||
|
||||
type ruleParams = {
|
||||
/** 当前的页码 */
|
||||
current?: number;
|
||||
/** 页面的容量 */
|
||||
pageSize?: number;
|
||||
};
|
||||
|
||||
type ApiResponse = {
|
||||
code?: number;
|
||||
type?: string;
|
||||
message?: string;
|
||||
};
|
||||
|
||||
type Category = {
|
||||
id?: number;
|
||||
name?: string;
|
||||
};
|
||||
|
||||
type deleteOrderParams = {
|
||||
/** ID of the order that needs to be deleted */
|
||||
orderId: number;
|
||||
};
|
||||
|
||||
type deletePetParams = {
|
||||
api_key?: string;
|
||||
/** Pet id to delete */
|
||||
petId: number;
|
||||
};
|
||||
|
||||
type deleteUserParams = {
|
||||
/** The name that needs to be deleted */
|
||||
username: string;
|
||||
};
|
||||
|
||||
type findPetsByStatusParams = {
|
||||
/** Status values that need to be considered for filter */
|
||||
status: ('available' | 'pending' | 'sold')[];
|
||||
};
|
||||
|
||||
type findPetsByTagsParams = {
|
||||
/** Tags to filter by */
|
||||
tags: string[];
|
||||
};
|
||||
|
||||
type getOrderByIdParams = {
|
||||
/** ID of pet that needs to be fetched */
|
||||
orderId: number;
|
||||
};
|
||||
|
||||
type getPetByIdParams = {
|
||||
/** ID of pet to return */
|
||||
petId: number;
|
||||
};
|
||||
|
||||
type getUserByNameParams = {
|
||||
/** The name that needs to be fetched. Use user1 for testing. */
|
||||
username: string;
|
||||
};
|
||||
|
||||
type loginUserParams = {
|
||||
/** The user name for login */
|
||||
username: string;
|
||||
/** The password for login in clear text */
|
||||
password: string;
|
||||
};
|
||||
|
||||
type Order = {
|
||||
id?: number;
|
||||
petId?: number;
|
||||
quantity?: number;
|
||||
shipDate?: string;
|
||||
/** Order Status */
|
||||
status?: 'placed' | 'approved' | 'delivered';
|
||||
complete?: boolean;
|
||||
};
|
||||
|
||||
type Pet = {
|
||||
id?: number;
|
||||
category?: Category;
|
||||
name: string;
|
||||
photoUrls: string[];
|
||||
tags?: Tag[];
|
||||
/** pet status in the store */
|
||||
status?: 'available' | 'pending' | 'sold';
|
||||
};
|
||||
|
||||
type Tag = {
|
||||
id?: number;
|
||||
name?: string;
|
||||
};
|
||||
|
||||
type updatePetWithFormParams = {
|
||||
/** ID of pet that needs to be updated */
|
||||
petId: number;
|
||||
};
|
||||
|
||||
type updateUserParams = {
|
||||
/** name that need to be updated */
|
||||
username: string;
|
||||
};
|
||||
|
||||
type uploadFileParams = {
|
||||
/** ID of pet to update */
|
||||
petId: number;
|
||||
};
|
||||
|
||||
type User = {
|
||||
id?: number;
|
||||
username?: string;
|
||||
firstName?: string;
|
||||
lastName?: string;
|
||||
email?: string;
|
||||
password?: string;
|
||||
phone?: string;
|
||||
/** User Status */
|
||||
userStatus?: number;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue