Commit 5a2792a8 authored by wuyongsheng's avatar wuyongsheng

Merge branch 'feat-jobList' into 'staging'

Feat job list

See merge request !69
parents bbda7197 a76e2c1e
......@@ -11838,7 +11838,7 @@
},
"webpack-dev-server": {
"version": "4.9.0",
"resolved": "https://registry.npmmirror.com/webpack-dev-server/-/webpack-dev-server-4.9.0.tgz",
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.9.0.tgz",
"integrity": "sha512-+Nlb39iQSOSsFv0lWUuUTim3jDQO8nhK3E68f//J2r5rIcp4lULHXz2oZ0UVdEeWXEh5lSzYUlzarZhDAeAVQw==",
"requires": {
"@types/bonjour": "^3.5.9",
......
......@@ -6,7 +6,7 @@
"homepage": "/v3/",
"dependencies": {
"@babel/core": "^7.16.0",
"@emotion/react": "^11.9.0",
"@emotion/react": "^11.9.3",
"@emotion/styled": "^11.8.1",
"@mui/icons-material": "^5.6.2",
"@mui/lab": "^5.0.0-alpha.84",
......@@ -77,14 +77,15 @@
"style-loader": "^3.3.1",
"tailwindcss": "^3.0.2",
"terser-webpack-plugin": "^5.2.5",
"tss-react": "^3.7.0",
"tus-js-client": "2.1.1",
"typescript": "^4.6.4",
"use-immer": "^0.7.0",
"web-vitals": "^2.1.4",
"webpack": "^5.64.4",
"webpack-dev-server": "^4.6.0",
"webpack-manifest-plugin": "^4.0.2",
"workbox-webpack-plugin": "^6.4.1",
"tus-js-client": "2.1.1"
"workbox-webpack-plugin": "^6.4.1"
},
"scripts": {
"start:master": "set \"REACT_APP_ENV=master\" && npm start",
......
......@@ -21,12 +21,25 @@ const RESTAPI = {
API_DATA_FIND: `${BACKEND_API_URI_PREFIX}/cpp/data/find`, //查询某路径下数据集
API_DATA_SEARCH: `${BACKEND_API_URI_PREFIX}/cpp/data/search`, //搜索项目中某路径下的数据集
API_DATA_MOVE: `${BACKEND_API_URI_PREFIX}/cpp/data/move`, //移动到
API_DATA_MOVE_PACKAGE: `${BACKEND_API_URI_PREFIX}/cpp/data/move/package`, //移动文件夹中的数据集
API_DATA_DEL: `${BACKEND_API_URI_PREFIX}/cpp/data/del`, //删除项目中的数据集
API_DATA_DEL_PACKAGE: `${BACKEND_API_URI_PREFIX}/cpp/data/del/package`, //删除文件夹中的数据集
API_USER_PERMISSION_LIST: `${BACKEND_API_URI_PREFIX}/uaa/routes/privilege/list`, //获取用户包含的权限列表
API_WORKBENCH_TEMPLATE_LIST: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/workflowspec`,//查询项目下工作流模板列表
API_WORKBENCH_DELETE_TEMPLATE: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/workflowspec`,//项目管理员-删除工作流模板
API_WORKBENCH_ADD_TEMPLATE_LIST: `${BACKEND_API_URI_PREFIX}/cpp/workbench/product/workflowspec`,//项目管理员-添加工作流模板-模板列表
API_WORKBENCH_ADD_TEMPLATE: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/workflowspec`,//项目管理员-添加工作流模板-提交
}
API_WORKBENCH_TEMPLATE_LIST: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/workflowspec`, //查询项目下工作流模板列表
API_WORKBENCH_DELETE_TEMPLATE: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/workflowspec`, //项目管理员-删除工作流模板
API_WORKBENCH_ADD_TEMPLATE_LIST: `${BACKEND_API_URI_PREFIX}/cpp/workbench/product/workflowspec`, //项目管理员-添加工作流模板-模板列表
API_WORKBENCH_ADD_TEMPLATE: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/workflowspec`, //项目管理员-添加工作流模板-提交
API_WORKBENCH_WORKFLOWJOB_LIST: `${BACKEND_API_URI_PREFIX}/cpp/workbench/project/workflowjob`, //查询工作流任务
API_WORKBENCH_DEL_WORKFLOWJOB: `${BACKEND_API_URI_PREFIX}/cpp/workflow/job/`, //删除工作流任务
API_WORKBENCH_CANCEL_WORKFLOWJOB: `${BACKEND_API_URI_PREFIX}/cpp/workflow/cancel`, //取消工作流
};
export default RESTAPI;
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:17:48
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-13 09:59:45
* @LastEditTime: 2022-06-16 20:22:37
* @FilePath: /bkunyun/src/api/api_prefix.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -32,7 +32,7 @@ switch (process.env.REACT_APP_ENV) {
if (["www.bkunyun.com"].includes(window.location.host)) {
BACKEND_API_URI_PREFIX = "https://www.bkunyun.com";
} else {
BACKEND_API_URI_PREFIX = "http://47.57.4.97";
BACKEND_API_URI_PREFIX = "http://47.75.104.171";
}
break;
}
......
......@@ -106,10 +106,12 @@ class CloudEController {
if (getLoaclStorageOfKey("userinfo")) {
url = urlToken(filetoken, projectId) + "&q=" + url;
}
return axios
.get(APIOPTION() + "/search" + base + url + "&showhidden=" + showHide, {
headers: headers,
})
return axios.get(
APIOPTION() + "/search" + base + url + "&showhidden=" + showHide,
{
headers: headers,
}
);
}
}
......@@ -170,5 +172,26 @@ class CloudEController {
});
}
}
// 文件下载
static JobFileDownload(url: any, filetoken: string, projectId: string) {
if (ApiUtils.getAuthorizationHeaders(headers)) {
url = url + urlToken(filetoken, projectId);
headers["Content-Type"] = "multipart/form-data";
const div = document.createElement("div");
const elink: any = document.createElement("a");
elink.style.display = "none";
elink.href = APIOPTION() + "/download" + url;
document.body.appendChild(div);
div.appendChild(elink);
div.addEventListener("click", (event) => {
event.stopPropagation();
});
elink.click();
URL.revokeObjectURL(elink.href); // 释放URL 对象
div.removeChild(elink);
document.body.removeChild(div);
}
}
}
export default CloudEController;
......@@ -2,29 +2,6 @@
// const APIOPTION = "https://fileserver.cloudam.cn"
// const APIPORT = "39.105.230.38"
import { getLoaclStorageOfKey } from "./utils";
// const raysyncAddr = {
// bandwidth: null
// capacity: 10485760
// enableLargeFileTransfer: true
// fileServerEndPoint: "https://fileserver.cloudam.cn"
// fileSystemType: "standard"
// jobLogServerEndPoint: "https://fileserver.cloudam.cn:6677"
// privateIp: "10.8.2.67"
// protocolType: "NFS"
// publicMountDir: "/public"
// publicMountUrl: "132594ad6e-atf93.cn-beijing.nas.aliyuncs.com"
// ramUserId: "61261f8a2a2aa4d72f752c3c"
// smbMountUrl: null
// srcAddr: "fileserver.cloudam.cn"
// srcIp: "47.94.198.50"
// sshServerEndPoint: "https://fileserver.cloudam.cn:8888"
// storageType: "Capacity"
// token: null
// userMountDir: "/public/data/"
// userMountUrl: "132594ad6e-uop2.cn-beijing.nas.aliyuncs.com"
// vncServerEndPoint: "https://fileserver.cloudam.cn:9090"
// zoneId: "cn-beijing-h"
// }
const API = function () {
const raysyncAddr = getLoaclStorageOfKey("raysyncAddr");
......@@ -50,38 +27,6 @@ const APIPORT = function () {
return raysyncAddr.srcIp || "";
};
// const currentRegion = {
// cloudProvider: "ALIYUN"
// description: "本计算区有丰富的CPU资源,并提供部分GPU资源,可以满足大部分计算作业需求。"
// enabled: true
// id: "CE-Z1"
// initialized: true
// location: "CLOUD"
// name: "通用计算区"
// primary: true
// storageConfig: {srcAddr: "fileserver.cloudam.cn", srcIp: "47.94.198.50", privateIp: "10.8.2.67",…}
// bandwidth: null
// capacity: 10485760
// enableLargeFileTransfer: true
// fileServerEndPoint: "https://fileserver.cloudam.cn"
// fileSystemType: "standard"
// jobLogServerEndPoint: "https://fileserver.cloudam.cn:6677"
// privateIp: "10.8.2.67"
// protocolType: "NFS"
// publicMountDir: "/public"
// publicMountUrl: "132594ad6e-atf93.cn-beijing.nas.aliyuncs.com"
// ramUserId: "61261f8a2a2aa4d72f752c3c"
// smbMountUrl: null
// srcAddr: "fileserver.cloudam.cn"
// srcIp: "47.94.198.50"
// sshServerEndPoint: "https://fileserver.cloudam.cn:8888"
// storageType: "Capacity"
// token: null
// userMountDir: "/public/data/"
// userMountUrl: "132594ad6e-uop2.cn-beijing.nas.aliyuncs.com"
// vncServerEndPoint: "https://fileserver.cloudam.cn:9090"
// zoneId: "cn-beijing-h"
// }
// 当前计算区
let currentRegion = localStorage.getItem("current-region");
let currentRegionJson = currentRegion && JSON.parse(currentRegion);
......@@ -114,31 +59,6 @@ const urlToken = (filetoken: string, projectId: string) => {
return `?username=${projectId}&token=${token}&filetoken=${encodeURIComponent(
filetoken
)}&share=false&project=true`;
// let json = getLoaclStorageOfKey("current-region");
// const userInfo = getLoaclStorageOfKey("userinfo");
// if (json["location"] && json["location"] === "ON_PREMISE") {
// return `?username=${
// userInfo["name"]
// }&token=${token}&filetoken=${encodeURIComponent(filetoken)}&share=false`; // 之前的filetoken是: userInfo["shareFileAccessToken"]
// }
// if (root && root === "home") {
// return `?username=${
// userInfo["homeDirectoryMountPoint"]
// }&token=${token}&filetoken=${encodeURIComponent(filetoken)}&share=false`;
// }
// // 是否共有文件系统
// if (
// localStorage.getItem("isShareFileSystem") &&
// localStorage.getItem("isShareFileSystem") === "true"
// ) {
// return `?username=${
// userInfo["shareDirectoryMountPoint"]
// }&token=${token}&filetoken=${encodeURIComponent(filetoken)}&share=true`;
// } else {
// return `?username=${
// userInfo["homeDirectoryMountPoint"]
// }&token=${token}&filetoken=${encodeURIComponent(filetoken)}&share=false`;
// }
};
const getUuid = () => {
......@@ -195,3 +115,60 @@ export {
encryptTransfer,
getType,
};
// mock 数据
// const raysyncAddr = {
// bandwidth: null
// capacity: 10485760
// enableLargeFileTransfer: true
// fileServerEndPoint: "https://fileserver.cloudam.cn"
// fileSystemType: "standard"
// jobLogServerEndPoint: "https://fileserver.cloudam.cn:6677"
// privateIp: "10.8.2.67"
// protocolType: "NFS"
// publicMountDir: "/public"
// publicMountUrl: "132594ad6e-atf93.cn-beijing.nas.aliyuncs.com"
// ramUserId: "61261f8a2a2aa4d72f752c3c"
// smbMountUrl: null
// srcAddr: "fileserver.cloudam.cn"
// srcIp: "47.94.198.50"
// sshServerEndPoint: "https://fileserver.cloudam.cn:8888"
// storageType: "Capacity"
// token: null
// userMountDir: "/public/data/"
// userMountUrl: "132594ad6e-uop2.cn-beijing.nas.aliyuncs.com"
// vncServerEndPoint: "https://fileserver.cloudam.cn:9090"
// zoneId: "cn-beijing-h"
// }
// const currentRegion = {
// cloudProvider: "ALIYUN"
// description: "本计算区有丰富的CPU资源,并提供部分GPU资源,可以满足大部分计算作业需求。"
// enabled: true
// id: "CE-Z1"
// initialized: true
// location: "CLOUD"
// name: "通用计算区"
// primary: true
// storageConfig: {srcAddr: "fileserver.cloudam.cn", srcIp: "47.94.198.50", privateIp: "10.8.2.67",…}
// bandwidth: null
// capacity: 10485760
// enableLargeFileTransfer: true
// fileServerEndPoint: "https://fileserver.cloudam.cn"
// fileSystemType: "standard"
// jobLogServerEndPoint: "https://fileserver.cloudam.cn:6677"
// privateIp: "10.8.2.67"
// protocolType: "NFS"
// publicMountDir: "/public"
// publicMountUrl: "132594ad6e-atf93.cn-beijing.nas.aliyuncs.com"
// ramUserId: "61261f8a2a2aa4d72f752c3c"
// smbMountUrl: null
// srcAddr: "fileserver.cloudam.cn"
// srcIp: "47.94.198.50"
// sshServerEndPoint: "https://fileserver.cloudam.cn:8888"
// storageType: "Capacity"
// token: null
// userMountDir: "/public/data/"
// userMountUrl: "132594ad6e-uop2.cn-beijing.nas.aliyuncs.com"
// vncServerEndPoint: "https://fileserver.cloudam.cn:9090"
// zoneId: "cn-beijing-h"
// }
export const a = () => {
return "a";
};
......@@ -135,7 +135,6 @@ type getDataFileMoveParams = {
dpath?: string; // 目标路径
};
// Content-Type application/x-www-form-urlencoded
// 移动到
const getDataFileMove = (params: getDataFileMoveParams) => {
return request({
......@@ -148,13 +147,31 @@ const getDataFileMove = (params: getDataFileMoveParams) => {
});
};
type getDataFileMovePackageParams = {
projectId: string;
names: string; // 包名
spath?: string; // 原路径
dpath?: string; // 目标路径
};
// 移动文件夹中的数据集
const getDataFileMovePackage = (params: getDataFileMovePackageParams) => {
return request({
url: Api.API_DATA_MOVE_PACKAGE,
method: "put",
data: params,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
type getDataFileDelParams = {
projectId: string;
names: string;
path?: string;
};
// Content-Type application/x-www-form-urlencoded
// 删除项目中的数据集
const getDataFileDel = (params: getDataFileDelParams) => {
return request({
......@@ -167,6 +184,24 @@ const getDataFileDel = (params: getDataFileDelParams) => {
});
};
type getDataFileDelPackageParams = {
projectId: string;
names: string;
path?: string;
};
// 删除项目中的数据集
const getDataFileDelPackage = (params: getDataFileDelPackageParams) => {
return request({
url: Api.API_DATA_DEL_PACKAGE,
method: "delete",
params,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
});
};
export {
current,
menu,
......@@ -180,5 +215,7 @@ export {
getDataFind,
getDataFileSearch,
getDataFileMove,
getDataFileMovePackage,
getDataFileDel,
getDataFileDelPackage,
};
......@@ -74,11 +74,59 @@ const addWorkbenchTemplate = (params: workflowspecAddTemplateParams) => {
};
type workflowJobListParams = {
projectId: string;
name?: string;
state?: string;
page?: number;
size?: number;
};
// 查询项目下工作流模板列表
const getWorkflowJobList = (params: workflowJobListParams) => {
return request({
url: Api.API_WORKBENCH_WORKFLOWJOB_LIST,
method: "get",
params,
});
};
type workflowJobDelParams = {
id: string
};
// 项目管理员-删除工作流模板
const deleteWorkflowJob = (params: workflowJobDelParams) => {
return request({
url: Api.API_WORKBENCH_DEL_WORKFLOWJOB + params.id,
method: "delete",
});
};
type workflowJobCancelParams = {
jobid: string
};
// 取消工作流
const cancelWorkflowJob = (params: workflowJobCancelParams) => {
return request({
url: Api.API_WORKBENCH_CANCEL_WORKFLOWJOB,
method: "delete",
params,
});
};
export {
current,
menu,
getWorkbenchTemplate,
deleteWorkbenchTemplate,
getAddWorkbenchTemplate,
addWorkbenchTemplate
addWorkbenchTemplate,
getWorkflowJobList,
deleteWorkflowJob,
cancelWorkflowJob
};
<?xml version="1.0" encoding="UTF-8"?>
<svg width="38px" height="48px" viewBox="0 0 38 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>img_bky.0c94999e备份 5</title>
<defs>
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-1">
<stop stop-color="#EEF5FF" offset="0%"></stop>
<stop stop-color="#D8E7FF" offset="100%"></stop>
</linearGradient>
<polygon id="path-2" points="0 0 23.8553102 0 23.8553102 6.97165479 0 6.97165479"></polygon>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="项目数据—传输列表" transform="translate(-853.000000, -292.000000)">
<g id="编组-13" transform="translate(829.000000, 172.000000)">
<g id="编组-54" transform="translate(0.000000, 67.000000)">
<g id="编组-52" transform="translate(0.000000, 36.000000)">
<g id="编组-20" transform="translate(24.000000, 16.000000)">
<g id="img_bky.0c94999e备份-5" transform="translate(0.000000, 1.000000)">
<path d="M4,0 L34,0 C36.209139,0 38,1.790861 38,4 L38,36 L38,36 L28,48 L4,48 C1.790861,48 0,46.209139 0,44 L0,4 C0,1.790861 1.790861,0 4,0 Z" id="矩形" fill="url(#linearGradient-1)" fill-rule="nonzero"></path>
<g id="编组" opacity="0.800000012" transform="translate(3.000000, 16.000000)">
<path d="M19.5440063,7.16876077 C19.5440063,7.16876077 17.7817143,6.14587449 16.5897729,5.46257202 C14.3574699,4.18194596 11.7171006,3.17507407 9.08500973,3.58317846 C13.1105773,4.31203006 15.7261828,7.27081968 16.7502019,8.14045351 L19.5440063,7.16876077 Z" id="Fill-1" fill="#00CCCC" fill-rule="nonzero"></path>
<g transform="translate(7.138353, 5.028345)" id="Fill-3-Clipped">
<mask id="mask-3" fill="white">
<use xlink:href="#path-2"></use>
</mask>
<g id="path-2"></g>
<path d="M23.8475341,1.30693225 C23.7854464,0.676529763 21.2051666,-0.388952164 16.9246113,0.145167087 C10.9941641,0.884848085 7.93902039,3.69347 0,2.7499337 C0.969567451,3.35237664 2.14623668,3.98507627 3.54527983,4.62046684 C9.66384563,7.39870079 15.4135961,7.60025894 19.3981287,5.82699353 C23.3887273,4.05070901 23.931745,2.16468655 23.8475341,1.30693225" id="Fill-3" fill="#0066FF" fill-rule="nonzero" mask="url(#mask-3)"></path>
</g>
<path d="M30.9736907,6.28008688 C30.6298533,8.44006041 25.3893647,8.30971378 20.0153519,4.38211926 C16.2335679,1.61819325 11.5168998,-0.705730866 7.16933256,0.198360149 C12.714265,0.895970559 16.0337454,4.16480925 19.1989342,6.65826274 C22.9154191,9.58528611 26.772993,10.748167 29.483086,9.08424577 C29.9538108,8.7146678 31.1956365,7.49987138 30.9736907,6.28008688" id="Fill-5" fill="#00CCCC" fill-rule="nonzero"></path>
<path d="M3.51830379,6.10049601 C2.21967146,5.72619249 1.51715254,6.10679675 0.0979130386,5.88646764 C2.2898948,7.01777921 4.86839043,7.53496521 7.13837434,7.77826578 C7.7971464,7.84947731 8.55254692,8.01736586 9.56764536,7.96052791 C8.88111225,7.89253239 8.14812039,7.57034126 7.16927547,6.79869712 C5.66461184,5.61225405 3.3792844,3.90370252 0,3.63053905 C1.96033036,4.42088852 2.46738003,5.39264689 3.51830379,6.10049601" id="Fill-7" fill="#0066FF" fill-rule="nonzero"></path>
</g>
<polygon id="矩形" fill="#FFFFFF" fill-rule="nonzero" opacity="0.5" points="28 36 38 36 33 42 28 48"></polygon>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="16px" viewBox="0 0 18 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>1.Base基础/Icon图标/文件传输</title>
<defs>
<filter color-interpolation-filters="auto" id="filter-1">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.540000 0 0 0 0 0.564000 0 0 0 0 0.600000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
<filter color-interpolation-filters="auto" id="filter-2">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.540000 0 0 0 0 0.564000 0 0 0 0 0.600000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="项目数据-长路径" transform="translate(-1324.000000, -136.000000)">
<g id="编组-10" transform="translate(1317.000000, 128.000000)">
<g id="文件传输" transform="translate(7.000000, 7.000000)" filter="url(#filter-1)">
<g>
<rect id="矩形备份-5" x="0" y="0" width="18" height="18"></rect>
<g filter="url(#filter-2)">
<g transform="translate(0.000000, 1.687500)">
<path d="M5.95624614,0.9 L7.0470055,1.84033454 C7.43885553,2.2205386 7.96337743,2.43318258 8.50936421,2.43318258 L8.50936421,2.43318258 L16.8,2.43318258 L17.1,13.425 L1.2,13.725 L0.9,1.2 L5.95624614,0.9 Z" id="路径-4" stroke="#7C878E" stroke-width="1.8"></path>
<polygon id="路径-5" fill="#7C878E" points="9.26587781 3.28436599 1.47245698 3.28436599 1.47245698 1.2526684 6.01231277 1.2526684"></polygon>
<polygon id="路径-6" fill="#7C878E" fill-rule="nonzero" points="8.05145975 5.6167684 8.05145975 10.8168243 5.59717839 10.8168243 5.59717839 9.06182432 6.2508 9.0612484 6.25145975 5.6167684"></polygon>
<polygon id="路径-6备份" fill="#7C878E" fill-rule="nonzero" transform="translate(11.062078, 8.216796) scale(-1, -1) translate(-11.062078, -8.216796) " points="12.2726957 5.6167684 12.2726957 10.81608 9.85203814 10.8168243 9.85145975 9.06182437 10.472057 9.0612484 10.4726957 5.6167684"></polygon>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 8备份 5</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-8备份-5">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-61备份-8" transform="translate(1.000000, 1.000000)" stroke="#C2C6CC" stroke-width="1.68">
<circle id="椭圆形" cx="7" cy="7" r="6.16"></circle>
<line x1="10.7487096" y1="2.20752017" x2="3.31564484" y2="11.6997394" id="路径-48"></line>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 26备份</title>
<defs>
<filter color-interpolation-filters="auto" id="filter-1">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.540000 0 0 0 0 0.564000 0 0 0 0 0.600000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-26备份" transform="translate(2.000000, 2.000000)">
<circle id="椭圆形备份" stroke="#8A9099" stroke-width="1.2" fill-rule="nonzero" cx="6" cy="6" r="6.6"></circle>
<g filter="url(#filter-1)" id="编组-28">
<g transform="translate(3.558554, 2.400000)">
<polyline id="路径-23" stroke="#979797" stroke-width="1.2" points="0.122694244 1.35254766e-12 2.44144585 2.31875161 2.4 7.59435239"></polyline>
<line x1="2.44144585" y1="2.31875161" x2="4.76019746" y2="-1.05607525e-13" id="路径-24" stroke="#979797" stroke-width="1.2"></line>
<line x1="0" y1="3.58021955" x2="4.8" y2="3.58021955" id="路径-60" stroke="#979797" stroke-width="1.2"></line>
<line x1="-5.77512014e-14" y1="6" x2="4.8" y2="6" id="路径-60备份" stroke="#979797" stroke-width="1.2"></line>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="16px" viewBox="0 0 14 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>1.Base基础/Icon图标/工作流模版备份 7</title>
<defs>
<filter color-interpolation-filters="auto" id="filter-1">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.540000 0 0 0 0 0.564000 0 0 0 0 0.600000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组" transform="translate(-1.000000, 0.000000)">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g filter="url(#filter-1)" id="编组-50">
<g transform="translate(1.000000, 1.605109)">
<line x1="0" y1="2.39431484" x2="14" y2="2.39431484" id="路径-16" stroke="#979797" stroke-width="1.5"></line>
<path d="M3.37934347,2.39431484 L3.37934347,1 C3.37934347,0.44771525 3.82705872,1.01453063e-16 4.37934347,0 L9.63329305,0 C10.1855778,-1.01453063e-16 10.6332931,0.44771525 10.6332931,1 L10.6332931,2.39431484 L10.6332931,2.39431484" id="路径-17" stroke="#979797" stroke-width="1.5"></path>
<path d="M2.45321216,3.89402686 L2.45321216,11.9292428 C2.45321216,12.4815275 2.90092741,12.9292428 3.45321216,12.9292428 L10.4872657,12.9292428 C11.0395505,12.9292428 11.4872657,12.4815275 11.4872657,11.9292428 L11.4872657,3.89402686 L11.4872657,3.89402686" id="路径-20" stroke="#979797" stroke-width="1.5"></path>
<line x1="5.49894415" y1="3.89402686" x2="5.49894415" y2="10.3954667" id="路径-21" stroke="#979797" stroke-width="1.5"></line>
<line x1="8.49836822" y1="3.89402686" x2="8.49836822" y2="10.3954667" id="路径-22" stroke="#979797" stroke-width="1.5"></line>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 51</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-51">
<rect id="矩形备份-22" x="0" y="0" width="16" height="16"></rect>
<g id="编组-24" transform="translate(1.000000, 1.000000)">
<circle id="椭圆形" fill="#FF4E4E" fill-rule="nonzero" cx="7" cy="7" r="7"></circle>
<line x1="4.2" y1="4.2" x2="9.8" y2="9.8" id="路径-50" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round"></line>
<line x1="4.2" y1="4.2" x2="9.8" y2="9.8" id="路径-50备份" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round" transform="translate(7.000000, 7.000000) scale(-1, 1) translate(-7.000000, -7.000000) "></line>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 8备份</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-8备份">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-61" transform="translate(1.000000, 1.000000)">
<circle id="椭圆形" fill="#1370FF" fill-rule="nonzero" cx="7" cy="7" r="7"></circle>
<line x1="7" y1="7" x2="7" y2="3.5" id="路径" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round"></line>
<line x1="7" y1="7" x2="9.625" y2="7" id="路径" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round"></line>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 18备份 3</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-18备份-3" transform="translate(0.000000, 0.000000)">
<g id="编组-9" transform="translate(0.500000, 0.500000)">
<circle id="椭圆形" fill="#FF4E4E" cx="7.5" cy="7.5" r="7.5"></circle>
<rect id="矩形" fill="#FFFFFF" x="4.5" y="4.5" width="6" height="6" rx="1"></rect>
</g>
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 50</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-50">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-61备份-4" transform="translate(1.000000, 1.000000)">
<circle id="椭圆形" fill="#0DD09B" fill-rule="nonzero" cx="7" cy="7" r="7"></circle>
<polyline id="路径-47" stroke="#FFFFFF" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" points="4.40461184 7.46931053 7 9.48405007 9.9825782 4.58929929"></polyline>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>编组 26备份</title>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组-26备份" transform="translate(2.000000, 2.000000)" stroke="#8A9099" stroke-width="1.2">
<circle id="椭圆形备份" fill-rule="nonzero" cx="6" cy="6" r="6.6"></circle>
<line x1="6" y1="6" x2="6" y2="3" id="路径备份" stroke-linecap="round"></line>
<line x1="6" y1="6" x2="8.25" y2="6" id="路径备份-2" stroke-linecap="round"></line>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>1.Base基础/Icon图标/任务列表</title>
<defs>
<filter color-interpolation-filters="auto" id="filter-1">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.760000 0 0 0 0 0.776000 0 0 0 0 0.800000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="工作台(管理员)空" transform="translate(-370.000000, -245.000000)">
<g id="编组-5" transform="translate(370.000000, 242.000000)">
<g id="1.Base基础/Icon图标/任务列表" transform="translate(0.000000, 3.000000)">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g filter="url(#filter-1)" id="编组-4">
<g transform="translate(0.500000, 0.000000)">
<path d="M7.38809691,0.889939751 C7.45764437,0.855744844 7.53911808,0.85573765 7.60867158,0.889920274 L7.60867158,0.889920274 L14.1102244,4.08516037 C14.1529938,4.10617975 14.187927,4.13844408 14.2121677,4.17736742 C14.2364085,4.21629077 14.2499569,4.26187312 14.2499569,4.30952854 L14.2499569,4.30952854 L14.2499569,11.9840447 C14.2499569,12.0332683 14.2355127,12.0802004 14.2098426,12.119868 C14.1841726,12.1595356 14.1472766,12.1919385 14.1023731,12.2121037 L14.1023731,12.2121037 L7.60081331,15.1318104 C7.53565621,15.161071 7.46109499,15.1610648 7.39594277,15.1317934 L7.39594277,15.1317934 L0.897545722,12.2122049 C0.852652465,12.1920353 0.815766035,12.1596329 0.790102919,12.1199688 C0.764439802,12.0803047 0.75,12.033379 0.75,11.984163 L0.75,11.984163 L0.75,4.30940599 C0.75,4.26175853 0.763543923,4.21618307 0.78777749,4.17726362 L0.78777749,4.17726362 Z" id="路径-15" stroke="#979797" stroke-width="1.5"></path>
<polyline id="路径-20" stroke="#979797" stroke-width="1.5" points="1.29720478 4.56847209 7.47016174 7.45 13.6431187 4.56847209"></polyline>
<line x1="7.47016174" y1="7.39513959" x2="7.47016174" y2="14.8580198" id="路径-21" stroke="#979797" stroke-width="1.5"></line>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>1.Base基础/Icon图标/任务列表</title>
<defs>
<filter color-interpolation-filters="auto" id="filter-1">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.076000 0 0 0 0 0.440000 0 0 0 0 1.000000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="任务列表" transform="translate(-370.000000, -245.000000)">
<g id="编组-5" transform="translate(370.000000, 242.000000)">
<g id="1.Base基础/Icon图标/任务列表" transform="translate(0.000000, 3.000000)">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g filter="url(#filter-1)" id="编组-4">
<g transform="translate(0.500000, 0.000000)">
<path d="M7.38809691,0.889939751 C7.45764437,0.855744844 7.53911808,0.85573765 7.60867158,0.889920274 L7.60867158,0.889920274 L14.1102244,4.08516037 C14.1529938,4.10617975 14.187927,4.13844408 14.2121677,4.17736742 C14.2364085,4.21629077 14.2499569,4.26187312 14.2499569,4.30952854 L14.2499569,4.30952854 L14.2499569,11.9840447 C14.2499569,12.0332683 14.2355127,12.0802004 14.2098426,12.119868 C14.1841726,12.1595356 14.1472766,12.1919385 14.1023731,12.2121037 L14.1023731,12.2121037 L7.60081331,15.1318104 C7.53565621,15.161071 7.46109499,15.1610648 7.39594277,15.1317934 L7.39594277,15.1317934 L0.897545722,12.2122049 C0.852652465,12.1920353 0.815766035,12.1596329 0.790102919,12.1199688 C0.764439802,12.0803047 0.75,12.033379 0.75,11.984163 L0.75,11.984163 L0.75,4.30940599 C0.75,4.26175853 0.763543923,4.21618307 0.78777749,4.17726362 L0.78777749,4.17726362 Z" id="路径-15" stroke="#979797" stroke-width="1.5"></path>
<polyline id="路径-20" stroke="#979797" stroke-width="1.5" points="1.29720478 4.56847209 7.47016174 7.45 13.6431187 4.56847209"></polyline>
<line x1="7.47016174" y1="7.39513959" x2="7.47016174" y2="14.8580198" id="路径-21" stroke="#979797" stroke-width="1.5"></line>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>1.Base基础/Icon图标/工作流模版</title>
<defs>
<filter color-interpolation-filters="auto" id="filter-1">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.760000 0 0 0 0 0.776000 0 0 0 0 0.800000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="任务列表" transform="translate(-245.000000, -246.000000)">
<g id="编组-4" transform="translate(244.000000, 242.000000)">
<g id="编组-5" transform="translate(0.000000, 3.000000)" filter="url(#filter-1)">
<g>
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-4" transform="translate(1.000000, 1.000000)" stroke="#979797" stroke-width="1.5">
<rect id="矩形" x="0.75" y="0.75" width="4.75" height="4.75" rx="1"></rect>
<rect id="矩形备份-2" x="0.75" y="8.5" width="4.75" height="4.75" rx="1"></rect>
<rect id="矩形备份" x="8.5" y="0.75" width="4.75" height="4.75" rx="1"></rect>
<rect id="矩形备份-3" x="8.5" y="8.5" width="4.75" height="4.75" rx="1"></rect>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>1.Base基础/Icon图标/工作流模版</title>
<defs>
<filter color-interpolation-filters="auto" id="filter-1">
<feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 0.076000 0 0 0 0 0.440000 0 0 0 0 1.000000 0 0 0 1.000000 0"></feColorMatrix>
</filter>
</defs>
<g id="上线UI" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="工作台(管理员)空" transform="translate(-245.000000, -246.000000)">
<g id="编组-4" transform="translate(244.000000, 242.000000)">
<g id="编组-5" transform="translate(0.000000, 3.000000)" filter="url(#filter-1)">
<g>
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<g id="编组-4" transform="translate(1.000000, 1.000000)" stroke="#979797" stroke-width="1.5">
<rect id="矩形" x="0.75" y="0.75" width="4.75" height="4.75" rx="1"></rect>
<rect id="矩形备份-2" x="0.75" y="8.5" width="4.75" height="4.75" rx="1"></rect>
<rect id="矩形备份" x="8.5" y="0.75" width="4.75" height="4.75" rx="1"></rect>
<rect id="矩形备份-3" x="8.5" y="8.5" width="4.75" height="4.75" rx="1"></rect>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
......@@ -19,7 +19,7 @@ const InformationDisplay = (props: InformationDisplayProps) => {
return (
<div className={style.infoListLi} key={item.label}>
<div className={style.infoListLiLabel}>{item.label}</div>
<div className={style.infoListLiValue}>{item.value}</div>
<div className={style.infoListLiValue}>{item.value || "-"}</div>
</div>
);
})}
......
import React from "react";
import React, { useCallback} from "react";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
......@@ -100,6 +99,18 @@ export default function EnhancedTable(props) {
const emptyRows = rowsPerPage - Math.min(rowsPerPage, rows.length - page * rowsPerPage);
const renderTableCellValue = useCallback(((item, row, index)=>{
if(
item.render
) {
return <>{item.render(row[item.id], row, index)}</>
} else if(row[item.id]) {
return row[item.id] || '-'
} else {
return '-'
}
}),[])
return (
<div className={classes.root}>
<Paper sx={{
......@@ -189,8 +200,7 @@ export default function EnhancedTable(props) {
body: props.bodyTableCell || classes.bodyTableCell
}}
> {
item.render ? <>{item.render(row[item.id], row, index)}</> :
row[item.id]
renderTableCellValue(item, row, index)
}
</TableCell>
)
......
......@@ -18,32 +18,52 @@ import LastPageIcon from '@mui/icons-material/LastPage';
import { makeStyles } from "@mui/styles";
const useStyles = makeStyles({
firstPageIconStyle: { width: '28px', height: '28px', padding: 0, backgroundColor: '#FFFFFF', borderRadius: '2px', border: '1px solid #D8D8D8', margin: "0 6px" },
KeyboardArrowLeftStyle:{ width: '28px', height: '28px', padding: 0, backgroundColor: '#FFFFFF', borderRadius: '2px', border: '1px solid #D8D8D8', marginRight: "3px" },
keyboardArrowRightStyle:{ width: '28px', height: '28px', padding: 0, backgroundColor: '#FFFFFF', borderRadius: '2px', border: '1px solid #D8D8D8', marginLeft: "3px" },
lastPageIconStyle:{ width: '28px', height: '28px', padding: 0, backgroundColor: '#FFFFFF', borderRadius: '2px', border: '1px solid #D8D8D8', margin: "0 6px" }
KeyboardArrowLeftStyle: { width: '28px', height: '28px', padding: 0, backgroundColor: '#FFFFFF', borderRadius: '2px', border: '1px solid #D8D8D8', marginRight: "3px" },
keyboardArrowRightStyle: { width: '28px', height: '28px', padding: 0, backgroundColor: '#FFFFFF', borderRadius: '2px', border: '1px solid #D8D8D8', marginLeft: "3px" },
lastPageIconStyle: { width: '28px', height: '28px', padding: 0, backgroundColor: '#FFFFFF', borderRadius: '2px', border: '1px solid #D8D8D8', margin: "0 6px" }
})
const TablePaginationActionsConsole = props => {
const classes = useStyles();
const { count, page, rowsPerPage, onChangePage } = props;
const { count, page, rowsPerPage, onChangePage, onPageChange } = props;
const handleFirstPageButtonClick = (event) => {
onChangePage(event, 0);
if (!onChangePage) {
onPageChange(event, 0)
return
}
onChangePage(event, 0)
}
const handleBackButtonClick = (event) => {
onChangePage(event, page - 1);
if (!onChangePage) {
onPageChange(event, page - 1)
return
}
onChangePage(event, page - 1)
}
const handleNextButtonClick = (event) => {
onChangePage(event, page + 1);
if (!onChangePage) {
onPageChange(event, page + 1);
return
}
onChangePage(event, page + 1)
}
const btnClick = (event, item) => {
onChangePage(event, item);
if (!onChangePage) {
onPageChange(event, item);
return
}
onChangePage(event, item)
}
const handleLastPageButtonClick = (event) => {
onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
if (!onChangePage) {
onPageChange(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1));
return
}
onChangePage(event, Math.max(0, Math.ceil(count / rowsPerPage) - 1))
}
const buttons = (count, page, rowsPerPage) => {
let max = 1;
if( rowsPerPage !== -1 ){
if (rowsPerPage !== -1) {
max = count % rowsPerPage === 0 ? count / rowsPerPage : parseInt(count / rowsPerPage) + 1;
}
let arr = [...Array(max).keys()];
......@@ -69,7 +89,7 @@ const TablePaginationActionsConsole = props => {
<FirstPageIcon />
</IconButton>
<IconButton
className = { classes.KeyboardArrowLeftStyle }
className={classes.KeyboardArrowLeftStyle}
onClick={handleBackButtonClick} disabled={page === 0} aria-label="previous page">
<KeyboardArrowLeft />
</IconButton>
......
......@@ -8,7 +8,10 @@ import NotFound from "@/views/404";
import useMyRequest from "@/hooks/useMyRequest";
import { useEffect } from "react";
import { menu } from "@/api/routes_api";
import { setFileServerEndPointLocalStorage } from "@/views/Project/project";
import {
setFileServerEndPointLocalStorage,
getFiletokenAccordingToId,
} from "@/views/Project/project";
const useMyRouter = () => {
const { permissionStore, menuStore, currentProjectStore } = useStores();
......@@ -53,6 +56,10 @@ const useMyRouter = () => {
currentProjectStore.setProjectList(list);
currentProjectStore.changeProject(list[0]);
setFileServerEndPointLocalStorage(list[0].zoneId);
getFiletokenAccordingToId(list[0].id).then((res) => {
list[0].filetoken = res;
currentProjectStore.changeProject(list[0]);
});
}
}
......
import React, { FC } from "react";
import { Props } from "ahooks/lib/useControllableValue";
import { makeStyles } from "tss-react/mui";
import { Typography, Menu, MenuItem, IconButton, Button } from "@mui/material";
import { makeStyles } from "@mui/styles";
import ArrowDropDownIcon from '@mui/icons-material/ArrowDropDown';
import cx from "classnames"
type ButtonTagProps = {
text: string;
variant?: "text" | 'contained' | 'outlined';
click: any;
select?: any[];
fontSize?: string;
dropValue?: boolean;
drop?: boolean;
color?: "inherit" | "primary" | "secondary" | "success" | "error" | "info" | "warning" | undefined,
text: string;//文本内容
variant?: "text" | 'contained' | 'outlined';//按钮样式
click?: any;//点击事件
select?: any[];//选择按钮的下拉列表
fontSize?: string;//按钮文字大小
dropValue?: boolean;//选择的值
drop?: boolean;//是否开启选择
color?: "inherit" | "primary" | "secondary" | undefined,//按钮颜色风格
btnStyle?: any,//按钮自定义样式类
size?: "large" | "medium" | "small",//按钮尺寸
disabled?: boolean,//是否禁用
style?: any,//按钮自定义样式
img?: JSX.Element;//图标按钮中的图标
selectCallBack?: (item: any, key: number) => void//选择按钮的回调
}
const useStyles = makeStyles({
root: { backgroundColor: "#136EFA", boxShadow: "none !important", color: "#ffffff", "&:hover": { backgroundColor: "#ffffff !important" } },
ArrowDropDownIconRoot: { color: "#8A9099", transition: "all 0.2s !important", transform: "rotate(0)" },
ArrowDropDownIconRootOpen: { color: "#8A9099", transform: "rotate(180deg)" },
})
const ButtonComponent = (props: ButtonTagProps) => {
const classes = useStyles();
const { size, disabled, variant, color, img, btnStyle = {}, select, selectCallBack } = props;
const { classes, cx } = useStyles({});
const [anchorEl, setAnchorEl] = React.useState(null);
const handleClick = (event: { currentTarget: React.SetStateAction<null>; }) => setAnchorEl(event.currentTarget);
const defultClick = (event: { stoppropagation: () => any; }) => event && event.stoppropagation && event.stoppropagation()
const handleCloseOption = (item: any, key: number) => {
setAnchorEl(null);
selectCallBack && selectCallBack(item, key)
}
const handleClose = () => setAnchorEl(null);
return (
<>
<Button
variant={props.variant || 'contained'}
color={props.color || "primary"}
size={size || "medium"}
variant={variant || 'contained'}
color={color || "primary"}
disableRipple={true}
disableFocusRipple={true}
disabled={disabled || false}
classes={{
root: classes.root,
}}
sx={{ color: "#565C66" }}//暂定
root: btnStyle.root || classes.root,
// disabled: btnStyle.disabled || classes.disabled,
containedSecondary: btnStyle.containedSecondary || classes.containedSecondary,
outlined: btnStyle.outlined || classes.outlined,
outlinedSecondary: btnStyle.outlinedSecondary || classes.outlinedSecondary,
text: btnStyle.text || classes.text,
textPrimary: btnStyle.textPrimary || classes.textPrimary,
textSecondary: btnStyle.textSecondary || classes.textSecondary,
sizeSmall: btnStyle.sizeSmall || classes.sizeSmall,
sizeLarge: btnStyle.sizeLarge || classes.sizeLarge,
}}
style={{ ...props.style }}
onClick={props.select ? handleClick : (props.click || defultClick)}
>
{img || ''}
<Typography style={{ fontSize: props.fontSize || "14px" }}>{props.text}</Typography>
{
(props.select && props.select.length > 0 || props.drop) && <ArrowDropDownIcon classes={{
......@@ -58,38 +73,46 @@ const ButtonComponent = (props: ButtonTagProps) => {
}
</Button>
<Menu
id="product-menu"
keepMounted
id="simple-menu"
anchorEl={anchorEl}
keepMounted
open={Boolean(anchorEl)}
onClose={handleClose}
MenuListProps={{
"aria-labelledby": "product-button",
}}
>
{
props.select && props.select.length > 0 && props.select.map((item, key) => {
select && select.length > 0 && select.map((item, key) => {
return (
<MenuItem
key={item.path}
onClick={() => {
// navigate(item.path);
handleClose();
}}
>
{item.name}
key={key}
classes={{ root: classes.menuItemRoot }}
onClick={() => handleCloseOption(item, key)}>
{item.name || ""}
</MenuItem>
);
})}
)
})
}
</Menu>
</>
)
}
const useStyles = makeStyles<{}>()(
(theme, { }) => ({
root: { backgroundColor: "#136EFA", boxShadow: "none !important", color: "#ffffff", "&:hover": { backgroundColor: "#0055D9" } },
containedSecondary: { backgroundColor: "#D62C1F", boxShadow: "none !important", "&:hover": { backgroundColor: "#D82C1F" } },
outlined: { backgroundColor: '#FFFFFF', border: "1px solid #136EFA", boxShadow: "none !important", color: "#136EFA", "&:hover": { backgroundColor: "rgba(19, 110, 250, 0.1)" } },
outlinedSecondary: { border: "1px solid #D62C1F", color: "#D62C1F", "&:hover": { border: "1px solid #D62C1F", backgroundColor: "rgba(214, 44, 31, 0.1)" } },
label: { "& p": { fontSize: "13px" } },
text: { backgroundColor: 'transparent', boxShadow: "none !important" },
textPrimary: { color: "#136EFA", "&:hover": { backgroundColor: "#E8F1FF" } },
textSecondary: { color: "#F44335", "&:hover": { backgroundColor: "rgba(244, 67, 53, 0.1)" } },
sizeSmall: { "& p": { fontSize: "12px" } },
sizeLarge: { "& p": { fontSize: "14px" } },
menuItemRoot: {},
ArrowDropDownIconRoot: { color: "#8A9099", transition: "all 0.2s !important", transform: "rotate(0)" },
ArrowDropDownIconRootOpen: { color: "#8A9099", transform: "rotate(180deg)" },
})
);
}
export default ButtonComponent;
\ No newline at end of file
......@@ -38,24 +38,8 @@ export interface IDialogProps {
/** 是否禁用确认按钮 */
disabledConfirm?: boolean;
children: React.ReactNode;
}
export interface IFooter {
isHideFooter?: boolean;
footerRender?: () => React.ReactNode;
showCancel?: boolean;
/** 是否显示确定按钮 */
showConfirm?: boolean;
/** 关闭弹窗时的回调函数 */
onClose?: () => void;
/** 点击确定按钮时的回调函数 */
onConfirm?: () => void;
/** 取消按钮文案 */
cancelText?: string;
/** 确认按钮文案 */
okText?: string;
/** 是否禁用确认按钮 */
disabledConfirm?: boolean;
/** 点击遮罩是否关闭 默认为false*/
clickMaskClose?: boolean;
}
const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
......@@ -76,7 +60,19 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
cancelText,
okText,
disabledConfirm,
clickMaskClose = false,
} = props;
const handelClose = (
event: {},
reason: "backdropClick" | "escapeKeyDown"
) => {
if (reason === "backdropClick" && !clickMaskClose) {
return;
}
onClose && onClose();
};
const Footer = () => {
if (isHideFooter) return null;
return footerRender ? (
......@@ -104,7 +100,7 @@ const MyDialog: React.FunctionComponent<IDialogProps> = (props) => {
return (
<Dialog
open={open}
onClose={onClose}
onClose={handelClose}
style={style}
className={className}
aria-labelledby="alert-dialog-title"
......
This diff is collapsed.
......@@ -26,7 +26,11 @@ const MyDialog = (props: any) => {
setOpen(true);
};
const handleClose = () => {
const handleClose = (event: any = {}, reason: any = "other") => {
// 点击弹窗外不关闭弹窗
if (reason === "backdropClick") {
return;
}
setOpen(false);
};
......@@ -57,7 +61,11 @@ const MyDialog = (props: any) => {
{title}
</DialogTitle>
)}
<DialogContent>
<DialogContent
sx={{
minWidth: "400px",
}}
>
{props.children}
<IconButton
aria-label="delete"
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-11 09:33:46
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-11 11:33:17
* @LastEditTime: 2022-06-16 14:21:00
* @FilePath: /bkunyun/src/components/mui/MyPopover.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......
......@@ -6,11 +6,11 @@ import TreeItem from "@mui/lab/TreeItem";
interface TreeItemType {
id: string;
name: string;
disabled?: boolean;
subdirs?: readonly TreeItemType[];
}
type MyTreeViewProps = {
// treeData: RenderTree;
treeData: Array<TreeItemType>;
onNodeFocus?: (event: object, value: string) => void; // 点击某一项的回调
onNodeSelect?: (event: object, value: Array<any> | string) => void; // 点击某一项的回调
......@@ -25,6 +25,7 @@ type MyTreeViewProps = {
interface RenderTree {
id: string | number;
name: string;
disabled?: boolean;
subdirs?: readonly RenderTree[];
}
......@@ -48,6 +49,7 @@ const MyTreeView = (props: MyTreeViewProps) => {
idFunc ? idFunc(nodes) : nodes.id || `${nodes.name}${index}`
)}
label={renderLabel === undefined ? nodes.name : renderLabel(nodes.name)}
disabled={nodes?.disabled ? true : false}
>
{Array.isArray(nodes.subdirs)
? nodes.subdirs.map((node, i) => renderTreeObj(node, i))
......@@ -55,20 +57,6 @@ const MyTreeView = (props: MyTreeViewProps) => {
</TreeItem>
);
// const renderTreeArray = (node: TreeItemType, index: number) => {
// return (
// <TreeItem
// key={node.id || `${node.name}${index}`}
// nodeId={String(node.id)}
// label={renderLabel === undefined ? node.name : renderLabel(node.name)}
// >
// {Array.isArray(node.subdirs)
// ? node.subdirs.map((nodeLi: any, i) => renderTreeArray(nodeLi, i))
// : null}
// </TreeItem>
// );
// };
return (
<TreeView
defaultCollapseIcon={<ArrowRightIcon />}
......@@ -79,14 +67,9 @@ const MyTreeView = (props: MyTreeViewProps) => {
defaultExpanded={defaultExpanded}
sx={{ ...treeViewSx }}
>
{treeData.length === 0 ? (
<div>暂无数据</div>
) : (
treeData.map((treeItem, index) => {
// return renderTreeArray(treeItem, index);
return renderTreeObj(treeItem, index);
})
)}
{treeData.map((treeItem, index) => {
return renderTreeObj(treeItem, index);
})}
</TreeView>
);
};
......
......@@ -8,25 +8,45 @@
*/
import { memo } from "react";
import { isEqual } from "lodash";
import { useState, useMemo, useEffect } from "react";
import { Box } from "@mui/system";
import Tab from "@mui/material/Tab";
import { TabContext, TabList, TabPanel } from "@mui/lab";
import { Typography } from '@mui/material';
interface ITabList {
label: string;
value: string;
component: JSX.Element;
icon?: string;
iconed?: string;
hide?: boolean
}
interface IProps {
value: string;
onChange: (val: string) => void;
tabList: ITabList[];
}
const Tabs = (props: IProps) => {
const { value, onChange, tabList } = props;
const { tabList } = props;
const [value, setValue] = useState(tabList.filter(e => !e.hide)[0].value);
const onChange = (val: string) => {
setValue(val);
};
const labelRender = (item: ITabList, key: number) => {
return (
<Box style={{ display: "flex", alignItems: "center" }}>
{
item.icon ? <img style={{ width: "14px", marginRight: "10px" }} src={value === item.value ? item.iconed : item.icon} alt="" />
: ""
}
<Typography sx={{ fontSize: "14px", fontWeight: '400' }} >{item.label}</Typography>
</Box>
)
}
return (
<TabContext value={value}>
<Box sx={{ borderBottom: 1, borderColor: "#F0F2F5" }}>
......@@ -36,9 +56,15 @@ const Tabs = (props: IProps) => {
}}
aria-label="lab API tabs example"
>
{tabList?.map((item) => {
{tabList?.map((item, key) => {
if (item.hide) return ""
return (
<Tab label={item.label} value={item.value} key={item.value} />
<Tab
key={key}
label={labelRender(item, key)}
value={item.value}
id={item.value}
/>
);
})}
</TabList>
......
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-14 17:22:15
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-14 17:22:56
* @FilePath: /bkunyun/src/hooks/useDeepEffect.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { useEffect, useRef } from 'react';
import _ from 'lodash';
export default function useDeepEffect(effectFunc: Function, deps: any[]) {
const isFirstRef = useRef(true);
const preDeps = useRef(deps);
useEffect(() => {
const isSame = preDeps.current.every((obj, index) => {
return _.isEqual(obj, deps[index]);
});
if (isFirstRef.current || !isSame) {
effectFunc();
}
isFirstRef.current = false;
preDeps.current = deps;
}, [deps]);
}
......@@ -20,7 +20,7 @@ const theme = createTheme({
},
palette: {
primary: { main: '#136EFA' },
secondary: { main: '#4EB9FB' }
secondary: { main: '#F44335' }
}
});
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-09 20:41:05
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-14 10:16:23
* @LastEditTime: 2022-06-14 20:55:22
* @FilePath: /bkunyun/src/store/index.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -11,11 +11,11 @@ import { configure } from "mobx";
import permissionStore from "./modules/permission";
import menuStore from "./modules/menu";
import currentProjectStore from "./modules/currentProject";
import fileList from "./modules/fileList";
import fileListStore from "./modules/fileList";
configure({ enforceActions: "always" });
export const stores = { permissionStore, menuStore, currentProjectStore, fileList };
export const stores = { permissionStore, menuStore, currentProjectStore, fileListStore };
/** Store类型 */
export type Stores = typeof stores;
......
......@@ -4,6 +4,7 @@ type projectInfo = {
name?: string;
desc?: string;
projectRole?: string;
filetoken?: string;
};
type productInfo = {
......
......@@ -2,18 +2,18 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-13 17:00:19
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-14 11:06:13
* @LastEditTime: 2022-06-16 09:43:42
* @FilePath: /bkunyun/src/store/modules/upload.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { makeAutoObservable } from "mobx";
import { makeAutoObservable } from "mobx";
interface IUploadInfo {
export interface IUploadInfo {
id: string,
open: boolean,
list: any,
isPermanence: boolean,
file: File,
info: any,
path: string;
}
/** 存储地图派单websocket推送数据状态的store */
......@@ -25,12 +25,23 @@ class FileList {
/** 文件上传列表 */
fileList: IUploadInfo[] = [];
setFileList (val: IUploadInfo[]) {
this.fileList = val
// setFileList (val: IUploadInfo[]) {
// this.fileList = val
// }
/** 新需要上传的文件列表 */
newFileList: IUploadInfo[] = [];
/** 设置最新需要上传的文件列表 */
setNewFileList = (val: IUploadInfo[]) => {
this.fileList = this.fileList.concat(val)
this.newFileList = val
}
/** 设置文件上传信息 */
setUploadInfo(id: string, val: IUploadInfo) {
setUploadInfo = (id: string, val: IUploadInfo) => {
const newFileList = this.fileList?.map((item)=>{
if(item.id === id){
return val
......@@ -39,34 +50,16 @@ class FileList {
this.fileList = newFileList
}
setUploadInfoOpen(id: string, val: boolean) {
const newFileList = this.fileList?.map((item)=>{
if(item.id === id){
return {...item,open: val};
}
return item;
})
this.fileList = newFileList
}
setUploadInfoList(id: string, val: any) {
setUploadInfoList = (id: string, val: any) => {
const newFileList = this.fileList?.map((item)=>{
if(item.id === id){
return {...item, list: val}
return {...item, info: {...item.info, ...val}}
} return item
})
this.fileList = newFileList
}
setUploadInfoIsPermanence(id: string, val: boolean) {
const newFileList = this.fileList?.map((item)=>{
if(item.id === id){
return {...item, isPermanence: val}
} return item
})
this.fileList = newFileList
}
}
const fileListStore = new FileList()
export default new FileList();
export default fileListStore
This diff is collapsed.
This diff is collapsed.
const localStorageKey = {
TOKEN: "token",
TOKEN: "token_key",
USER_INFO: "userInfo",
USER_LOGIN: "userlogin",
};
......
......@@ -2,12 +2,12 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-07 18:37:53
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-14 10:32:54
* @LastEditTime: 2022-06-15 17:49:27
* @FilePath: /bkunyun/src/utils/util.ts
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { v4 as uuidv4 } from 'uuid';
import { v4 as uuidv4 } from "uuid";
export const isProjectOwner = (name: string) => {
let localName = "";
......@@ -23,26 +23,49 @@ export const isProjectOwner = (name: string) => {
* 生成32位的随机id
* @returns 返回32位的uuid
*/
export const uuid = () => {
export const uuid = () => {
const reg = /-/g;
const pwd = uuidv4().replace(reg, '');
const pwd = uuidv4().replace(reg, "");
return pwd;
};
// 获取用户token 信息
/** 格式化时间 xx小时xx分钟xx秒
* params: item: 毫秒的时间戳
*/
export const formatTime = (time: number) => {
const newTime = Math.floor(time / 1000);
const hours = Math.floor(newTime / 3600);
const minutes = Math.floor((newTime % 3600) / 60);
const seconds = newTime % 60;
const hoursString = hours ? `${hours}小时` : "";
const minutesString = minutes ? `${minutes}分钟` : "";
const secondsString = seconds ? `${seconds}秒` : "";
return `${hoursString}${minutesString}${secondsString}`;
};
// 获取用户信息
export const getUserInfo = () => {
let val: any;
try {
val = JSON.parse(localStorage.getItem("userInfo") || "{}")
}
catch {
console.error("获取用户信息token 出错");
val = JSON.parse(localStorage.getItem("userInfo") || "{}");
} catch {
console.error("获取用户信息 出错");
}
return val
}
return val;
};
// 获取token信息
export const getTokenInfo = () => {
let val: any;
try {
val = JSON.parse(localStorage.getItem("token_key") || "{}");
} catch {
console.error("获取token信息 出错");
}
return val;
};
const IsNumberLetterChineseReg = new RegExp("^[A-Za-z0-9\u4e00-\u9fa5]+$");
......@@ -53,3 +76,20 @@ export const checkIsNumberLetterChinese = (string: string) => {
export const getMbfromB = (b: number) => {
return Math.floor(b / 1048576);
};
// 内存单位转换
export const storageUnitFromB = (b: number) => {
if (b <= 0) {
return "0B";
} else if (b < 1024) {
return `${b}B`;
} else if (b < 1024 * 1024) {
return `${(b / 1024).toFixed(2)}KB`;
} else if (b < 1024 * 1024 * 1024) {
return `${(b / (1024 * 1024)).toFixed(2)}MB`;
} else if (b < 1024 * 1024 * 1024 * 1024) {
return `${(b / (1024 * 1024 * 1024)).toFixed(2)}G`;
} else {
return `${(b / (1024 * 1024 * 1024 * 1024)).toFixed(2)}t`;
}
};
.itemBox {
height: 50px;
padding: 16px 0;
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid #f0f2f5;
}
.fileNameBox {
white-space: nowrap;
display: inline-block;
vertical-align: middle;
color: #1e2633;
max-width: 260px;
overflow: hidden;
text-overflow: ellipsis;
font-size: 14px;
}
.speedBox {
display: flex;
justify-content: space-between;
align-items: center;
}
.rightBox {
cursor: pointer;
font-size: 12px;
color: #1370ff;
}
.leftBox {
display: flex;
}
.span {
color: #8a9099;
font-size: 12px;
}
import { useEffect } from "react";
import { toJS } from "mobx";
import { useNavigate, useLocation } from "react-router-dom";
import { observer } from "mobx-react-lite";
import { useMemo } from "react";
import { LinearProgress } from "@mui/material";
import { formatTime, storageUnitFromB } from "@/utils/util";
import useGlobalStore from "@/hooks/useGlobalStore";
import { observer } from "mobx-react-lite";
import { toJS } from "mobx";
import UseTusUpload from "@/utils/Upload/tusUpload";
// toJS(currentProjectStore.currentProjectInfo.id);
import { IUploadInfo } from "@/store/modules/fileList";
import { useMessage } from "@/components/MySnackbar";
import bkunyunFile from "@/assets/img/bkunyunFile.svg";
import styles from "./index.module.css";
/*
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-11 15:46:42
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-14 11:07:55
* @LastEditTime: 2022-06-16 02:07:56
* @FilePath: /bkunyun/src/views/ConsoleLayout/components/FileItem/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
const FileItem = observer(() => {
const fileList = toJS(useGlobalStore("fileList"));
const { uploadFile } = UseTusUpload(fileList?.fileList);
useEffect(() => {
fileList?.fileList?.forEach((item) => {
uploadFile(
item.id,
item.list,
"/",
"/",
(upload: any, filepath: string) => console.log(upload, filepath, 1111)
);
});
console.log(fileList?.fileList, 1111);
}, [fileList.fileList, uploadFile]);
return <div>dd</div>;
interface IProps {
fileItemInfo: IUploadInfo;
}
const FileItem = observer((props: IProps) => {
const { fileItemInfo } = props;
const itemInfo = toJS(fileItemInfo)?.info;
const { statusMsg = "" } = itemInfo || {};
const uploadInfoStore = toJS(useGlobalStore("fileListStore"));
const currentProjectStore = toJS(useGlobalStore("currentProjectStore"));
const Message = useMessage();
const navigate = useNavigate();
const location: any = useLocation();
/** 时间 */
const TimeText = useMemo(() => {
const val = itemInfo?.endTime - itemInfo?.startTime;
return formatTime(val) || "";
}, [itemInfo?.endTime, itemInfo?.startTime]);
const text = useMemo(() => {
let result = "";
if (statusMsg === "上传失败") {
result = "重新上传";
}
if (statusMsg === "正在上传") {
if (itemInfo?.isSuspend) {
result = "重新上传";
} else {
result = "暂停";
}
}
if (statusMsg === "上传成功") {
result = "查看文件";
}
return result;
}, [itemInfo?.isSuspend, statusMsg]);
/** 操作合集 */
const onOperation = () => {
if (text === "暂停") {
itemInfo?.upload?.abort(true).then(() => {
Message.info("暂停成功!");
uploadInfoStore.setUploadInfoList(fileItemInfo?.id, {
isSuspend: true,
});
});
}
if (text === "重新上传") {
itemInfo?.upload?.start();
uploadInfoStore.setUploadInfoList(fileItemInfo?.id, {
isSuspend: false,
});
}
if (text === "查看文件") {
if (
location?.state?.pathName !== fileItemInfo?.path ||
location?.pathname !== "/product/cadd/projectData"
) {
navigate(`/product/cadd/projectData`, {
state: { pathName: fileItemInfo?.path },
});
}
}
};
const speed = useMemo(() => {
let val = 0;
const time = Math.floor((itemInfo?.endTime - itemInfo.startTime) / 1000);
if (time > 0) {
val = Math.floor(itemInfo?.bytesUploaded / time);
}
return val;
}, [itemInfo?.bytesUploaded, itemInfo?.endTime, itemInfo.startTime]);
return (
<div className={styles.itemBox}>
<div className={styles.leftBox}>
<img src={bkunyunFile} alt="" style={{ marginRight: 16 }} />
<div>
<div>
<b className={styles.fileNameBox} title={itemInfo?.name || ""}>
{itemInfo?.name || ""}
</b>
{statusMsg === "上传失败" ? (
<span
className={styles.span}
style={{ marginLeft: 16, color: "#FF4E4E" }}
>{`(${statusMsg})`}</span>
) : (
<span className={styles.span} style={{ marginLeft: 16 }}>
{TimeText}
</span>
)}
</div>
{statusMsg !== "上传成功" ? (
<LinearProgress
sx={{
width: 300,
borderRadius: 2,
margin: "6px 0",
color: "red",
}}
variant="determinate"
value={itemInfo?.percentage}
/>
) : null}
<div style={{ fontSize: 12 }}>
{statusMsg === "上传成功" ? (
<>
<span style={{ color: "#8A9099" }}>已上传至</span>
<span style={{ color: "#565C66", marginLeft: 12 }}>
{`CADD - ${
currentProjectStore?.currentProjectInfo?.name || ""
}`}
</span>
</>
) : (
<div className={styles.speedBox}>
<span className={styles.span}>{`${storageUnitFromB(
itemInfo?.bytesUploaded || 0
)}/${storageUnitFromB(itemInfo?.bytesTotal || 0)}`}</span>{" "}
:
<span className={styles.span}>{`${storageUnitFromB(
speed
)}/s`}</span>
</div>
)}
</div>
</div>
</div>
<div className={styles.rightBox} onClick={onOperation}>
{text}
</div>
</div>
);
});
export default FileItem;
......@@ -2,18 +2,23 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-06-10 18:05:21
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-11 18:08:27
* @LastEditTime: 2022-06-16 21:15:59
* @FilePath: /bkunyun/src/views/ConsoleLayout/components/TransferList/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { Box, InputLabel, MenuItem, Select } from "@mui/material";
import { Box } from "@mui/material";
import { memo } from "react";
import MySelect from "@/components/mui/MySelect";
import MyTitle from "@/components/mui/MyTitle";
import FileItem from "../FileItem";
import useGlobalStore from "@/hooks/useGlobalStore";
import { observer } from "mobx-react-lite";
import { toJS } from "mobx";
const TranSferList = observer(() => {
const uploadInfoStore = toJS(useGlobalStore("fileListStore"));
const TranSferList = () => {
return (
<Box style={{ width: 520, padding: 20 }}>
<MyTitle title="传输列表" />
......@@ -41,11 +46,13 @@ const TranSferList = () => {
size="small"
/>
</Box>
<Box>
<FileItem />
<Box style={{ height: 400, overflowY: "auto" }}>
{uploadInfoStore?.fileList.map((item) => {
return <FileItem fileItemInfo={item} key={item.id} />;
})}
</Box>
</Box>
);
};
});
export default memo(TranSferList);
......@@ -3,10 +3,10 @@ import { Outlet, useLocation, useNavigate } from "react-router-dom";
import cx from "classnames";
import { observer } from "mobx-react-lite";
import ArrowDropDownIcon from "@mui/icons-material/ArrowDropDown";
import Add from "@mui/icons-material/Add";
import Avatar from "@mui/material/Avatar";
import { Box, Menu, MenuItem } from "@mui/material";
import uploadIcon from "@/assets/img/uploadIcon.svg";
import globalText from "@/utils/globalText_CN";
import useIndex from "./useIndex";
import { useStores } from "@/store/index";
......@@ -45,6 +45,7 @@ const ConsoleLayout = observer(() => {
<Button
text={globalText.console}
variant={"text"}
style={{ color: "#565C66" }}
click={() => navigate("/home")}
/>
......@@ -52,6 +53,7 @@ const ConsoleLayout = observer(() => {
<Button
text={globalText.product}
variant={"text"}
style={{ color: "#565C66" }}
click={handleProductClick}
dropValue={productOpen}
drop={true}
......@@ -105,7 +107,11 @@ const ConsoleLayout = observer(() => {
}}
>
<Box className={style.topRightItem}>
<Add />
<img
src={uploadIcon}
alt=""
style={{ verticalAlign: "middle" }}
/>
</Box>
</MyPopover>
<Box className={style.topRightItem}>
......
......@@ -13,7 +13,8 @@
.content {
flex: 1;
height: calc(100vh - 57px);
overflow: scroll;
overflow: hidden;
/* ??????????? */
}
.list {
/* background-color: red; */
......
......@@ -5,16 +5,31 @@ import MyDialog from "@/components/mui/MyDialog";
import { checkIsNumberLetterChinese } from "@/utils/util";
import { useMessage } from "@/components/MySnackbar";
import CloudEController from "@/api/fileserver/CloudEController";
import InputAdornment from '@mui/material/InputAdornment';
const AddFolder = (props: any) => {
const { list, path, projectId, fileToken, refresh } = props;
const Message = useMessage();
let addFolderDialogRef: any = React.createRef();
const [fileName, setFileName] = useState("");
const [fileNameCheck, setFileNameCheck] = useState({
error: false,
help: "",
});
const showDialog = () => {
addFolderDialogRef.current.handleClickOpen();
initData()
};
const initData = () => {
setFileName('')
setFileNameCheck({
error: false,
help: "",
})
}
useImperativeHandle(props.onRef, () => {
return {
showDialog: showDialog,
......@@ -41,11 +56,6 @@ const AddFolder = (props: any) => {
};
const addFolderSubmitloading = false;
const [fileName, setFileName] = useState("");
const [fileNameCheck, setFileNameCheck] = useState({
error: false,
help: "",
});
const handleFileNameChange = (e: any) => {
const fileName = e.target.value;
setFileName(fileName);
......@@ -99,6 +109,9 @@ const AddFolder = (props: any) => {
value={fileName}
onChange={handleFileNameChange}
helperText={fileNameCheck.help}
InputProps={{
endAdornment: <InputAdornment position="end">{fileName.length}/30</InputAdornment>,
}}
size="small"
/>
</MyDialog>
......
import React, { useState, useImperativeHandle, useMemo } from "react";
import MyDialog from "@/components/mui/MyDialog";
import { useMessage } from "@/components/MySnackbar";
import CloudEController from "@/api/fileserver/CloudEController";
import { getDataFileDel, getDataFileDelPackage } from "@/api/project_api";
import useMyRequest from "@/hooks/useMyRequest";
const DeleteDialog = (props: any) => {
const {
path,
projectId,
fileToken,
currentOperateFile,
selectIds,
refresh,
showList,
} = props;
const Message = useMessage();
let deleteFileDialogRef: any = React.createRef();
const showDialog = () => {
deleteFileDialogRef.current.handleClickOpen();
};
useImperativeHandle(props.onRef, () => {
return {
showDialog: showDialog,
};
});
const { run: getDataFileDelRun } = useMyRequest(getDataFileDel, {
onSuccess: (res: any) => {
successDelete();
},
});
const { run: getDataFileDelPackageRun } = useMyRequest(
getDataFileDelPackage,
{
onSuccess: (res: any) => {
successDelete();
},
}
);
const successDelete = () => {
Message.success("删除成功!");
deleteFileDialogRef?.current?.handleClose();
refresh();
};
const deletePathProvidedToDataSet = useMemo(() => {
return path === "/" ? "/" : `${path}/`;
}, [path]);
const deletePathProvidedFileServer = useMemo(() => {
return path === "/" ? `${path}` : `${path}/`;
}, [path]);
// 删除
const handleSubmit = () => {
if (!currentOperateFile) {
// 批量删除
// 要删除的数据集
const datSetDeleteList = showList.filter((item: any) => {
return selectIds.indexOf(item.name) !== -1 && item.type === "dataSet";
});
// 要删除的文件夹
const folderDeleteList = showList.filter((item: any) => {
return selectIds.indexOf(item.name) !== -1 && item.type === "directory";
});
// 要删除的文件
const fileDeleteList = showList.filter((item: any) => {
return (
selectIds.indexOf(item.name) !== -1 &&
item.type !== "dataSet" &&
item.type !== "directory"
);
});
if (datSetDeleteList.length > 0) {
dataSetsDelete(datSetDeleteList);
}
if (folderDeleteList.length > 0) {
foldersDelete(folderDeleteList);
}
if (fileDeleteList.length > 0) {
filesDelete(fileDeleteList);
}
} else {
if (currentOperateFile.type === "dataSet") {
dataSetDelete();
} else if (currentOperateFile.type === "directory") {
folerDelete();
} else {
fileDelete();
}
}
};
// 删除单个数据集
const dataSetDelete = () => {
getDataFileDelRun({
projectId: projectId as string,
names: currentOperateFile.name,
path: deletePathProvidedToDataSet,
});
};
// 删除单个文件夹
const folerDelete = () => {
fileDelete();
const names = currentOperateFile.name;
dataSetInFolerDelete(names);
};
// 删除文件夹中的数据集
const dataSetInFolerDelete = (names: string) => {
getDataFileDelPackageRun({
projectId: projectId as string,
names,
path: deletePathProvidedToDataSet,
});
};
// 删除单个文件
const fileDelete = () => {
CloudEController.JobOutFileDel(
`${deletePathProvidedFileServer}${currentOperateFile.name}`,
fileToken as string,
projectId as string
)?.then((res) => {
successDelete();
});
};
// 删除多个数据集
const dataSetsDelete = (datSetDeleteList: Array<any>) => {
getDataFileDelRun({
projectId: projectId as string,
names: datSetDeleteList.map((item: any) => item.name).join(","),
path: deletePathProvidedToDataSet,
});
};
// 删除多个文件夹
const foldersDelete = (folderDeleteList: Array<any>) => {
filesDelete(folderDeleteList);
const names = folderDeleteList.map((item: any) => item.name).join(",");
dataSetInFolerDelete(names);
};
// 删除多个文件
const filesDelete = (fileDeleteList: Array<any>) => {
const deletePath = fileDeleteList
.map((item: any) => {
return `${deletePathProvidedFileServer}${item.name}`;
})
.join(" ");
CloudEController.JobOutFileDel(
deletePath,
fileToken as string,
projectId as string
)?.then((res) => {
successDelete();
});
};
const submitloading = false;
return (
<MyDialog
handleSubmit={handleSubmit}
onRef={deleteFileDialogRef}
title="提示"
submitloading={submitloading}
>
{currentOperateFile
? "确认删除该数据吗?"
: `确认删除这${selectIds.length}条数据吗?`}
</MyDialog>
);
};
export default DeleteDialog;
......@@ -20,7 +20,14 @@
display: flex;
justify-content: flex-start;
align-items: center;
}
.treeLabelText{
line-height: 44px;
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow:ellipsis;
white-space: nowrap;
width: 320px;
}
.labelFolderIcon {
margin-right: 9px;
......
......@@ -45,16 +45,23 @@
box-sizing: border-box;
position: relative;
}
.tableBox {
/* .tableBox {
height: 300px;
overflow: scroll;
}
} */
.fileIconBox {
display: flex;
justify-content: flex-start;
align-items: center;
}
.fileIconBoxText{
display: block;
width: 260px;
overflow: hidden;
text-overflow: ellipsis;
-o-text-overflow:ellipsis;
white-space: nowrap;
}
.noFile {
position: absolute;
top: 92px;
......
import React, { useState, useImperativeHandle, useCallback } from "react";
import React, {
useState,
useImperativeHandle,
useCallback,
useMemo,
} from "react";
import style from "./index.module.css";
import { TextField } from "@mui/material";
import MyDialog from "@/components/mui/MyDialog";
import { Button } from "@mui/material";
import { checkIsNumberLetterChinese, uuid } from "@/utils/util";
import { uuid } from "@/utils/util";
import { useMessage } from "@/components/MySnackbar";
import { useDropzone } from "react-dropzone";
import Table from "@/components/Material.Ui/Table";
......@@ -12,68 +16,140 @@ import fileIcon from "@/assets/project/fileIcon.svg";
import noFile from "@/assets/project/noFile.svg";
import uploaderIcon from "@/assets/project/uploaderIcon.svg";
import classnames from "classnames";
import { getMbfromB } from "@/utils/util";
import { observer } from "mobx-react-lite";
import { storageUnitFromB } from "@/utils/util";
import { observer } from "mobx-react";
import { useStores } from "@/store";
import { toJS } from "mobx";
import useGlobalStore from "@/hooks/useGlobalStore";
import { APIOPTION, urlToken } from "@/api/fileserver/raysyncApi";
import UseTusUpload from "@/utils/Upload/tusUpload";
const UpLoaderFile = observer((props: any) => {
const uploadInfoStore = useGlobalStore("fileList");
const { fileListStore } = useStores();
const message = useMessage();
const [fileList, setFileList] = useState<any>([]);
// list 是项目数据table的数据
const { path, list } = props;
// 集合当前路径下的文件、文件夹、数据集 和已选择要上传的文件列表
const nowNameList = useMemo(() => {
return [...list, ...fileList];
}, [list, fileList]);
const currentProjectStore = toJS(useGlobalStore("currentProjectStore"));
const uploadInfoStore = toJS(useGlobalStore("fileListStore"));
const { uploadFile } = UseTusUpload(uploadInfoStore);
const onDrop = useCallback(
(acceptedFiles: any) => {
// 判断是否有文件名重复
const fileListRepeatName = getRepeatName(fileList, acceptedFiles);
const listRepeatName = getRepeatName(list, acceptedFiles);
if (fileListRepeatName || listRepeatName) {
message.error(`${fileListRepeatName || listRepeatName}文件已存在`);
return;
// 获取重复的项目文件列表和要上传(名称不重复就上传)的文件
const getRepeatFileAndGetUploderFileList = (
acceptedFiles: Array<any>
) => {
let repeatFileList: any = [];
let uploderFileList: any = [];
acceptedFiles.forEach((fItem: any, index: number) => {
if (
nowNameList.some((nItem: any) => {
return nItem.name === fItem.name;
})
) {
repeatFileList.push(acceptedFiles[index]);
} else {
uploderFileList.push(acceptedFiles[index]);
}
});
return {
repeatFileList,
uploderFileList,
};
};
const repeatAndUploaderFileList =
getRepeatFileAndGetUploderFileList(acceptedFiles);
if (repeatAndUploaderFileList.repeatFileList.length > 0) {
message.error(
`“${repeatAndUploaderFileList.repeatFileList
.map((i: any) => i.name)
.join("、")}”文件已存在`
);
}
// 插入新的文件列表
const popLength = 10 - fileList.length;
let newFileList = [...acceptedFiles.slice(0, popLength), ...fileList];
if (
fileList.length + repeatAndUploaderFileList.uploderFileList.length >
10
) {
message.error("最大支持同时上传10个文件");
}
let newFileList = [
...repeatAndUploaderFileList.uploderFileList.slice(0, popLength),
...fileList,
];
setFileList(newFileList);
},
[fileList, list, message]
[fileList, message, nowNameList]
);
const getRepeatName = (fList: Array<any>, Alist: Array<any>) => {
let repeatName = "";
Alist.forEach((aItem) => {
fList.forEach((fItem: any) => {
if (fItem.name === aItem.name) {
repeatName = fItem.name;
}
});
});
return repeatName;
};
const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
const submitloading = false;
let dialogRef: any = React.createRef();
const handleSubmit = () => {
const newFileList = fileList?.map((item: any) => {
return {
id: uuid(),
open: false,
list: item,
isPermanence: true,
};
});
uploadInfoStore.setFileList(newFileList);
const getFileToken = useCallback(
(newFileList: any) => {
let url =
APIOPTION() +
"/parallelupload/" +
urlToken(
currentProjectStore?.currentProjectInfo?.filetoken || "",
currentProjectStore?.currentProjectInfo?.id as string
);
console.log("handleSubmit");
newFileList?.forEach((item: any) => {
uploadFile(
item,
item?.file,
url,
currentProjectStore?.currentProjectInfo?.filetoken || "",
`${path}/${item?.file?.name}`
);
});
},
[
currentProjectStore?.currentProjectInfo?.filetoken,
currentProjectStore?.currentProjectInfo?.id,
path,
uploadFile,
]
);
const handleSubmit = () => {
const newFileList =
fileList?.map((item: any) => {
return {
id: uuid(),
path,
list: [],
file: item,
};
}) || [];
toJS(fileListStore?.setNewFileList)(newFileList);
if (newFileList?.length) {
getFileToken(newFileList);
}
dialogRef.current.handleClose();
};
const showDialog = () => {
dialogRef.current.handleClickOpen();
initData();
};
const initData = () => {
setFileList([]);
};
useImperativeHandle(props.onRef, () => {
......@@ -92,15 +168,13 @@ const UpLoaderFile = observer((props: any) => {
return (
<span className={style.fileIconBox}>
<img className={style.fileIcon} src={fileIcon} alt="" />
{item.name}
<span className={style.fileIconBoxText}>{item.name}</span>
</span>
);
};
// 1,048,576
const renderSize = (item: any) => {
return (
<span>{item.size ? `${getMbfromB(Number(item.size))}MB` : "-"}</span>
);
return <span>{item.size ? storageUnitFromB(Number(item.size)) : "-"}</span>;
};
const handleRowDelete = (index: number) => {
......@@ -183,12 +257,14 @@ const UpLoaderFile = observer((props: any) => {
fontSize: "12px",
lineHeight: "20px",
color: "#8A9099",
// padding: "12px 24px",
}}
tableBoySx={{
backgroundColor:
fileList.length >= 10 ? "rgba(255, 0, 0, 0.6)" : "",
}}
tableContainerStyle={{
maxHeight: "300px",
}}
></Table>
</div>
{fileList.length === 0 && (
......
......@@ -3,6 +3,7 @@
}
.projectDataStickyTop {
padding: 28px 24px;
position: relative;
}
.projectDataTitle {
font-size: 18px;
......@@ -73,6 +74,10 @@
align-items: center;
}
.folderPointer{
cursor: pointer;
}
.folderIcon {
margin-right: 12px;
}
......@@ -111,4 +116,21 @@
}
.showPathSpanActive{
color: #1370FF;
}
.noDataBox{
background-color: #fff;
height: calc(100vh - 377px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
position: relative;
top: -53px;
}
.noDataText{
margin-top: 8px;
font-size: 14px;
line-height: 22px;
color: #8A9099;
}
\ No newline at end of file
This diff is collapsed.
......@@ -34,7 +34,7 @@
outline: none;
}
.projectInfoListLiValue:focus {
border: 1px solid #136efa;
border: 2px solid #136efa;
}
.projectInfoTextarea {
line-height: 22px;
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-01 09:15:10
* @LastEditTime: 2022-06-14 15:40:27
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -21,14 +21,17 @@ import { toJS } from "mobx";
import { observer } from "mobx-react-lite";
import InformationDisplay from "@/components/InformationDisplay";
import classnames from "classnames";
import { Button } from "@mui/material";
import { Button, TextField } from "@mui/material";
import LoadingButton from "@mui/lab/LoadingButton";
import { useMessage } from "@/components/MySnackbar";
import Loading from "@/views/Loading";
import MyDialog from "@/components/mui/MyDialog";
import { getProjectList } from "../../project";
import { checkIsNumberLetterChinese } from "@/utils/util";
import { setFileServerEndPointLocalStorage } from "@/views/Project/project";
import {
setFileServerEndPointLocalStorage,
getFiletokenAccordingToId,
} from "@/views/Project/project";
type zoneIdOption = {
id: string;
......@@ -40,9 +43,27 @@ const BaseInfo = observer(() => {
const { currentProjectStore } = useStores();
const [projectInfo, setProjectInfo] = useState<any>({});
const [deleteProjectName, setDeleteProjectName] = useState("");
const [nameCheck, setNameCheck] = useState({
error: false,
help: "",
});
const currentUserName = JSON.parse(
localStorage.getItem("userInfo") || "{}"
).name;
// 是否拥有编辑权限
const hasEditAuth = useMemo(() => {
if (!currentUserName) {
return false;
} else if (!projectInfo.members) {
return false;
} else {
return projectInfo.members.some((item: any) => {
return (
item.username === currentUserName && item.projectRole === "OWNER"
);
});
}
}, [currentUserName, projectInfo]);
const { run, loading } = useMyRequest(getProject, {
onSuccess: (result: any) => {
setProjectInfo(result.data);
......@@ -98,11 +119,50 @@ const BaseInfo = observer(() => {
];
}, [projectInfo, zoneIdMap]);
const checkName = (name: string, showMessage = false) => {
let help = "";
if (name) {
if (name.length > 30) {
help = "格式不正确,必须在30字符以内,仅限大小写字母、数字、中文";
setNameCheck({
error: true,
help,
});
showMessage && message.error(help);
return false;
} else if (checkIsNumberLetterChinese(name)) {
setNameCheck({
error: false,
help: "",
});
return true;
} else {
help = "格式不正确,必须在30字符以内,仅限大小写字母、数字、中文";
setNameCheck({
error: true,
help,
});
showMessage && message.error(help);
return false;
}
} else {
help = "项目名称不能为空";
setNameCheck({
error: true,
help,
});
showMessage && message.error(help);
return false;
}
};
const nameChange = (e: any) => {
setProjectInfo({
...projectInfo,
name: e.target.value,
});
checkName(e.target.value);
// setNameCheck
};
const descChange = (e: any) => {
......@@ -126,16 +186,10 @@ const BaseInfo = observer(() => {
// 修改项目
const handleClickUpdate = () => {
if (projectInfo.name) {
if (checkIsNumberLetterChinese(projectInfo.name)) {
updateProjectRun({ ...projectInfo, product: "CADD" });
} else {
message.info(
"格式不正确,必须在30字符以内,仅限大小写字母、数字、中文"
);
}
if (checkName(projectInfo.name, true)) {
updateProjectRun({ ...projectInfo, product: "CADD" });
} else {
message.info("项目名称不能为空");
return;
}
};
......@@ -147,9 +201,23 @@ const BaseInfo = observer(() => {
DialogRef.current.handleClose();
const projectList = await getProjectList();
currentProjectStore.setProjectList(projectList);
currentProjectStore.changeProject(projectList[0]);
setFileServerEndPointLocalStorage(projectList[0].zoneId);
setProjectInfo(projectList[0]);
// 项目删完了
if (projectList.length === 0) {
currentProjectStore.changeProject({});
localStorage.setItem("fileServerEndPoint", "");
setProjectInfo({});
} else {
projectList[0].filetoken = getFiletokenAccordingToId(
projectList[0].id
);
currentProjectStore.changeProject(projectList[0]);
setFileServerEndPointLocalStorage(projectList[0].zoneId);
getFiletokenAccordingToId(projectList[0].id).then((res) => {
projectList[0].filetoken = res;
currentProjectStore.changeProject(projectList[0]);
});
setProjectInfo(projectList[0]);
}
},
}
);
......@@ -158,6 +226,7 @@ const BaseInfo = observer(() => {
// 显示删除弹窗
const handleClickDelete = () => {
DialogRef.current.handleClickOpen();
setDeleteProjectName("");
};
const deleteProjectNameChange = (e: any) => {
......@@ -181,7 +250,7 @@ const BaseInfo = observer(() => {
<Loading />
</div>
);
} else if (currentUserName !== projectInfo.owner) {
} else if (!hasEditAuth) {
return <InformationDisplay infoList={infoList} />;
} else {
return (
......@@ -195,13 +264,26 @@ const BaseInfo = observer(() => {
>
项目名称
</div>
<input
<TextField
required
error={nameCheck.error}
id="name"
variant="outlined"
value={projectInfo.name}
onChange={nameChange}
helperText={nameCheck.help}
size="small"
sx={{
width: "560px",
}}
/>
{/* <input
value={projectInfo.name}
className={style.projectInfoListLiValue}
onChange={nameChange}
maxLength={30}
placeholder="请输入项目名称"
></input>
></input> */}
</div>
<div className={style.projectInfoListLi}>
<div className={style.projectInfoListLiLabel}>项目描述</div>
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-11 15:24:15
* @LastEditTime: 2022-06-15 19:04:11
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -35,16 +35,9 @@ const AddMember = observer((props: IProps) => {
const [projectMember, setProjectMember] = useState("");
const [filterTableData, setFilterTableData] = useState([]);
const [checkData, setCheckData] = useState<string[]>([]);
const [selectOptions, setSelectOptions] = useState<IOption[]>([]);
const Message = useMessage();
const selectOptions = useMemo(() => {
return [
{ value: "VIEWER", label: "查看者" },
{ value: "DEVELOPER", label: "研发者" },
{ value: "MANAGER", label: "管理者" },
];
}, []);
const changePermission = useCallback(
(val: IOption, index: number) => {
const tableDataIndex = tableData[index] as any;
......@@ -56,34 +49,53 @@ const AddMember = observer((props: IProps) => {
[tableData]
);
const columns = [
{ id: "checkbox", width: 50 },
{ id: "username", label: "项目成员", width: 160 },
{
id: "projectRole",
label: "项目权限",
width: 160,
render: (item: string, row: any, index: number) => {
const defaultValue = selectOptions.filter(
(every) => every.value === item
);
return (
<MySelect
input={<OutlinedInput />}
value={
defaultValue?.length
? defaultValue[0]
: { value: "VIEWER", label: "查看者" }
}
onChange={(val) => changePermission(val, index)}
options={selectOptions}
size="small"
/>
);
const columns = useMemo(() => {
return [
{ id: "checkbox", width: 50 },
{ id: "username", label: "项目成员", width: 160 },
{
id: "projectRole",
label: "项目权限",
width: 160,
render: (item: string, row: any, index: number) => {
const defaultValue = selectOptions.filter(
(every) => every.value === item
);
return (
<MySelect
input={<OutlinedInput />}
value={
defaultValue?.length
? defaultValue[0]
: { value: "VIEWER", label: "查看者" }
}
onChange={(val) => changePermission(val, index)}
options={selectOptions}
size="small"
/>
);
},
},
},
];
];
}, [changePermission, selectOptions]);
useEffect(() => {
if (addMemberDialog) {
http.get<IResponse<any>>("/cpp/project/listroles").then((res) => {
const arr = [];
const { data } = res;
for (const key in data) {
arr.push({
label: String(data[key]),
value: key,
});
}
setSelectOptions(arr);
});
}
}, [addMemberDialog, http]);
/** 过滤表格数据 */
useEffect(() => {
if (!!projectMember) {
const newVal =
......@@ -96,6 +108,7 @@ const AddMember = observer((props: IProps) => {
}
}, [projectMember, tableData]);
/** 获取表格数据 */
useEffect(() => {
if (!addMemberDialog) return;
const projectInfo = toJS(currentProjectStore?.currentProjectInfo);
......@@ -104,19 +117,20 @@ const AddMember = observer((props: IProps) => {
params: { id: projectInfo?.id || "" },
})
.then((res) => {
if (res.data.length) {
setTableData(res?.data);
}
setTableData(res?.data);
});
}, [currentProjectStore?.currentProjectInfo, http, addMemberDialog]);
const onClose = () => {
const onClose = (event: any = {}, reason: any = "other") => {
// 点击弹窗外不关闭弹窗
if (reason === "backdropClick") {
return;
}
setAddMemberDialog(false);
};
const onConfirm = () => {
const projectInfo = toJS(currentProjectStore?.currentProjectInfo);
console.log(tableData, 1111);
const params = tableData.filter((item: any) => {
return checkData.includes(item?.username);
});
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-07 15:55:26
* @LastEditTime: 2022-06-15 13:50:54
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -34,10 +34,6 @@ const RemoveItem = observer((props: IProps) => {
};
const onConfirm = () => {
const projectInfo = toJS(currentProjectStore?.currentProjectInfo);
console.log(111111, {
id: projectInfo?.id || "",
username: removeDialog.username,
});
http
.del<IResponse<any>>(
`/cpp/project/removemember?id=${projectInfo?.id || ""}&username=${
......
......@@ -2,7 +2,7 @@
* @Author: 吴永生#A02208 yongsheng.wu@wholion.com
* @Date: 2022-05-31 10:18:13
* @LastEditors: 吴永生#A02208 yongsheng.wu@wholion.com
* @LastEditTime: 2022-06-10 18:08:00
* @LastEditTime: 2022-06-16 20:49:14
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
......@@ -25,8 +25,9 @@ import { IDialogInfo } from "./interface";
import { toJS } from "mobx";
import { useStores } from "@/store";
import { isProjectOwner } from "@/utils/util";
import { observer } from "mobx-react";
const ProjectMembers = () => {
const ProjectMembers = observer(() => {
const http = useHttp();
const { currentProjectStore } = useStores();
......@@ -49,22 +50,18 @@ const ProjectMembers = () => {
const [projectName, setProjectMember] = useState("");
/** 过滤后数据 */
const [filterTableData, setFilterTableData] = useState([]);
/** 项目所有者 */
const [projectOwner, setProjectOwner] = useState("");
const columns = useMemo(() => {
const val: any = [
{ id: "username", label: "成员名称" },
{ id: "projectRoleDesc", label: "项目权限" },
{ id: "phone", label: "联系方式" },
];
if (isProjectOwner(projectOwner)) {
val.push({
{
id: "operation",
label: "操作",
width: 160,
render: (item: any, row: any) => {
return projectOwner === row?.username ? null : (
return row?.projectRole === "OWNER" ? null : (
<>
<span
style={{ color: "#1370FF", cursor: "pointer" }}
......@@ -85,10 +82,10 @@ const ProjectMembers = () => {
</>
);
},
});
}
},
];
return val;
}, [projectOwner]);
}, []);
/** 获取表格数据 */
const getTableList = useCallback(() => {
......@@ -100,7 +97,6 @@ const ProjectMembers = () => {
})
.then((res) => {
const { data = {} } = res;
setProjectOwner(data.owner);
setTableData(data?.members || []);
});
}, [currentProjectStore?.currentProjectInfo, http]);
......@@ -154,7 +150,7 @@ const ProjectMembers = () => {
sx={{ width: 340, height: 32 }}
endAdornment={<SearchIcon style={{ color: "#8A9099" }} />}
/>
{isProjectOwner(projectOwner) ? (
{currentProjectStore?.currentProjectInfo?.projectRole === "OWNER" ? (
<Button
style={{ backgroundColor: "#1370FF " }}
variant="contained"
......@@ -194,6 +190,6 @@ const ProjectMembers = () => {
/>
</>
);
};
});
export default memo(ProjectMembers);
......@@ -19,8 +19,6 @@ import Tabs from "@/components/mui/Tabs";
const ProjectSetting = observer(() => {
const { currentProjectStore } = useStores();
const [value, setValue] = useState("projectMember");
const tabList = useMemo(() => {
return [
{
......@@ -36,11 +34,7 @@ const ProjectSetting = observer(() => {
];
}, []);
const changeTabs = (val: string) => {
setValue(val);
};
if (currentProjectStore.currentProjectInfo.name || true) {
if (currentProjectStore.currentProjectInfo.name) {
return (
<div style={{ padding: 24 }}>
<div style={{ display: "flex", alignItems: "center" }}>
......@@ -50,7 +44,7 @@ const ProjectSetting = observer(() => {
</span>
</div>
<Box sx={{ width: "100%", typography: "body1" }}>
<Tabs value={value} onChange={changeTabs} tabList={tabList} />
<Tabs tabList={tabList} />
</Box>
</div>
);
......
......@@ -18,14 +18,24 @@ import WorkbenchList from "./workbenchList";
import Tabs from "@/components/mui/Tabs";
import usePass from "@/hooks/usePass";
import Template from "@/assets/project/workbenchTemplate.svg"
import Template_select from "@/assets/project/workbenchTemplate_select.svg"
import List from "@/assets/project/workbenchList.svg"
import List_select from "@/assets/project/workbenchList_select.svg"
//ui
import ButtonDemo from "@/views/mui_demo/button"
import InputDemo from "@/views/mui_demo/input"
const ProjectWorkbench = observer(() => {
const { currentProjectStore } = useStores();
const isPass = usePass();
const [value, setValue] = useState("workbenchTemplate");
useEffect(() => {
console.log(isPass("PROJECT_WORKBENCH_FLOES_USE",'USER'), "11111111111");
console.log(isPass("PROJECT_WORKBENCH_FLOES_USE", 'USER'), "11111111111");
console.log(isPass("PROJECT_WORKBENCH_FLOES"), 'wwwwwwwwwww')
}, [])
const tabList = useMemo(() => {
......@@ -34,18 +44,35 @@ const ProjectWorkbench = observer(() => {
label: "工作流模版",
value: "workbenchTemplate",
component: <WorkbenchTemplate />,
hide: !isPass("PROJECT_WORKBENCH_FLOES"),
icon: Template,
iconed: Template_select
},
{
label: "任务列表",
value: "workbenchList",
component: <WorkbenchList />,
hide: !isPass("PROJECT_WORKBENCH_JOBS"),
icon: List,
iconed: List_select
},
{
label: "按钮组件",
value: "MUI_BUTTON",
component: <ButtonDemo />,
icon: List,
iconed: List_select
},
{
label: "输入框组件",
value: "MUI_INPUT",
component: <InputDemo />,
icon: List,
iconed: List_select
},
];
}, []);
const changeTabs = (val: string) => {
setValue(val);
};
return (
<div style={{ padding: 24 }}>
......@@ -56,7 +83,7 @@ const ProjectWorkbench = observer(() => {
</span>
</div>
<Box sx={{ width: "100%", typography: "body1" }}>
<Tabs value={value} onChange={changeTabs} tabList={tabList} />
<Tabs tabList={tabList} />
</Box>
</div>
);
......
import { memo, useCallback, useEffect, useMemo, useState } from "react";
import styles from "../index.module.css";
import { Box, Typography } from "@mui/material";
import Button from "@mui/material/Button";
import Dialog from "@/components/mui/Dialog";
const SimpleDialog = (props: any) => {
const { openDialog, closeDialog, onConfirm, text, title } = props;
return (
< >
<Dialog
open={openDialog}
onClose={closeDialog}
onConfirm={onConfirm}
title={title}
>
<Box>
<Typography sx={{ fontSize: '14px', fontWeight: '400' }}>{text}</Typography>
</Box>
</Dialog>
</>
);
};
export default memo(SimpleDialog);
.headerBox {
margin-bottom: 20px;
}
.tabHeader {
display: flex;
align-items: center;
}
.tabHeaderSelect {
margin-left: 16px;
}
.body {
margin-top: 24px;
border-top: 1px solid #F0F2F5;
overflow: hidden;
overflow-y: auto;
height: calc(100vh - 290px);
}
.tabBox {
padding: 15px 0px 16px 24px;
display: flex;
align-items: center;
width: 100%;
border-bottom: 1px solid #F0F2F5;
}
.tabBox:hover {
background-color: #F5F6F7;
}
.tabBoxInfo {
width: 24%;
}
.tabBoxDescInfo {
display: flex;
}
.tabBoxTitle {
font-size: 14px;
font-weight: 600;
color: #1E2633;
margin-bottom: 10px;
}
.tabBoxDesc {
font-size: 12px;
font-weight: 400;
color: #8A9099;
}
.tabBoxTime {
font-size: 12px;
font-weight: 400;
color: #565C66;
margin-left: 4px;
}
.tabBoxMiddle {
display: flex;
align-items: center;
width: 10%;
}
.tabBoxJobStatus {
display: flex;
align-items: center;
width: 46%;
}
.tabBoxStatusText {
font-size: 12px;
font-weight: 400;
color: #1E2633;
margin: 0px 16px 0px 6px;
white-space: nowrap;
}
.tabBoxJobOperate {
width: 10%;
display: flex;
justify-content: center;
}
\ No newline at end of file
......@@ -2,12 +2,13 @@
import { memo, useCallback, useEffect, useMemo, useState } from "react";
import styles from "../index.module.css";
import { Box, Typography } from "@mui/material";
import Button from "@mui/material/Button";
import Button from "@/components/mui/Button";
import Dialog from "@/components/mui/Dialog";
import OutlinedInput from "@mui/material/OutlinedInput";
import SearchIcon from "@mui/icons-material/Search";
import Checkbox from '@mui/material/Checkbox';
import CloseOutlinedIcon from '@mui/icons-material/CloseOutlined';
import noData from '../../../../../assets/project/noTemplate.svg'
import _ from "lodash";
const AddTemplate = (props: any) => {
......@@ -36,15 +37,22 @@ const AddTemplate = (props: any) => {
endAdornment={<SearchIcon style={{ color: "#8A9099" }} />}
/>
<Button
style={{ backgroundColor: "#1370FF", marginLeft: "12px" }}
variant="contained"
onClick={addTemplateCallback}
size="small"
>
添加模版{selectTemplateData.length === 0 ? "" : `(${selectTemplateData.length})`}
</Button>
click={addTemplateCallback}
size={"small"}
text={'添加模版' + (selectTemplateData.length === 0 ? "" : `(${selectTemplateData.length})`)}
/>
</Box>
{
addTemplateList.length === 0 && <Box sx={{
display: 'flex', alignItems: 'center', flexDirection: 'column', minHeight: 'calc(100vh - 376px)',
justifyContent: 'center'
}}>
<img alt="" src={noData} />
<Typography sx={{ fontSize: '12px', fontWeight: '400', color: '#8A9099' }}>暂未相关模版</Typography>
</Box>
}
<Box sx={{ display: "flex", flexWrap: 'wrap', overflowX: 'hidden', overflowY: 'overlay', marginLeft: '-8px' }} >
{
addTemplateList.map((item: any, key: any) => {
......
......@@ -2,7 +2,7 @@
import { memo, useCallback, useEffect, useMemo, useState } from "react";
import styles from "../index.module.css";
import { Box, Typography } from "@mui/material";
import Button from "@mui/material/Button";
import Button from "@/components/mui/Button";
import usePass from "@/hooks/usePass";
const TemplateBox = (props: any) => {
......@@ -23,27 +23,15 @@ const TemplateBox = (props: any) => {
display: 'flex', justifyContent: 'end'
}} >
{
isPass("PROJECT_WORKBENCH_FLOES_USE", 'MANAGER') && <Button
style={{ backgroundColor: "#F0F2F5", color: "#565C66" }}
variant="contained"
onClick={() => { props.startDialog(info.id) }}
size="small"
>
删除模版
</Button>
isPass("PROJECT_WORKBENCH_FLOES_USE", 'MANAGER') &&
<Button size={"small"} text={'删除模版'} click={() => { props.startDialog(info.id) }} style={{ backgroundColor: "#F0F2F5", color: "#565C66" }} />
}
{
isPass("PROJECT_WORKBENCH_FLOES_USE", 'USER') && <Button
style={{ backgroundColor: "#1370FF", marginLeft: "12px" }}
variant="contained"
// onClick={addTemplateBlock}
size="small"
>
使用模版
</Button>
isPass("PROJECT_WORKBENCH_FLOES_USE", 'USER') &&
<Button size={"small"} text={'使用模版'} click={() => { }} style={{ marginLeft: "12px" }} />
}
</Box>
</Box>
</Box >
);
};
......
.headerBox {
/* display: flex;
justify-content: space-between;
align-items: center; */
margin-bottom: 20px;
}
......
......@@ -6,13 +6,13 @@
* @FilePath: /bkunyun/src/views/Project/ProjectSetting/index.tsx
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { memo, useCallback, useEffect, useMemo, useState } from "react";
import { memo, SetStateAction, useCallback, useEffect, useMemo, useState } from "react";
import { Box, Typography } from "@mui/material";
import styles from "./index.module.css";
import OutlinedInput from "@mui/material/OutlinedInput";
import SearchIcon from "@mui/icons-material/Search";
// import Button from "@/components/mui/Button";
import Button from "@mui/material/Button";
import Button from "@/components/mui/Button";
// import Button from "@mui/material/Button";
import Add from "@mui/icons-material/Add";
import useMyRequest from "@/hooks/useMyRequest";
import TemplateBox from "./components/templateBox"
......@@ -29,9 +29,13 @@ import _ from "lodash";
import { IResponse, useHttp } from "@/api/http";
import { useStores } from "@/store";
import usePass from "@/hooks/usePass";
import { toJS } from "mobx";
import { observer } from "mobx-react-lite";
const ProjectMembers = () => {
const ProjectMembers = observer(() => {
const { currentProjectStore } = useStores();
const projectIdData = toJS(currentProjectStore.currentProjectInfo.id);
const isPass = usePass();
/** 搜索模板名称 */
......@@ -92,6 +96,12 @@ const ProjectMembers = () => {
});
}, [currentProjectStore.currentProjectInfo.id, getTemplateInfo]);
useEffect(() => {
console.log('projectIdData: ', projectIdData);
}, [projectIdData])
/** 点击添加工作流模版 */
const onAddMember = () => {
// setAddMemberDialog(true);
......@@ -159,11 +169,17 @@ const ProjectMembers = () => {
}
const searchChange = (data: any) => {
setTemplateName(data.length > 30 ? data.slice(0, 30) : data);
}
useEffect(() => {
getTemplateInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
title: templateName
});
setTimeout(() => {
getTemplateInfo({
projectId: currentProjectStore.currentProjectInfo.id as string,
title: templateName
});
}, 300)
}, [templateName]);
return (
......@@ -172,10 +188,9 @@ const ProjectMembers = () => {
<Box className={styles.tabBox} >
<OutlinedInput
onChange={(e: any) => {
_.debounce(() => {
setTemplateName(e.target.value);
}, 200)();
searchChange(e.target.value)
}}
value={templateName}
placeholder="输入关键词搜索"
size="small"
sx={{ width: 340, height: 32 }}
......@@ -183,21 +198,14 @@ const ProjectMembers = () => {
/>
{
templateList.length > 0 && isPass("PROJECT_WORKBENCH_FLOES_ADD", 'MANAGER') && <Button
style={{ backgroundColor: "#1370FF " }}
variant="contained"
onClick={addTemplateBlock}
startIcon={<Add />}
size="small"
>
添加工作流模版
</Button>
templateList.length > 0 && isPass("PROJECT_WORKBENCH_FLOES_ADD", 'MANAGER') &&
<Button text={'添加工作流模版'} img={<Add />} click={addTemplateBlock} size={'small'} />
}
</Box>
{
templateList.length === 0 && !isPass("PROJECT_WORKBENCH_FLOES_ADD", 'MANAGER') &&
templateList.length === 0 && templateName.length > 0 &&
<Box sx={{
display: 'flex', alignItems: 'center', flexDirection: 'column', minHeight: 'calc(100vh - 376px)',
justifyContent: 'center'
......@@ -216,7 +224,7 @@ const ProjectMembers = () => {
</Box>
}
{
templateList.length === 0 && isPass("PROJECT_WORKBENCH_FLOES_ADD", 'MANAGER') && <Box className={styles.addNewTemplate}
templateList.length === 0 && templateName.length === 0 && isPass("PROJECT_WORKBENCH_FLOES_ADD", 'MANAGER') && <Box className={styles.addNewTemplate}
onClick={addTemplateBlock}
>
<Add sx={{ color: "#565C66", fontSize: "20px", width: "30px", height: '30px' }} />
......@@ -244,6 +252,6 @@ const ProjectMembers = () => {
</Box>
);
};
});
export default memo(ProjectMembers);
......@@ -8,6 +8,10 @@ import { useMessage } from "@/components/MySnackbar";
import { getProjectList } from "../../project";
import { useStores } from "@/store";
import { checkIsNumberLetterChinese } from "@/utils/util";
import {
setFileServerEndPointLocalStorage,
getFiletokenAccordingToId,
} from "@/views/Project/project";
type zoneIdOption = {
id: string;
......@@ -18,14 +22,25 @@ const AddProject = (props: any) => {
const { currentProjectStore } = useStores();
const message = useMessage();
let DialogRef: any = React.createRef();
const [name, setName] = useState("");
const [nameCheck, setNameCheck] = useState({
error: false,
help: "",
});
const [desc, setDesc] = useState("");
const [descCheck, setDescCheck] = useState({
error: false,
help: "",
});
const [zoneId, setZoneId] = useState("");
const [zoneIdOptions, setZoneIdOptions] = useState<Array<zoneIdOption>>([]);
const [submitloading, setSubmitloading] = useState(false);
useImperativeHandle(props.onRef, () => {
return {
handleClickOpen: handleClickOpen,
};
});
const [zoneId, setZoneId] = useState("");
const [zoneIdOptions, setZoneIdOptions] = useState<Array<zoneIdOption>>([]);
// 设置计算区
const { run } = useMyRequest(hpczone, {
onSuccess: (result: any) => {
......@@ -33,7 +48,6 @@ const AddProject = (props: any) => {
setZoneId(result[0].id || "");
},
});
const [submitloading, setSubmitloading] = useState(false);
const { run: addProjectRun } = useMyRequest(addProject, {
onBefore: () => {
setSubmitloading(true);
......@@ -45,6 +59,18 @@ const AddProject = (props: any) => {
message.success("新建项目成功");
const projectList = await getProjectList();
currentProjectStore.setProjectList(projectList);
let project: any = {};
projectList.forEach((item: any) => {
if (item.name === name) {
project = { ...item };
}
});
currentProjectStore.changeProject(project);
setFileServerEndPointLocalStorage(project.zoneId);
getFiletokenAccordingToId(project.id).then((res) => {
project.filetoken = res;
currentProjectStore.changeProject(project);
});
}
},
onError: () => {
......@@ -58,18 +84,17 @@ const AddProject = (props: any) => {
const handleClickOpen = () => {
DialogRef.current.handleClickOpen();
initData()
};
const [name, setName] = useState("");
const [nameCheck, setNameCheck] = useState({
error: false,
help: "",
});
const [desc, setDesc] = useState("");
const [descCheck, setDescCheck] = useState({
error: false,
help: "",
});
const initData = () => {
setName('')
setDesc('')
if (zoneIdOptions.length > 0) {
setZoneId(zoneIdOptions[0].id)
}
}
const checkName = (name: string) => {
if (name) {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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