Commit 819d0e07 authored by chenshouchao's avatar chenshouchao

feat: 数据集查看器优化提测

parent 0683510d
...@@ -30,6 +30,27 @@ type IGetDatasetItemsListParams = { ...@@ -30,6 +30,27 @@ type IGetDatasetItemsListParams = {
sort?: string; // 排序 sort?: string; // 排序
} }
export type IQuery = {
index: string;
compare: ">" | "<" | ">=" | "<=" | "=" | "≈";
query: string;
};
type IQuerylist = Array<IQuery>
type IGetDatasetItemsListNewParamstype = {
type?: string;
projectId: string;
token: string;
filetoken: string;
path: string; // 数据集路径
name: string; // 数据集名称
page: number; //
size: number; //
index?: string; // 选择的属性
sort?: string; // 排序
}
type IGetDatasetSizeParams = { type IGetDatasetSizeParams = {
type?: string; // 产品id type?: string; // 产品id
projectId: string; projectId: string;
...@@ -281,6 +302,22 @@ class CloudEController { ...@@ -281,6 +302,22 @@ class CloudEController {
} }
} }
// 获取数据集里的数据列表(新 可支持高级搜索)
static GetDatasetItemsListNew(params: IGetDatasetItemsListNewParamstype, querylist: IQuerylist) {
if (ApiUtils.getAuthorizationHeaders(headers)) {
headers["Cache-Control"] = "no-cache";
let url = getUrlThroughParams(params, ['filetoken','path','token'], '?')
return axios.post(
`${APIOPTION()}:5003/find/dataset/new${url}`,{
querylist
},
{
headers: headers,
}
);
}
}
// 分子另存为 // 分子另存为
static SaveDataset(params: ISaveDatasetParams) { static SaveDataset(params: ISaveDatasetParams) {
if (ApiUtils.getAuthorizationHeaders(headers)) { if (ApiUtils.getAuthorizationHeaders(headers)) {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
*/ */
import { useRef, useEffect, useState } from "react"; import { useRef, useEffect, useState } from "react";
import Popover, { PopoverProps } from "@mui/material/Popover"; import Popover, { PopoverProps } from "@mui/material/Popover";
import Typography from "@mui/material/Typography"; import { ThemeProvider, createTheme } from "@mui/material/styles";
interface IProps extends Omit<PopoverProps, "open"> { interface IProps extends Omit<PopoverProps, "open"> {
/** 触发行为 */ /** 触发行为 */
...@@ -22,7 +22,18 @@ interface IProps extends Omit<PopoverProps, "open"> { ...@@ -22,7 +22,18 @@ interface IProps extends Omit<PopoverProps, "open"> {
/** open 修改 */ /** open 修改 */
changeOpen: (val: boolean) => void; changeOpen: (val: boolean) => void;
} }
const theme = createTheme({
components: {
MuiPaper: {
styleOverrides: {
root: {
boxShadow: "0px 3px 10px 0px rgba(0,24,57,0.14)",
},
},
},
},
});
// .css-3bmhjh-MuiPaper-root-MuiPopover-paper
const MyPopover = (props: IProps) => { const MyPopover = (props: IProps) => {
const [anchorEl, setAnchorEl] = useState<any | null>(null); const [anchorEl, setAnchorEl] = useState<any | null>(null);
const ref = useRef(null); const ref = useRef(null);
...@@ -61,40 +72,42 @@ const MyPopover = (props: IProps) => { ...@@ -61,40 +72,42 @@ const MyPopover = (props: IProps) => {
const id = open ? "simple-popover" : undefined; const id = open ? "simple-popover" : undefined;
return ( return (
<div> <ThemeProvider theme={theme}>
<Typography <div>
ref={ref} <div
aria-owns={id} ref={ref}
onClick={trigger === "click" ? handelClick : undefined} aria-owns={id}
onMouseEnter={trigger === "hover" ? handlePopoverOpen : undefined} onClick={trigger === "click" ? handelClick : undefined}
onMouseLeave={trigger === "hover" ? handlePopoverClose : undefined} onMouseEnter={trigger === "hover" ? handlePopoverOpen : undefined}
> onMouseLeave={trigger === "hover" ? handlePopoverClose : undefined}
{children} >
</Typography> {children}
<Popover </div>
id={id} <Popover
open={open} id={id}
anchorEl={anchorEl} open={open}
onClose={handlePopoverClose} anchorEl={anchorEl}
sx={{ onClose={handlePopoverClose}
pointerEvents: trigger === "hover" ? "none" : undefined, sx={{
}} pointerEvents: trigger === "hover" ? "none" : undefined,
anchorOrigin={ }}
anchorOrigin || { anchorOrigin={
vertical: "bottom", anchorOrigin || {
horizontal: "center", vertical: "bottom",
horizontal: "center",
}
} }
} transformOrigin={
transformOrigin={ transformOrigin || {
transformOrigin || { vertical: "top",
vertical: "top", horizontal: "center",
horizontal: "center", }
} }
} >
> {content}
<Typography sx={{ p: 1 }}>{content}</Typography> </Popover>
</Popover> </div>
</div> </ThemeProvider>
); );
}; };
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
flex-wrap: wrap; flex-wrap: wrap;
position: relative;
} }
.datasetLi { .datasetLi {
flex: 1; flex: 1;
......
...@@ -5,6 +5,7 @@ import MyTooltip from "@/components/mui/MyTooltip"; ...@@ -5,6 +5,7 @@ import MyTooltip from "@/components/mui/MyTooltip";
import Checkbox from "@mui/material/Checkbox"; import Checkbox from "@mui/material/Checkbox";
import style from "./index.module.css"; import style from "./index.module.css";
import classNames from "classnames"; import classNames from "classnames";
import MyCircularProgress from "@/components/mui/MyCircularProgress";
import NoData from "@/components/BusinessComponents/NoData"; import NoData from "@/components/BusinessComponents/NoData";
type IDatasetCardTableProps = { type IDatasetCardTableProps = {
...@@ -13,11 +14,18 @@ type IDatasetCardTableProps = { ...@@ -13,11 +14,18 @@ type IDatasetCardTableProps = {
showData: Array<string>; showData: Array<string>;
selectItems: Array<string>; selectItems: Array<string>;
setSelectItems: any; setSelectItems: any;
loading: boolean;
}; };
const DatasetCardTable = (props: IDatasetCardTableProps) => { const DatasetCardTable = (props: IDatasetCardTableProps) => {
const { list, graphicDimension, showData, selectItems, setSelectItems } = const {
props; list,
graphicDimension,
showData,
selectItems,
setSelectItems,
loading,
} = props;
// 选择/取消分子 // 选择/取消分子
const handleSelectItem = (id: string) => { const handleSelectItem = (id: string) => {
...@@ -34,7 +42,7 @@ const DatasetCardTable = (props: IDatasetCardTableProps) => { ...@@ -34,7 +42,7 @@ const DatasetCardTable = (props: IDatasetCardTableProps) => {
// 空盒子用于布局 // 空盒子用于布局
const nullBox = useMemo(() => { const nullBox = useMemo(() => {
if (list.length > 4) { if (list.length > 4) {
let nullBoxLength = 8 - list.length; let nullBoxLength = Math.abs(8 - list.length);
return new Array(nullBoxLength).fill(""); return new Array(nullBoxLength).fill("");
} else { } else {
return []; return [];
...@@ -46,6 +54,7 @@ const DatasetCardTable = (props: IDatasetCardTableProps) => { ...@@ -46,6 +54,7 @@ const DatasetCardTable = (props: IDatasetCardTableProps) => {
{list.length !== 0 && ( {list.length !== 0 && (
<> <>
<div className={style.list}> <div className={style.list}>
<MyCircularProgress loading={loading} />
{list.map((item, index) => { {list.map((item, index) => {
return ( return (
<div <div
......
...@@ -9,6 +9,7 @@ type IDatasetTableProps = { ...@@ -9,6 +9,7 @@ type IDatasetTableProps = {
setSelectItems: any; setSelectItems: any;
sortState: sortState; sortState: sortState;
setSortState: any; setSortState: any;
loading: boolean;
}; };
const DatasetTable = (props: IDatasetTableProps) => { const DatasetTable = (props: IDatasetTableProps) => {
...@@ -19,6 +20,7 @@ const DatasetTable = (props: IDatasetTableProps) => { ...@@ -19,6 +20,7 @@ const DatasetTable = (props: IDatasetTableProps) => {
setSelectItems, setSelectItems,
sortState, sortState,
setSortState, setSortState,
loading,
} = props; } = props;
const headCells = useMemo(() => { const headCells = useMemo(() => {
let width = let width =
...@@ -45,6 +47,7 @@ const DatasetTable = (props: IDatasetTableProps) => { ...@@ -45,6 +47,7 @@ const DatasetTable = (props: IDatasetTableProps) => {
setSelectItems={setSelectItems} setSelectItems={setSelectItems}
sortState={sortState} sortState={sortState}
setSortState={setSortState} setSortState={setSortState}
loading={loading}
></MyTable> ></MyTable>
); );
}; };
......
...@@ -11,14 +11,14 @@ ...@@ -11,14 +11,14 @@
padding-bottom: 64px; padding-bottom: 64px;
} }
.top { .top {
margin-bottom: 20px; margin-bottom: 16px;
} }
.title { .title {
line-height: 22px; line-height: 22px;
color: rgba(30, 38, 51, 1); color: rgba(30, 38, 51, 1);
font-size: 18px; font-size: 18px;
font-weight: 600; font-weight: 600;
margin-bottom: 20px; margin-bottom: 16px;
} }
.screens { .screens {
display: flex; display: flex;
...@@ -58,20 +58,17 @@ ...@@ -58,20 +58,17 @@
position: relative; position: relative;
} }
.searchBox { .searchBox {
position: absolute;
top: 36px;
right: 0;
width: 662px; width: 662px;
box-shadow: 0px 3px 10px 0px rgba(0, 24, 57, 0.14);
background-color: #fff; background-color: #fff;
border-radius: 4px;
z-index: 10;
padding: 20px 24px 24px; padding: 20px 24px 24px;
box-sizing: border-box; box-sizing: border-box;
} }
.searchBox img { .deleteIcon {
cursor: pointer; cursor: pointer;
} }
.deleteIconDisabled {
cursor: not-allowed;
}
.searchTop { .searchTop {
margin-bottom: 12px; margin-bottom: 12px;
} }
......
...@@ -25,7 +25,9 @@ import _ from "lodash"; ...@@ -25,7 +25,9 @@ import _ from "lodash";
import AddIcon from "@mui/icons-material/Add"; import AddIcon from "@mui/icons-material/Add";
import MySelect from "@/components/mui/MySelect"; import MySelect from "@/components/mui/MySelect";
import { sortState } from "@/components/mui/MyTableNew"; import { sortState } from "@/components/mui/MyTableNew";
import { IQuery } from "@/api/fileserver/CloudEController";
import MyInput from "@/components/mui/MyInput"; import MyInput from "@/components/mui/MyInput";
import MyPopover from "@/components/mui/MyPopover";
type ISeeDatasetProps = { type ISeeDatasetProps = {
handleClose: any; handleClose: any;
...@@ -35,70 +37,69 @@ type ISeeDatasetProps = { ...@@ -35,70 +37,69 @@ type ISeeDatasetProps = {
name: string; name: string;
}; };
type IQuery = {
index: any;
compare: ">" | "<" | ">=" | "<=" | "=" | "≈";
query: any;
};
const SeeDataset = observer((props: ISeeDatasetProps) => { const SeeDataset = observer((props: ISeeDatasetProps) => {
const { path, name, fileToken, projectId } = props; const { path, name, fileToken, projectId } = props;
const { currentProjectStore } = useStores(); const { currentProjectStore } = useStores();
const productId = toJS(currentProjectStore.currentProductInfo.id); // 产品id 如:cadd const productId = toJS(currentProjectStore.currentProductInfo.id); // 产品id 如:cadd
const token = getToken(); const token = getToken();
const [tableType, setTableType] = useState<"table" | "card">("table"); const [loading, setLoading] = useState(false);
const [tableType, setTableType] = useState<"table" | "card">("table"); // 展示普通表格还是卡片式表格
const [graphicDimension, setGraphicDimension] = useState("2D"); // 分子结构图是2D还是3D const [graphicDimension, setGraphicDimension] = useState("2D"); // 分子结构图是2D还是3D
const [showData, setShowData] = useState<Array<string>>([]); //显示的数据类型 const [showData, setShowData] = useState<Array<string>>([]); //显示的数据类型
const [showSearchBox, setShowSearchBox] = useState<boolean>(true); // 高级筛选显示隐藏控制 const [showSearchBox, setShowSearchBox] = useState<boolean>(false); // 高级筛选显示隐藏控制
const [hasSmiles, setHasSmiles] = useState(false); const [hasSmiles, setHasSmiles] = useState(false); // 是否是分子结构型数据集
const [dataTypes, setdataTypes] = useState<Array<IOption>>([]); // 可选的数据类型 const [dataTypes, setdataTypes] = useState<Array<IOption>>([]); // 可选的数据类型
const [sort, setSort] = useState("null"); // 排序方式
const [sortState, setSortState] = useState<sortState>({ const [sortState, setSortState] = useState<sortState>({
// 排序状态
field: null, field: null,
order: null, order: null,
}); });
console.log(sortState); const [querylist, setQuerylist] = useState<Array<IQuery>>([]); // 高级筛选
const [querylist, setQuerylist] = useState<Array<IQuery>>([]);
const [queryInit, setQueryInit] = useState<IQuery>({ const [queryInit, setQueryInit] = useState<IQuery>({
// 高级筛选初始化数据
index: "", index: "",
compare: ">", compare: ">",
query: "", query: "",
}); });
// const [searchDataType, setSearchDataType] = useState<any>(null); // 搜索的数据属性
const [page, setPage] = useState(0); // 当前页码 // 请求接口的页码是从0开始的 const [page, setPage] = useState(0); // 当前页码 // 请求接口的页码是从0开始的
const size = 8; // 每页数量
const [count, setCount] = useState(0); // 总页数 const [count, setCount] = useState(0); // 总页数
const [list, setList] = useState<Array<any>>([]); // 分子列表 const [list, setList] = useState<Array<any>>([]); // 分子列表
const [selectItems, setSelectItems] = useState<Array<any>>([]); const [selectItems, setSelectItems] = useState<Array<any>>([]); // 选中的数据
const [saveOpen, setSaveOpen] = useState(false); // 另存为弹窗显示控制 const [saveOpen, setSaveOpen] = useState(false); // 另存为弹窗显示控制
const [downloadOpen, setDownloadOpen] = useState(false); // 下载弹窗显示控制 const [downloadOpen, setDownloadOpen] = useState(false); // 下载弹窗显示控制
const [firstGetList, setFirstGetList] = useState(true); // 第一次请求列表 const [firstGetList, setFirstGetList] = useState(true); // 第一次请求列表
// const handleSortChange = (e: any) => { // 页码改变
// setSort(e);
// };
const pageChange = (value: number) => { const pageChange = (value: number) => {
setPage(value - 1); getList(value - 1);
}; };
// 获取分子列表 // 获取分子列表
const getList = useCallback( const getList = useCallback(
(paramsPage = 0) => { (paramsPage = 0) => {
setPage(paramsPage); setPage(paramsPage);
CloudEController.GetDatasetItemsList({ setSelectItems([]);
type: productId as string, let requestQuerylist = querylist.filter((query) => {
projectId: projectId as string, return query.index !== "" && query.query !== "";
token: token, });
filetoken: fileToken as string, setLoading(true);
path: path, CloudEController.GetDatasetItemsListNew(
name: name, {
page: paramsPage, type: productId as string,
size, projectId: projectId as string,
index: "", token: token,
sort: sort === "null" ? "" : sort, filetoken: fileToken as string,
}) path: path,
name: name,
page: paramsPage,
size: tableType === "table" ? 15 : 8,
index: sortState.field ? sortState.field : "",
sort: sortState.order ? sortState.order : "",
},
requestQuerylist
)
?.then((res) => { ?.then((res) => {
setLoading(false);
setList(res.data.list); setList(res.data.list);
setCount(res.data.totalPage - 1); setCount(res.data.totalPage - 1);
if (res.data.list && res.data.list.length > 0) { if (res.data.list && res.data.list.length > 0) {
...@@ -106,20 +107,7 @@ const SeeDataset = observer((props: ISeeDatasetProps) => { ...@@ -106,20 +107,7 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
let arr: any = []; let arr: any = [];
let _hasSmiles = false; let _hasSmiles = false;
Object.keys(res.data.list[0]).forEach((item) => { Object.keys(res.data.list[0]).forEach((item) => {
if ( if (!["meta", "id"].includes(item)) {
![
"meta",
"id",
// "canonical_smiles",
// "mol",
// "mol2",
// "pdb",
// "sdf",
// "sdf2d",
// "sdf3d",
// "smiles",
].includes(item)
) {
arr.push({ label: item, value: item }); arr.push({ label: item, value: item });
} }
if (item === "smiles") { if (item === "smiles") {
...@@ -144,67 +132,195 @@ const SeeDataset = observer((props: ISeeDatasetProps) => { ...@@ -144,67 +132,195 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
}); });
} }
setFirstGetList(false); setFirstGetList(false);
setShowSearchBox(false);
} }
} }
}) })
?.catch((error) => { ?.catch((error) => {
setLoading(false);
console.log(error); console.log(error);
setList([]); setList([]);
}); });
}, },
[productId, projectId, token, fileToken, path, name, sort, firstGetList] [
productId,
projectId,
token,
fileToken,
path,
name,
sortState,
firstGetList,
querylist,
tableType,
]
); );
// 当排序状态、展示方式改变的时候获取第一页数据
useEffect(() => { useEffect(() => {
getList(page); getList(0);
}, [page]); }, [sortState, tableType]);
// 高级筛选值变化
const handleIndexChange = (e: any, subscriptIndex: number) => { const handleIndexChange = (e: any, subscriptIndex: number) => {
let arr = _.cloneDeep(querylist); let arr = _.cloneDeep(querylist);
console.log(e);
arr[subscriptIndex].index = e; arr[subscriptIndex].index = e;
setQuerylist(arr); setQuerylist(arr);
}; };
// 高级筛选值变化
const handleCompareChange = (e: any, subscriptIndex: number) => { const handleCompareChange = (e: any, subscriptIndex: number) => {
let arr = _.cloneDeep(querylist); let arr = _.cloneDeep(querylist);
console.log(e);
arr[subscriptIndex].compare = e; arr[subscriptIndex].compare = e;
setQuerylist(arr); setQuerylist(arr);
}; };
// 高级筛选值变化
const handleQueryChange = (e: any, subscriptIndex: number) => { const handleQueryChange = (e: any, subscriptIndex: number) => {
let arr = _.cloneDeep(querylist); let arr = _.cloneDeep(querylist);
console.log(e);
arr[subscriptIndex].query = e.target.value; arr[subscriptIndex].query = e.target.value;
setQuerylist(arr); setQuerylist(arr);
}; };
// 高级筛选值变化
const handleDeleteQuery = (index: number) => { const handleDeleteQuery = (index: number) => {
if (querylist.length === 1) {
return;
}
let arr = _.cloneDeep(querylist); let arr = _.cloneDeep(querylist);
arr.splice(index, 1); arr.splice(index, 1);
setQuerylist(arr); setQuerylist(arr);
}; };
// 高级筛选值初始化
const handleInitQuerylist = () => { const handleInitQuerylist = () => {
setQuerylist([{ ...queryInit }]); setQuerylist([{ ...queryInit }]);
}; };
// 点击其他地方隐藏高级筛选 // 显示数据变化
useEffect(() => { const handleSetShowData = (e: any) => {
document.addEventListener("click", (e) => { if (e.length === 0) {
setShowSearchBox(false); return;
}); }
}, []); setShowData(e);
// 高级筛选box取消冒泡
const handlestopBubble = (e: any) => {
e.nativeEvent.stopImmediatePropagation();
}; };
const handleShowSearchBox = (e: any) => { // 高级筛选渲染
e.nativeEvent.stopImmediatePropagation(); const searchBox = () => {
setShowSearchBox(!showSearchBox); return (
<div className={style.searchBox}>
<div className={style.searchTop}>
<span
className={classNames({
[style.searchTopText]: true,
[style.width250]: true,
})}
>
选择属性
</span>
<span
className={classNames({
[style.searchTopText]: true,
[style.width120]: true,
})}
>
比较符
</span>
<span
className={classNames({
[style.searchTopText]: true,
[style.width180]: true,
})}
>
比较值
</span>
</div>
<div className={style.searchList}>
{querylist.map((item, index) => {
return (
<div className={style.searchLi} key={index}>
<MySelect
options={dataTypes}
placeholder="请选择属性"
value={item.index}
sx={{ marginRight: "16px", width: "250px" }}
onChange={(e) => handleIndexChange(e, index)}
></MySelect>
<MySelect
value={item.compare}
onChange={(e) => handleCompareChange(e, index)}
options={[
{
label: ">",
value: ">",
},
{
label: "<",
value: "<",
},
{
label: ">=",
value: ">=",
},
{
label: "<=",
value: "<=",
},
{
label: "=",
value: "=",
},
{
label: "≈",
value: "≈",
},
]}
sx={{ marginRight: "16px", width: "120px" }}
></MySelect>
<MyInput
value={item.query}
onChange={(e) => handleQueryChange(e, index)}
sx={{ marginRight: "16px", width: "180px" }}
></MyInput>
<img
onClick={() => handleDeleteQuery(index)}
src={jobDel}
alt=""
className={classNames({
[style.deleteIcon]: true,
[style.deleteIconDisabled]: querylist.length === 1,
})}
/>
</div>
);
})}
</div>
<div className={style.searchFooter}>
<div
className={style.searchFooterLeft}
onClick={() => setQuerylist([...querylist, { ...queryInit }])}
>
<AddIcon sx={{ fontSize: "20px", marginRight: "6px" }} />
<span>添加条件</span>
</div>
<div className={style.searchFooterRight}>
<MyButton
variant="outlined"
text="重置"
style={{ marginRight: "12px" }}
onClick={() => handleInitQuerylist()}
color="secondary"
></MyButton>
<MyButton
text="筛选"
onClick={() => {
getList(0);
}}
></MyButton>
</div>
</div>
</div>
);
}; };
return ( return (
...@@ -276,7 +392,7 @@ const SeeDataset = observer((props: ISeeDatasetProps) => { ...@@ -276,7 +392,7 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
<MyMultipleMenu <MyMultipleMenu
value={showData} value={showData}
options={dataTypes} options={dataTypes}
setValue={setShowData} setValue={(e: any) => handleSetShowData(e)}
showSelectAll={true} showSelectAll={true}
iconColor="rgba(138, 144, 153, 1)" iconColor="rgba(138, 144, 153, 1)"
> >
...@@ -286,134 +402,33 @@ const SeeDataset = observer((props: ISeeDatasetProps) => { ...@@ -286,134 +402,33 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
</MyMultipleMenu> </MyMultipleMenu>
</div> </div>
<div className={style.screensRight}> <div className={style.screensRight}>
<MyButton <MyPopover
text="高级筛选" open={showSearchBox}
onClick={(e: any) => { changeOpen={(e) => setShowSearchBox(e)}
handleShowSearchBox(e); content={searchBox()}
transformOrigin={{
vertical: "top",
horizontal: "right",
}} }}
variant="outlined" anchorOrigin={{
color="secondary" vertical: "bottom",
img={ horizontal: "right",
<img }}
src={filter} >
alt="" <MyButton
style={{ marginRight: "10px" }} text="高级筛选"
></img> variant="outlined"
} color="secondary"
></MyButton> img={
{showSearchBox && ( <img
<div src={filter}
className={style.searchBox} alt=""
onClick={(e) => handlestopBubble(e)} style={{ marginRight: "10px" }}
> ></img>
<div className={style.searchTop}> }
<span style={{ margin: "4px 0" }}
className={classNames({ ></MyButton>
[style.searchTopText]: true, </MyPopover>
[style.width250]: true,
})}
>
选择属性
</span>
<span
className={classNames({
[style.searchTopText]: true,
[style.width120]: true,
})}
>
比较符
</span>
<span
className={classNames({
[style.searchTopText]: true,
[style.width180]: true,
})}
>
比较值
</span>
</div>
<div className={style.searchList}>
{querylist.map((item, index) => {
return (
<div className={style.searchLi}>
<MySelect
options={dataTypes}
placeholder="请选择属性"
value={item.index}
sx={{ marginRight: "16px", width: "250px" }}
onChange={(e) => handleIndexChange(e, index)}
></MySelect>
<MySelect
value={item.compare}
onChange={(e) => handleCompareChange(e, index)}
options={[
{
label: ">",
value: ">",
},
{
label: "<",
value: "<",
},
{
label: ">=",
value: ">=",
},
{
label: "<=",
value: "<=",
},
{
label: "=",
value: "=",
},
{
label: "≈",
value: "≈",
},
]}
sx={{ marginRight: "16px", width: "120px" }}
></MySelect>
<MyInput
value={item.query}
onChange={(e) => handleQueryChange(e, index)}
sx={{ marginRight: "16px", width: "180px" }}
></MyInput>
<img
onClick={() => handleDeleteQuery(index)}
src={jobDel}
alt=""
/>
</div>
);
})}
</div>
<div className={style.searchFooter}>
<div
className={style.searchFooterLeft}
onClick={() =>
setQuerylist([...querylist, { ...queryInit }])
}
>
<AddIcon sx={{ fontSize: "20px", marginRight: "6px" }} />
<span>添加条件</span>
</div>
<div className={style.searchFooterRight}>
<MyButton
variant="outlined"
text="重置"
style={{ marginRight: "12px" }}
onClick={() => handleInitQuerylist()}
color="secondary"
></MyButton>
<MyButton
text="筛选"
onClick={() => setSaveOpen(true)}
></MyButton>
</div>
</div>
</div>
)}
</div> </div>
</div> </div>
</div> </div>
...@@ -426,6 +441,7 @@ const SeeDataset = observer((props: ISeeDatasetProps) => { ...@@ -426,6 +441,7 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
setSelectItems={setSelectItems} setSelectItems={setSelectItems}
sortState={sortState} sortState={sortState}
setSortState={setSortState} setSortState={setSortState}
loading={loading}
></DatasetTable> ></DatasetTable>
)} )}
{tableType === "card" && ( {tableType === "card" && (
...@@ -435,6 +451,7 @@ const SeeDataset = observer((props: ISeeDatasetProps) => { ...@@ -435,6 +451,7 @@ const SeeDataset = observer((props: ISeeDatasetProps) => {
showData={showData} showData={showData}
selectItems={selectItems} selectItems={selectItems}
setSelectItems={setSelectItems} setSelectItems={setSelectItems}
loading={loading}
></DatasetCardTable> ></DatasetCardTable>
)} )}
</div> </div>
......
.datasetBox {
padding: 24px 32px 0;
box-sizing: border-box;
position: relative;
display: flex;
flex-direction: column;
justify-content: flex-start;
height: 100%;
}
.datasetBoxShowFoot {
padding-bottom: 64px;
}
.top {
margin-bottom: 20px;
}
.title {
line-height: 22px;
color: rgba(30, 38, 51, 1);
font-size: 18px;
font-weight: 600;
margin-bottom: 20px;
}
.screens {
display: flex;
justify-content: space-between;
align-items: center;
}
.screensLeft {
display: flex;
justify-content: flex-start;
align-items: center;
}
.screensRight {
display: flex;
justify-content: flex-end;
align-items: center;
}
.selectShowData {
margin-left: 24px;
font-size: 14px;
color: rgba(19, 112, 255, 1);
}
.table {
flex: 1;
overflow-y: overlay;
display: flex;
flex-direction: column;
}
.list {
flex: 1;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
}
.datasetLi {
flex: 1;
min-width: 20%;
margin: 0 16px 16px 0;
border: 1px solid rgba(235, 237, 240, 1);
border-radius: 4px;
min-height: 275px;
box-sizing: border-box;
position: relative;
cursor: pointer;
}
.datasetLi:nth-child(4n) {
margin-right: 0;
}
.datasetLi:nth-last-child(1) {
margin-bottom: 0;
}
.datasetLi:nth-last-child(2) {
margin-bottom: 0;
}
.datasetLi:nth-last-child(3) {
margin-bottom: 0;
}
.datasetLi:nth-last-child(4) {
margin-bottom: 0;
}
.datasetLiTop {
height: 55%;
box-sizing: border-box;
}
.datasetLiBottom {
height: 45%;
box-sizing: border-box;
background-color: RGBA(247, 248, 250, 1);
display: flex;
flex-direction: column;
}
.datasetLiTitle {
height: 38px;
line-height: 38px;
color: rgba(19, 112, 255, 1);
font-size: 14px;
text-align: center;
font-weight: 600;
width: 100%;
overflow: hidden;
}
.datasetLiDataList {
flex: 1;
overflow: overlay;
}
.noDataList {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
color: rgba(138, 144, 153, 1);
font-size: 14px;
line-height: 22px;
}
.datasetLiDataLi {
height: 20px;
line-height: 20px;
color: rgba(30, 38, 51, 1);
font-size: 12px;
padding: 0 16px;
display: flex;
justify-content: space-between;
}
.datasetLiDataLi:nth-child(2n) {
background-color: rgba(235, 237, 240, 1);
}
.datasetLiDataLiKey {
max-width: 50%;
white-space: nowrap;
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
.datasetLiDataLiValue {
max-width: 50%;
white-space: nowrap;
display: block;
overflow: hidden;
text-overflow: ellipsis;
}
.pagination {
height: 76px;
min-height: 76px;
display: flex;
justify-content: center;
align-items: center;
}
.foot {
position: absolute;
bottom: 0;
background-color: #fff;
width: 100%;
box-sizing: border-box;
height: 64px;
padding: 0 32px;
display: flex;
justify-content: flex-end;
align-items: center;
box-shadow: 0px -3px 10px 0px rgba(0, 24, 57, 0.04);
}
.nullBox {
visibility: hidden;
}
import FullScreenDrawer from "@/components/CommonComponents/FullScreenDrawer";
import { useState, useMemo, useCallback, useEffect } from "react";
import RadioGroupOfButtonStyle from "@/components/CommonComponents/RadioGroupOfButtonStyle";
import MyMultipleMenu, { IOption } from "@/components/mui/MyMultipleMenu";
import MySelect from "@/components/mui/MySelect";
import MyInput from "@/components/mui/MyInput";
import MyButton from "@/components/mui/MyButton";
import SearchIcon from "@mui/icons-material/Search";
import MyPagination from "@/components/mui/MyPagination";
import NglView from "@/components/BusinessComponents/NglView";
import KekuleView from "@/components/BusinessComponents/KekuleView";
import Checkbox from "@mui/material/Checkbox";
import CloudEController from "@/api/fileserver/CloudEController";
import { getToken } from "@/utils/util";
import { observer } from "mobx-react-lite";
import { useStores } from "@/store";
import { toJS } from "mobx";
import classNames from "classnames";
import Save from "./components/Save";
import Download from "./components/Download";
import NoData from "@/components/BusinessComponents/NoData";
import MyTooltip from "@/components/mui/MyTooltip";
import style from "./index.module.css";
type ISeeDatasetProps = {
handleClose: any;
path: string;
fileToken: string;
projectId: string;
name: string;
};
const SeeDataset = observer((props: ISeeDatasetProps) => {
const { path, name, fileToken, projectId } = props;
const { currentProjectStore } = useStores();
const productId = toJS(currentProjectStore.currentProductInfo.id); // 产品id 如:cadd
const token = getToken();
const [graphicDimension, setGraphicDimension] = useState("2D"); // 分子结构图是2D还是3D
const [showData, setShowData] = useState<Array<string>>([]); //显示的数据类型
const [dataTypes, setdataTypes] = useState<Array<IOption>>([]); // 可选的数据类型
const [sort, setSort] = useState("null"); // 排序方式
const [keyword, setKeyword] = useState(""); // 关键字
const [searchDataType, setSearchDataType] = useState<any>(null); // 搜索的数据属性
const [page, setPage] = useState(0); // 当前页码 // 请求接口的页码是从0开始的
const size = 8; // 每页数量
const [count, setCount] = useState(0); // 总页数
const [list, setList] = useState<Array<any>>([]); // 分子列表
const [selectItems, setSelectItems] = useState<Array<any>>([]);
const [saveOpen, setSaveOpen] = useState(false); // 另存为弹窗显示控制
const [downloadOpen, setDownloadOpen] = useState(false); // 下载弹窗显示控制
const [showAnimation, setShowAnimation] = useState(true); // 弹窗动画变化中
const [firstGetList, setFirstGetList] = useState(true); // 第一次请求列表
// 解决图像渲染造成弹窗卡顿的问题
useEffect(() => {
setTimeout(() => {
setShowAnimation(false);
}, 300);
}, []);
const isCadd = useMemo(() => {
if (productId === "cadd") {
return true;
} else {
return false;
}
}, [productId]);
const handleSearchDataTypeChange = (e: any) => {
setSearchDataType(e);
};
const handleSortChange = (e: any) => {
setSort(e);
};
const handleKeywordChange = (e: any) => {
if (e.target.value.length <= 30) {
setKeyword(e.target.value);
}
};
const pageChange = (value: number) => {
setPage(value - 1);
};
// 空盒子用于布局
const nullBox = useMemo(() => {
if (list.length > 4) {
let nullBoxLength = 8 - list.length;
return new Array(nullBoxLength).fill("");
} else {
return [];
}
}, [list]);
// 获取分子列表
const getList = useCallback(
(paramsPage = 0) => {
setPage(paramsPage);
CloudEController.GetDatasetItemsList({
type: productId as string,
projectId: projectId as string,
token: token,
filetoken: fileToken as string,
path: path,
name: name,
page: paramsPage,
size,
index: searchDataType ? `${searchDataType}` : "",
sort: sort === "null" ? "" : sort,
query: keyword,
})
?.then((res) => {
setList(res.data.list);
setCount(res.data.totalPage - 1);
if (res.data.list && res.data.list.length > 0) {
if (res.data.list[0]) {
let arr: any = [];
Object.keys(res.data.list[0]).forEach((item) => {
if (
![
"meta",
"id",
// "canonical_smiles",
// "mol",
// "mol2",
// "pdb",
// "sdf",
// "sdf2d",
// "sdf3d",
// "smiles",
].includes(item)
) {
arr.push({ label: item, value: item });
}
});
if (firstGetList) {
setdataTypes(arr);
setSearchDataType(arr[0].value);
}
setFirstGetList(false);
}
}
})
?.catch((error) => {
console.log(error);
setList([]);
// Message.error(error?.response?.data?.message || "获取数据集信息失败");
// Message.error("未搜索到相关数据");
});
},
[
productId,
projectId,
token,
fileToken,
path,
name,
searchDataType,
sort,
keyword,
firstGetList,
// Message,
]
);
useEffect(() => {
getList(page);
}, [page]);
// 选择/取消分子
const handleSelectItem = (id: string) => {
let list: string[] = [...selectItems];
if (selectItems.filter((e) => e === id).length > 0) {
list = list.filter((e) => e !== id);
setSelectItems(list);
} else {
list.push(id);
setSelectItems(list);
}
};
return (
<FullScreenDrawer handleClose={props.handleClose} zIndex={1100}>
<div
className={classNames({
[style.datasetBox]: true,
[style.datasetBoxShowFoot]: true,
})}
>
<div className={style.top}>
<div className={style.title}>{name}</div>
<div className={style.screens}>
<div className={style.screensLeft}>
{isCadd && (
<RadioGroupOfButtonStyle
handleRadio={setGraphicDimension}
value={graphicDimension}
radioOptions={[
{
value: "2D",
label: "2D",
},
{
value: "3D",
label: "3D",
},
]}
RadiosBoxStyle={{ width: "132px" }}
/>
)}
<MyMultipleMenu
value={showData}
options={dataTypes}
setValue={setShowData}
showSelectAll={true}
>
<span className={style.selectShowData}>
选择显示数据({showData.length})
</span>
</MyMultipleMenu>
</div>
<div className={style.screensRight}>
<MySelect
options={dataTypes}
title={dataTypes.length === 0 ? "暂无属性" : "选择属性"}
isTitle={true}
value={searchDataType}
onChange={handleSearchDataTypeChange}
fullWidth={false}
disabled={dataTypes.length === 0}
sx={{
width: "160px",
marginRight: "16px",
height: "32px",
}}
></MySelect>
<MySelect
options={[
{
label: "无",
value: "null",
},
{
label: "正序",
value: "ASC",
},
{
label: "倒序",
value: "DESC",
},
]}
title="排序方式"
value={sort}
onChange={handleSortChange}
isTitle={true}
fullWidth={false}
sx={{
width: "160px",
marginRight: "16px",
height: "32px",
}}
></MySelect>
<MyInput
value={keyword}
onChange={handleKeywordChange}
placeholder="请输入关键词搜索"
fullWidth={false}
InputProps={{
endAdornment: <SearchIcon style={{ color: "#8A9099" }} />,
}}
sx={{
width: "340px",
marginRight: "16px",
}}
size="small"
></MyInput>
<MyButton
text="确认"
style={{ width: "68px" }}
onClick={() => {
getList();
}}
></MyButton>
</div>
</div>
</div>
{!showAnimation && (
<div className={style.table}>
{list.length !== 0 && (
<>
<div className={style.list}>
{list.map((item, index) => {
return (
<div
className={style.datasetLi}
key={item.id}
onClick={() => {
handleSelectItem(item.id);
}}
>
{isCadd && (
<div className={style.datasetLiTop}>
{graphicDimension === "2D" && (
<KekuleView id={`${index}2d`} smi={item.smiles} />
)}
{graphicDimension === "3D" && (
<NglView id={`${index}3d`} content={item.pdb} />
)}
</div>
)}
<div className={style.datasetLiBottom}>
<div
className={style.datasetLiTitle}
title={item.smiles}
>
{item.smiles}
</div>
{showData.length !== 0 && (
<div className={style.datasetLiDataList}>
{Object.keys(item)
.filter((key) => showData.indexOf(key) !== -1)
.map((key, index) => {
return (
<div
className={style.datasetLiDataLi}
key={index}
>
<span
className={style.datasetLiDataLiKey}
>
{key}
</span>
<MyTooltip title={item[key]}>
<span
className={style.datasetLiDataLiValue}
>
{item[key]}
</span>
</MyTooltip>
</div>
);
})}
</div>
)}
{showData.length === 0 && (
<div className={style.noDataList}>
请选择显示数据
</div>
)}
</div>
{graphicDimension === "2D" && (
<Checkbox
size="small"
sx={{
padding: "0px",
position: "absolute",
top: "16px",
right: "20px",
zIndex: 1,
}}
checked={selectItems.includes(item.id)}
/>
)}
{graphicDimension === "3D" && (
<Checkbox
size="small"
sx={{
padding: "0px",
position: "absolute",
top: "16px",
right: "20px",
zIndex: 1,
background: "RGBA(30, 38, 51, 1)",
border: "1px solid #565C66",
borderRadius: "2px",
}}
checked={selectItems.includes(item.id)}
/>
)}
</div>
);
})}
{nullBox.map((item, index) => {
return (
<div
className={classNames({
[style.datasetLi]: true,
[style.nullBox]: true,
})}
key={index + "null"}
></div>
);
})}
</div>
<div className={style.pagination}>
<MyPagination
page={page}
pageChange={pageChange}
count={count}
/>
</div>
</>
)}
{list.length === 0 && <NoData text="未搜索到相关数据"></NoData>}
</div>
)}
</div>
<div className={style.foot}>
{isCadd && (
<MyButton
variant="outlined"
text={`下载(${selectItems.length})`}
style={{ marginRight: "12px" }}
disabled={selectItems.length === 0}
onClick={() => setDownloadOpen(true)}
></MyButton>
)}
<MyButton
disabled={selectItems.length === 0}
text={`另存为(${selectItems.length})`}
onClick={() => setSaveOpen(true)}
></MyButton>
</div>
{saveOpen && (
<Save
type={productId as string}
projectId={projectId}
token={token}
fileToken={fileToken}
path={path}
name={name}
selectIds={selectItems}
open={saveOpen}
setOpen={setSaveOpen}
></Save>
)}
{downloadOpen && (
<Download
type={productId as string}
projectId={projectId}
token={token}
fileToken={fileToken}
path={path}
name={name}
selectIds={selectItems}
open={downloadOpen}
setOpen={setDownloadOpen}
></Download>
)}
</FullScreenDrawer>
);
});
export default SeeDataset;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment