Commit ecdbac07 authored by chenshouchao's avatar chenshouchao

feat: 查看数据集细节、联调完成

parent 5ceeea43
...@@ -8,6 +8,7 @@ import { APIOPTION, urlToken } from "./raysyncApi"; ...@@ -8,6 +8,7 @@ import { APIOPTION, urlToken } from "./raysyncApi";
// import UserStore from '../../../../console/common/stores/UserStore' // import UserStore from '../../../../console/common/stores/UserStore'
import { ApiUtils } from "./utils"; import { ApiUtils } from "./utils";
import Base64 from "crypto-js/enc-base64"; import Base64 from "crypto-js/enc-base64";
import { getUrlThroughParams } from "@/utils/util";
import Utf8 from "crypto-js/enc-utf8"; import Utf8 from "crypto-js/enc-utf8";
import { getLoaclStorageOfKey } from "./utils"; import { getLoaclStorageOfKey } from "./utils";
...@@ -15,6 +16,44 @@ let headers: any = { ...@@ -15,6 +16,44 @@ let headers: any = {
"Content-Type": "application/json", "Content-Type": "application/json",
}; };
type IGetDatasetItemsListParams = {
type?: string;
projectId: string;
token: string;
filetoken: string;
path: string; // 数据集路径
name: string; // 数据集名称
page: number; //
size: number; //
query?: string; // 搜索的关键词
index?: string; // 选择的属性
sort?: string; // 排序
}
type ISaveDatasetParams = {
type?: string;
projectId: string;
token: string;
filetoken: string;
path: string; // 数据集路径
name: string; // 数据集名称
dpath: string; // 目标路径
dname: string; // 目标数据集名称
id: string; // 每个分子的index,逗号分隔
baseurl?: string; // 需要回调后台插入数据集元数据的url,比如http://47.57.4.97/)
}
type IDownloadDatasetItemsParams = {
type?: string;
projectId: string;
token: string;
filetoken: string;
path: string; // 数据集路径
name: string; // 数据集名称
id: string; // 每个分子的index,逗号分隔
downloadType: string; // 下载格式”,可选 SMILES(.smi)、SD(.sdf)、PDB(.pdb)、MOL(.mol)、MOL2(.mol2)
}
class CloudEController { class CloudEController {
// 新建文件夹 // 新建文件夹
static JobFileNewFolder(url: any, filetoken: string, projectId: string) { static JobFileNewFolder(url: any, filetoken: string, projectId: string) {
...@@ -158,10 +197,6 @@ class CloudEController { ...@@ -158,10 +197,6 @@ class CloudEController {
if (ApiUtils.getAuthorizationHeaders(headers)) { if (ApiUtils.getAuthorizationHeaders(headers)) {
url = url + urlToken(filetoken, projectId) + "&batch=true"; url = url + urlToken(filetoken, projectId) + "&batch=true";
headers["Content-Type"] = "multipart/form-data"; headers["Content-Type"] = "multipart/form-data";
// Base64.stringify(Utf8.parse(urls))
// headers["originalfilepath"] = encodeURIComponent(
// original_filepath.join(" ")
// );
headers["originalfilepath"] = Base64.stringify( headers["originalfilepath"] = Base64.stringify(
Utf8.parse(original_filepath.join(" ")) Utf8.parse(original_filepath.join(" "))
); );
...@@ -193,5 +228,61 @@ class CloudEController { ...@@ -193,5 +228,61 @@ class CloudEController {
document.body.removeChild(div); document.body.removeChild(div);
} }
} }
// 获取分子列表
static GetDatasetItemsList(params: IGetDatasetItemsListParams) {
if (ApiUtils.getAuthorizationHeaders(headers)) {
headers["Cache-Control"] = "no-cache";
let url = getUrlThroughParams(params, ['filetoken','path','token'], '?')
return axios.get(
`${APIOPTION()}:5003/find/dataset${url}`,
{
headers: headers,
}
);
}
}
// 分子另存为
static SaveDataset(params: ISaveDatasetParams) {
if (ApiUtils.getAuthorizationHeaders(headers)) {
headers["Cache-Control"] = "no-cache";
let url = getUrlThroughParams(params, ['filetoken','path','token','dpath'], '?')
return axios.post(`${APIOPTION()}:5003/save${url}`,{}, {
headers: headers,
});
}
}
// 数据集分子下载
static DownloadDatasetItems(params: IDownloadDatasetItemsParams) {
if (ApiUtils.getAuthorizationHeaders(headers)) {
headers["Cache-Control"] = "no-cache";
let url = getUrlThroughParams(params, ['filetoken','path','token'], '?')
return axios.get(
`${APIOPTION()}:5003/download${url}`,
{
headers: headers,
}
);
}
}
// 生成文件并下载
static FunDownload(content: string, filename: string) {
// 创建隐藏的可下载链接
let eleLink = document.createElement('a');
eleLink.download = filename;
eleLink.style.display = 'none';
// 字符内容转变成blob地址
let blob = new Blob([content]);
eleLink.href = URL.createObjectURL(blob);
// 触发点击
document.body.appendChild(eleLink);
eleLink.click();
// 然后移除
document.body.removeChild(eleLink);
}
} }
export default CloudEController; export default CloudEController;
...@@ -45,6 +45,19 @@ const FileSelect = observer((props: FileSelectProps) => { ...@@ -45,6 +45,19 @@ const FileSelect = observer((props: FileSelectProps) => {
const [dataSetList, setDataSetList] = useState<any>([]); const [dataSetList, setDataSetList] = useState<any>([]);
const [keyWord, setKeyWord] = useState(""); const [keyWord, setKeyWord] = useState("");
// 弹窗标题
const dialogTitle = useMemo(() => {
if (type === "dataset") {
return "数据集选择器";
} else if (type === "file") {
return "文件选择器";
} else if (type === "path") {
return "路径选择器";
} else {
return "路径选择器";
}
}, [type]);
// 点击确认时返回的路径 // 点击确认时返回的路径
const resultPath = useMemo(() => { const resultPath = useMemo(() => {
if (keyWord) { if (keyWord) {
...@@ -68,7 +81,6 @@ const FileSelect = observer((props: FileSelectProps) => { ...@@ -68,7 +81,6 @@ const FileSelect = observer((props: FileSelectProps) => {
} }
} }
}, [path, selectFileName, keyWord, selectItem, type]); }, [path, selectFileName, keyWord, selectItem, type]);
console.log("resultPath", resultPath);
const fileSelectOnConfirm = () => { const fileSelectOnConfirm = () => {
if (type === "file") { if (type === "file") {
...@@ -415,7 +427,7 @@ const FileSelect = observer((props: FileSelectProps) => { ...@@ -415,7 +427,7 @@ const FileSelect = observer((props: FileSelectProps) => {
open={props.open} open={props.open}
onClose={props.onClose} onClose={props.onClose}
onConfirm={fileSelectOnConfirm} onConfirm={fileSelectOnConfirm}
title="文件选择器" title={dialogTitle}
> >
<div className={style.FSBox}> <div className={style.FSBox}>
<div className={style.FSTop}> <div className={style.FSTop}>
......
...@@ -53,7 +53,7 @@ const KekuleView = (props: IKekuleViewProps) => { ...@@ -53,7 +53,7 @@ const KekuleView = (props: IKekuleViewProps) => {
.setChemObj(molecule); .setChemObj(molecule);
chemViewer.setEnableToolbar(toolbar); chemViewer.setEnableToolbar(toolbar);
chemViewer.setAutofit(true); chemViewer.setAutofit(true);
chemViewer.setPadding(16); chemViewer.setPadding(26);
chemViewer.setEnableDirectInteraction(false); chemViewer.setEnableDirectInteraction(false);
} catch (err) { } catch (err) {
console.log(err); console.log(err);
......
...@@ -54,6 +54,7 @@ export default function MySelect(props: IProps) { ...@@ -54,6 +54,7 @@ export default function MySelect(props: IProps) {
variant = "outlined", variant = "outlined",
multiple = false, multiple = false,
onChange, onChange,
fullWidth,
...other ...other
} = props; } = props;
...@@ -93,7 +94,7 @@ export default function MySelect(props: IProps) { ...@@ -93,7 +94,7 @@ export default function MySelect(props: IProps) {
MuiInputLabel: { MuiInputLabel: {
styleOverrides: { styleOverrides: {
root: { root: {
top: "-9px", // top: "-9px",
}, },
}, },
}, },
...@@ -115,7 +116,7 @@ export default function MySelect(props: IProps) { ...@@ -115,7 +116,7 @@ export default function MySelect(props: IProps) {
return ( return (
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<FormControl fullWidth variant={variant}> <FormControl fullWidth={fullWidth} variant={variant}>
{isTitle ? ( {isTitle ? (
<InputLabel id="demo-simple-select-label"> <InputLabel id="demo-simple-select-label">
{title || "请选择"} {title || "请选择"}
...@@ -132,9 +133,13 @@ export default function MySelect(props: IProps) { ...@@ -132,9 +133,13 @@ export default function MySelect(props: IProps) {
onChange={handleChange} onChange={handleChange}
> >
{options.length {options.length
? options?.map((item: IOption) => { ? options?.map((item: IOption, index) => {
return ( return (
<MenuItem value={item.value} disabled={item?.disabled}> <MenuItem
value={item.value}
disabled={item?.disabled}
key={index}
>
{item.label} {item.label}
</MenuItem> </MenuItem>
); );
......
...@@ -93,3 +93,23 @@ export const storageUnitFromB = (b: number) => { ...@@ -93,3 +93,23 @@ export const storageUnitFromB = (b: number) => {
return `${(b / (1024 * 1024 * 1024 * 1024)).toFixed(2)}t`; return `${(b / (1024 * 1024 * 1024 * 1024)).toFixed(2)}t`;
} }
}; };
// 从本地缓存拿token
export const getToken = (): string => {
return JSON.parse(localStorage.getItem('token_key') || "{}")?.access_token || ''
}
// 请求地址拼接 没值的不拼接 需要转义的通过encodeURIComponent转义
export const getUrlThroughParams = (params: any, encodeArr: Array<string> = [], initUrl= ''):string => { // params 是要穿的参数 是个对象 encodeArr 需要通过encodeURIComponent转换的字段数组
let url = initUrl
Object.keys(params).forEach((item: string, index) => {
if (params[item]) {
let value = params[item]
if (encodeArr.some(encodeItem => encodeItem = item)) {
value = encodeURIComponent(params[item])
}
url += `${index === 0 ? '' : '&'}${item}=${value}`
}
})
return url
}
import React, { useState } from "react";
import MyDialog from "@/components/mui/MyDialog";
import { useMessage } from "@/components/MySnackbar";
import CloudEController from "@/api/fileserver/CloudEController";
import MySelect from "@/components/mui/MySelect";
type IDownloadProps = {
type: string;
projectId: string;
token: string;
fileToken: string;
path: string;
name: string;
selectIds: Array<any>;
open: boolean;
setOpen: any;
};
const flieTypeMap = {
SMILES: ".smi",
SD: ".sdf",
PDB: ".pdb",
MOL: ".mol",
MOL2: ".mol2",
};
const Download = (props: IDownloadProps) => {
const {
type,
path,
projectId,
token,
fileToken,
selectIds,
name,
open,
setOpen,
} = props;
const Message = useMessage();
const [downloadType, setDownloadType] = useState("SMILES");
const options = [
{
label: "SMILES",
value: "SMILES",
},
{
label: "SD",
value: "SD",
},
{
label: "PDB",
value: "PDB",
},
{
label: "MOL",
value: "MOL",
},
{
label: "MOL2",
value: "MOL2",
},
];
const handleChange = (e: any) => {
setDownloadType(e);
};
const handleSubmit = () => {
CloudEController.DownloadDatasetItems({
type: type,
projectId: projectId,
token: token,
filetoken: fileToken,
name: name,
path: path,
id: selectIds.join(","),
downloadType: downloadType,
})
?.then((res) => {
// @ts-ignore
const filename = `${name}${flieTypeMap[downloadType]}`;
CloudEController.FunDownload(res.data, filename);
setOpen(false);
})
?.catch((error) => {
console.log(error);
Message.error(error?.response?.data?.message || "文件服务发生错误!");
});
};
return (
<>
<MyDialog
open={open}
onClose={() => setOpen(false)}
onConfirm={handleSubmit}
title="下载"
>
<div style={{ padding: "20px 0" }}>
<MySelect
value={downloadType}
options={options}
onChange={(e) => handleChange(e)}
// fullWidth={true}
title="下载格式"
isTitle={true}
sx={{
width: "388px",
}}
></MySelect>
</div>
</MyDialog>
</>
);
};
export default Download;
...@@ -7,6 +7,9 @@ ...@@ -7,6 +7,9 @@
justify-content: flex-start; justify-content: flex-start;
height: 100%; height: 100%;
} }
.datasetBoxShowFoot {
padding-bottom: 64px;
}
.top { .top {
margin-bottom: 20px; margin-bottom: 20px;
} }
...@@ -57,6 +60,8 @@ ...@@ -57,6 +60,8 @@
border-radius: 4px; border-radius: 4px;
min-height: 275px; min-height: 275px;
box-sizing: border-box; box-sizing: border-box;
position: relative;
cursor: pointer;
} }
.datasetLi:nth-child(4n) { .datasetLi:nth-child(4n) {
margin-right: 0; margin-right: 0;
...@@ -91,11 +96,22 @@ ...@@ -91,11 +96,22 @@
font-size: 14px; font-size: 14px;
text-align: center; text-align: center;
font-weight: 600; font-weight: 600;
width: 100%;
overflow: hidden;
} }
.datasetLiDataList { .datasetLiDataList {
flex: 1; flex: 1;
overflow: auto; overflow: auto;
} }
.noDataList {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
color: rgba(138, 144, 153, 1);
font-size: 14px;
line-height: 22px;
}
.datasetLiDataLi { .datasetLiDataLi {
height: 20px; height: 20px;
line-height: 20px; line-height: 20px;
......
import { useState, useEffect, useMemo } from "react";
import MyDialog from "@/components/mui/MyDialog";
import { checkIsNumberLetterChinese } from "@/utils/util";
import { useMessage } from "@/components/MySnackbar";
import CloudEController from "@/api/fileserver/CloudEController";
import FileSelect from "@/components/BusinessComponents/FileSelect";
import fileSelectIcon from "@/assets/project/fileSelect.svg";
import MyInput from "@/components/mui/MyInput";
import { BACKEND_API_URI_PREFIX } from "@/api/api_prefix";
import InputAdornment from "@mui/material/InputAdornment";
type ISaveProps = {
type: string;
projectId: string;
token: string;
fileToken: string;
path: string;
name: string;
selectIds: Array<any>;
open: boolean;
setOpen: any;
};
const Save = (props: ISaveProps) => {
const {
type,
path,
projectId,
token,
fileToken,
selectIds,
name,
open,
setOpen,
} = props;
const Message = useMessage();
const [dname, setDname] = useState("");
const [dpath, setDpath] = useState("/");
const [fileSelectOpen, setFileSelectOpen] = useState(false);
const [datasetNameCheck, setDatasetNameCheck] = useState({
error: false,
help: "",
});
const [dpathCheck, setDpathCheck] = useState({
error: false,
help: "",
});
useEffect(() => {
if (open) {
setDname("");
setDatasetNameCheck({
error: false,
help: "",
});
}
}, [open]);
const showDpath = useMemo(() => {
return `ProjectData${dpath === "/" ? "" : dpath}`;
}, [dpath]);
const handleSaveSubmit = () => {
if (dname && !datasetNameCheck.error && dpath) {
CloudEController.SaveDataset({
type: type,
projectId: projectId,
token: token,
filetoken: fileToken,
name: name,
path: path,
dpath: dpath,
dname: dname,
id: selectIds.join(","),
baseurl: BACKEND_API_URI_PREFIX,
})
?.then((res) => {
Message.success("另存为成功!");
setOpen(false);
})
?.catch((error) => {
console.log(error);
Message.error(error?.response?.data?.message || "文件服务发生错误!");
});
} else {
if (!dpath) {
setDpathCheck({
error: true,
help: "请选择另存为路径",
});
} else {
setDpathCheck({
error: false,
help: "",
});
}
if (!dname) {
setDatasetNameCheck({
error: true,
help: "数据集名称不能为空",
});
}
}
};
const handleDnameChange = (e: any) => {
const dname = e.target.value;
setDname(dname);
if (!dname) {
setDatasetNameCheck({
error: true,
help: "数据集名称不能为空",
});
} else if (!checkIsNumberLetterChinese(dname) || dname.length > 30) {
setDatasetNameCheck({
error: true,
help: "格式不正确,必须在30字符以内,仅限大小写字母、数字、中文",
});
} else {
setDatasetNameCheck({
error: false,
help: "",
});
}
};
const onFileSelectConfirm = (path: string) => {
setFileSelectOpen(false);
setDpath(path);
};
return (
<>
<MyDialog
open={open}
onClose={() => setOpen(false)}
onConfirm={handleSaveSubmit}
title="另存为"
>
<MyInput
sx={{
width: "388px",
display: "block",
margin: "20px 0",
}}
required
error={datasetNameCheck.error}
label="数据集名称"
variant="outlined"
value={dname}
onChange={handleDnameChange}
helperText={datasetNameCheck.help}
InputProps={{
endAdornment: (
<InputAdornment position="end">{dname.length}/30</InputAdornment>
),
}}
size="small"
/>
<MyInput
sx={{
width: "388px",
}}
value={showDpath}
required
label="保存路径"
InputProps={{
endAdornment: (
<img
onClick={() => {
setFileSelectOpen(true);
}}
src={fileSelectIcon}
alt="选择输出路径"
style={{ cursor: "pointer" }}
/>
),
}}
error={dpathCheck.error}
helperText={dpathCheck.help}
></MyInput>
{fileSelectOpen && (
<FileSelect
onClose={() => {
setFileSelectOpen(false);
}}
open={fileSelectOpen}
onConfirm={onFileSelectConfirm}
/>
)}
</MyDialog>
</>
);
};
export default Save;
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