feat: 首页仪表盘接口对接完成

This commit is contained in:
landaiqing
2024-07-17 00:12:32 +08:00
parent d63b76b639
commit 359ef60128
36 changed files with 2510 additions and 1162 deletions

View File

@@ -1,23 +1,23 @@
# 开发环境配置
VITE_NODE_ENV='development'
# 开发环境
VITE_APP_BASE_API='/api'
# 页面 title 前缀
VITE_APP_TITLE=开发环境
# 网络请求公用地址
VITE_API_BASE_URL='http://127.0.0.1:3000'
#VITE_API_BASE_URL='http://1.95.0.111:4000'
VITE_TITLE_NAME='五味子云存储'
# token key
VITE_APP_TOKEN_KEY='schisandra'
# the upload url
VITE_UPLOAD_URL='http://127.0.0.1:3000'
# the websocket url
VITE_WEB_SOCKET_URL='ws://127.0.0.1:3010/wx/socket'
# 开发环境配置
VITE_NODE_ENV='development'
# 开发环境
VITE_APP_BASE_API='/api'
# 页面 title 前缀
VITE_APP_TITLE=开发环境
# 网络请求公用地址
VITE_API_BASE_URL='http://127.0.0.1:5050'
#VITE_API_BASE_URL='http://1.95.0.111:4000'
VITE_TITLE_NAME='五味子云存储'
# token key
VITE_APP_TOKEN_KEY='schisandra'
# the upload url
VITE_UPLOAD_URL='http://127.0.0.1:3000'
# the websocket url
VITE_WEB_SOCKET_URL='ws://127.0.0.1:3010/wx/socket'

View File

@@ -1,3 +1,4 @@
node_modules
.eslintrc.cjs
dist
/src/components/Main/Home/index.tsx

View File

@@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"@ant-design/charts": "^2.1.1",
"@ant-design/icons": "^5.3.7",
"@ant-design/pro-components": "^2.7.10",
"@ant-design/pro-provider": "^2.14.7",

777
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,17 @@
/** @format */
import { BrowserRouter } from "react-router-dom";
import GetRouter from "@/router/getRouter.tsx";
import AuthRoute from "@/router/useAuth.tsx";
const App = () => {
return (
<BrowserRouter>
<AuthRoute>
<GetRouter />
</AuthRoute>
</BrowserRouter>
);
};
export default App;
/** @format */
import { BrowserRouter } from "react-router-dom";
import GetRouter from "@/router/getRouter.tsx";
import AuthRoute from "@/router/useAuth.tsx";
const App = () => {
return (
<BrowserRouter>
<AuthRoute>
<GetRouter />
</AuthRoute>
</BrowserRouter>
);
};
export default App;

61
src/api/oss/ali/index.ts Normal file
View File

@@ -0,0 +1,61 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 初始化ali oss
* @param data 用户id
*/
export const initAliOSS = (data: any) => {
return web.request({
url: "/oss/oss/ali/init",
method: "post",
params: {
userId: data,
},
});
};
/**
* 获取文件目录信息
* @param userId 用户id
* @param dirName 目录名称
* @param bucket 桶名称
*/
export const getDirAndFileList = (userId: any, dirName: any, bucket: any) => {
return web.request({
url: "/oss/oss/ali/listDir",
method: "get",
params: {
userId: userId,
dirName: dirName,
bucket: bucket,
},
});
};
/**
* 查询Ali OSS所有桶
* @param userId
*/
export const getAllAliOSsBucket = (userId: any) => {
return web.request({
url: `/oss/oss/ali/seleteBucket`,
method: "post",
params: {
userId: userId,
},
});
};
/**
* 获取所有阿里云oss配置
* @param userId
*/
export const getAllAliOSSConfig = (userId: any) => {
return web.request({
url: `/oss/oss/ali/return_online`,
method: "get",
params: {
userId: userId,
},
});
};

169
src/api/oss/index.ts Normal file
View File

@@ -0,0 +1,169 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 获取用户存储商
* @param data 用户id
*/
export const getAllStorage = (data: any) => {
return web.request({
url: "/oss/oss/user/selectUserOSSType",
method: "get",
params: {
userId: data,
},
});
};
/**
* 获取存储商所有存储桶
* @param data 用户id
* @param type
*/
export const getStorageBuckets = (data: any, type: any) => {
return web.request({
url: "/oss/oss/" + type + "/seleteBucket",
method: "post",
params: {
userId: data,
},
});
};
/**
* 获取存储桶所有文件
* @param userId
* @param type
* @param bucket
* @param dirName
*/
export const getBucketFiles = (userId: any, bucket: any, dirName: any, type: any) => {
return web.request({
url: "/oss/oss/" + type + "/listDir",
method: "get",
params: {
userId: userId,
bucket: bucket,
dirName: dirName,
},
});
};
/**
* 获取存储商所有存储桶个数
* @param userId
*/
export const getStorageAndBuckets = (userId: any) => {
return web.request({
url: "/oss/oss/user/selectUserOSSType",
method: "get",
params: {
userId: userId,
},
});
};
/**
* 获取用户文件热力图
* @param userId
*/
export const getUserFileHeatMap = (userId: any) => {
return web.request({
url: "/oss/oss/user/selectUserFileHeat",
method: "get",
params: {
userId: userId,
},
});
};
/**
* 获取用户文件流量
* @param userId
*/
export const getUserFileFlow = (userId: any) => {
return web.request({
url: "/oss/oss/user/selectFileFlow",
method: "get",
params: {
userId: userId,
},
});
};
/**
* 获取用户文件个数
* @param userId
*/
export const getUserFileCount = (userId: any) => {
return web.request({
url: "/oss/oss/user/selectFileCount",
method: "get",
params: {
userId: userId,
},
});
};
/**
* 获取用户每月上传文件个数
* @param userId
*/
export const getUserUploadFileDiagramPerMonth = (userId: any) => {
return web.request({
url: "/oss/oss/user/selectUploadFileDiagramPerMonth",
method: "get",
params: {
userId: userId,
},
});
};
/**
* 获取用户每月下载文件个数
* @param userId
*/
export const getUserDownloadFileDiagramPerMonth = (userId: any) => {
return web.request({
url: "/oss/oss/user/selectDownloadFileDiagramPerMonth",
method: "get",
params: {
userId: userId,
},
});
};
/**
* 获取用户最近下载文件
* @param userId
*/
export const getUserRecentDownloadFile = (userId: any) => {
return web.request({
url: "/oss/oss/user/selectRecentDownloadFile",
method: "get",
params: {
userId: userId,
},
});
};
/**
* 获取用户最近上传文件
* @param userId
*/
export const getUserRecentUploadFile = (userId: any) => {
return web.request({
url: "/oss/oss/user/selectRecentUploadFile",
method: "get",
params: {
userId: userId,
},
});
};
/**
* 获取用户最近预览文件
* @param userId
*/
export const getUserRecentPreviewFile = (userId: any) => {
return web.request({
url: "/oss/oss/user/selectPreviewFile",
method: "get",
params: {
userId: userId,
},
});
};

View File

@@ -6,7 +6,7 @@ import web from "@/utils/axios/web.ts";
* 初始化minio
* @param data 用户id
*/
export const initMinio = (data: any) => {
export const initMinioOSS = (data: any) => {
return web.request({
url: "/oss/oss/minio/init",
method: "post",
@@ -33,12 +33,25 @@ export const getDirAndFileList = (userId: any, dirName: any, bucket: any) => {
});
};
/**
* 获取用户拥有的厂商
* 查询MinIO所有桶
* @param userId
*/
export const getBrandsList = (userId: any) => {
export const getAllMinioBucket = (userId: any) => {
return web.request({
url: "/oss/oss/minio/userId",
url: `/oss/oss/minio/seleteBucket`,
method: "post",
params: {
userId: userId,
},
});
};
/**
* 获取MinIO配置信息
* @param userId
*/
export const getAllMinioConfig = (userId: any) => {
return web.request({
url: `/oss/oss/minio/return_online`,
method: "get",
params: {
userId: userId,

View File

@@ -0,0 +1,57 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 初始化qiniu
* @param data 用户id
*/
export const initQiniuOSS = (data: any) => {
return web.request({
url: "/oss/oss/qiniu/init",
method: "post",
params: {
userId: data,
},
});
};
/**
* 获取文件目录信息
* @param userId 用户id
* @param dirName 目录名称
* @param bucket 桶名称
*/
export const getDirAndFileList = (userId: any, dirName: any, bucket: any) => {
return web.request({
url: "/oss/oss/qiniu/listMinioDir",
method: "get",
params: {
userId: userId,
dirName: dirName,
bucket: bucket,
},
});
};
/**
* 查询qiniu所有桶
* @param userId
*/
export const getAllQiniuBucket = (userId: any) => {
return web.request({
url: `/oss/oss/qiniu/seleteBucket`,
method: "post",
params: {
userId: userId,
},
});
};
export const getAllQiniuConfigs = (userId: any) => {
return web.request({
url: `/oss/oss/qiniu/return_online`,
method: "get",
params: {
userId: userId,
},
});
};

View File

@@ -0,0 +1,60 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 初始化Tencent oss
* @param data 用户id
*/
export const initTencentOSS = (data: any) => {
return web.request({
url: "/oss/oss/ali/tencent",
method: "post",
params: {
userId: data,
},
});
};
/**
* 获取文件目录信息
* @param userId 用户id
* @param dirName 目录名称
* @param bucket 桶名称
*/
export const getDirAndFileList = (userId: any, dirName: any, bucket: any) => {
return web.request({
url: "/oss/oss/tencent/listDir",
method: "get",
params: {
userId: userId,
dirName: dirName,
bucket: bucket,
},
});
};
/**
* 查询Tencent OSS所有桶
* @param userId
*/
export const getAllTencentOSsBucket = (userId: any) => {
return web.request({
url: `/oss/oss/tencent/seleteBucket`,
method: "post",
params: {
userId: userId,
},
});
};
/**
* 查询Tencent OSS所有配置
* @param userId
*/
export const getAllTencentOSsConfig = (userId: any) => {
return web.request({
url: `/oss/oss/tencent/return_online`,
method: "get",
params: {
userId: userId,
},
});
};

47
src/api/oss/up/index.ts Normal file
View File

@@ -0,0 +1,47 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 初始化Up oss
* @param data 用户id
*/
export const initUpOSS = (data: any) => {
return web.request({
url: "/oss/oss/up/tencent",
method: "post",
params: {
userId: data,
},
});
};
/**
* 获取文件目录信息
* @param userId 用户id
* @param dirName 目录名称
* @param bucket 桶名称
*/
export const getDirAndFileList = (userId: any, dirName: any, bucket: any) => {
return web.request({
url: "/oss/oss/up/listDir",
method: "get",
params: {
userId: userId,
dirName: dirName,
bucket: bucket,
},
});
};
/**
* 查询Tencent OSS所有桶
* @param userId
*/
export const getAllUpOSsBucket = (userId: any) => {
return web.request({
url: `/oss/oss/up/seleteBucket`,
method: "post",
params: {
userId: userId,
},
});
};

View File

@@ -1,137 +1,150 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 第三方登录
* @param type
*/
export const oauthLogin = (type: string) => {
return web.request({
url: "/auth/oauth/render/" + type,
method: "get",
});
};
/**
* 获取短信验证码
* @param data
*/
export const getSms = (data: any) => {
return web.request({
url: "/auth/sms/sendByTemplate/",
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 注册
* @param data
*/
export const register = (data: API.PhoneRegisterRequest) => {
return web.request({
url: "/auth/auth/user/register",
method: "post",
data: data,
});
};
/**
* 登录
* @param data
*/
export const login = (data: API.LoginRequest) => {
return web.request({
url: "/auth/auth/user/login",
method: "post",
data: data,
});
};
/**
* 手机号登录
* @param data
*/
export const loginByPhone = (data: API.LoginByPhoneRequest) => {
return web.request({
url: "/auth/auth/user/loginByPhone",
method: "post",
data: data,
});
};
/**
* 找回密码
* @param data
*/
export const findPassword = (data: API.findPasswordRequest) => {
return web.request({
url: "/auth/auth/user/findPassword",
method: "post",
data: data,
});
};
/**
* 生成客户端id
*/
export const createClientId = () => {
return web.request({
url: "/auth/auth/user/createClientId",
method: "get",
});
};
/**
* 获取客户端id
* @param clientId
*/
export const getClientId = (clientId: string) => {
return web.request({
url: "/auth/auth/user/getClientId",
method: "post",
data: {
clientId: clientId,
},
});
};
/**
* 获取客户端token
* @param clientId
*/
export const getClientToken = (clientId: string) => {
return web.request({
url: "/auth/auth/user/getClientToken",
method: "post",
params: {
clientId: clientId,
},
});
};
/**
* 生成微信登录二维码
* @param clientId
*/
export const generateQRCode = (clientId: string) => {
return web.request({
url: "/wechat/wx/generateQRCode",
method: "get",
params: {
clientId: clientId,
},
});
};
/**
* 获取用户操蛋权限
* @param userId
*/
export const getUserMenuPermission = (userId: string): any => {
return web.request({
url: "/auth/permission/selectUserPermission",
method: "get",
params: {
userId: userId,
},
});
};
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 第三方登录
* @param type
*/
export const oauthLogin = (type: string) => {
return web.request({
url: "/auth/auth/oauth/render/" + type,
method: "get",
});
};
/**
* 获取短信验证码
* @param data
*/
export const getSms = (data: any) => {
return web.request({
url: "/auth/sms/sendByTemplate/",
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 注册
* @param data
*/
export const register = (data: API.PhoneRegisterRequest) => {
return web.request({
url: "/auth/auth/user/register",
method: "post",
data: data,
});
};
/**
* 登录
* @param data
*/
export const login = (data: API.LoginRequest) => {
return web.request({
url: "/auth/auth/user/login",
method: "post",
data: data,
});
};
/**
* 手机号登录
* @param data
*/
export const loginByPhone = (data: API.LoginByPhoneRequest) => {
return web.request({
url: "/auth/auth/user/loginByPhone",
method: "post",
data: data,
});
};
/**
* 找回密码
* @param data
*/
export const findPassword = (data: API.findPasswordRequest) => {
return web.request({
url: "/auth/auth/user/findPassword",
method: "post",
data: data,
});
};
/**
* 生成客户端id
*/
export const createClientId = () => {
return web.request({
url: "/auth/auth/user/createClientId",
method: "get",
});
};
/**
* 获取客户端id
* @param clientId
*/
export const getClientId = (clientId: string) => {
return web.request({
url: "/auth/auth/user/getClientId",
method: "post",
data: {
clientId: clientId,
},
});
};
/**
* 获取客户端token
* @param clientId
*/
export const getClientToken = (clientId: string) => {
return web.request({
url: "/auth/auth/user/getClientToken",
method: "post",
params: {
clientId: clientId,
},
});
};
/**
* 生成微信登录二维码
* @param clientId
*/
export const generateQRCode = (clientId: string) => {
return web.request({
url: "/wechat/wx/generateQRCode",
method: "get",
params: {
clientId: clientId,
},
});
};
/**
* 获取用户菜单权限
* @param userId
*/
export const getUserMenuPermission = (userId: string): any => {
return web.request({
url: "/auth/auth/permission/selectUserPermission",
method: "get",
params: {
userId: userId,
},
});
};
/**
* 获取用户信息
* @param userId
*/
export const getUserInfoApi = (userId: string): any => {
return web.request({
url: "/auth/auth/user/getUserInfo",
method: "get",
params: {
userId: userId,
},
});
};

View File

@@ -0,0 +1 @@
<svg t="1721106120251" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="11406" width="200" height="200"><path d="M860 64H164c-55.2 0-100 44.8-100 100v696c0 55.2 44.8 100 100 100h696c55.2 0 100-44.8 100-100V164c0-55.2-44.8-100-100-100zM709.5 566.4L536.9 764.3c-13.2 15.1-36.6 15.1-49.8 0L314.5 566.4c-15.5-17.8-2.9-45.5 20.7-45.5h119.7V284.5c0-19.9 16.1-36.1 36.1-36.1h42c19.9 0 36.1 16.1 36.1 36.1v236.4h119.7c23.6-0.1 36.2 27.7 20.7 45.5z" fill="#40D786" p-id="11407"></path></svg>

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -0,0 +1 @@
<svg t="1721105828851" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7265" width="200" height="200"><path d="M758.9376 951.4496H272.6912c-107.264 0-194.2016-86.9376-194.2016-194.2016V271.0016C78.4896 163.7376 165.4272 76.8 272.6912 76.8h486.2464c107.264 0 194.2016 86.9376 194.2016 194.2016v486.2464c0 107.264-86.9376 194.2016-194.2016 194.2016z" fill="#F78748" p-id="7266"></path><path d="M745.1136 444.0576c-14.5408-113.9712-111.6672-200.9088-228.4544-200.9088S302.6944 330.0352 288.2048 444.0576c-75.264 13.1584-131.84 78.9504-131.84 157.0304 0 87.9104 71.5264 159.4368 159.4368 159.4368h58.2656c13.6704 0 24.7296-11.0592 24.7296-24.7296s-11.0592-24.7296-24.7296-24.7296H315.8016c-60.6208 0-109.9776-49.3056-109.9776-109.9776 0-58.0608 45.3632-106.2912 103.2704-109.7216a28.62592 28.62592 0 0 0 26.9312-27.136c4.864-96.2048 84.224-171.5712 180.5824-171.5712s175.7184 75.3664 180.5824 171.6224c0.768 14.592 12.3392 26.2656 26.88 27.0848 57.9584 3.4304 103.3216 51.6608 103.3216 109.7216 0 60.6208-49.3056 109.9776-109.9776 109.9776h-54.9376c-13.6704 0-24.7296 11.0592-24.7296 24.7296s11.0592 24.7296 24.7296 24.7296h54.9376c87.9104 0 159.4368-71.5264 159.4368-159.4368 0.1536-78.1312-56.4736-143.872-131.7376-157.0304z" fill="#F7F8F8" p-id="7267"></path><path d="M532.3776 513.792a24.7296 24.7296 0 0 0-34.4576 0.512l-82.0224 81.8176a24.80128 24.80128 0 0 0-0.0512 35.0208c9.6256 9.6768 25.344 9.6768 35.0208 0.0512l42.24-42.1376v167.0656c0 13.6704 11.0592 24.7296 24.7296 24.7296s24.7296-11.0592 24.7296-24.7296v-164.6592l42.752 40.2432c4.7616 4.5056 10.8544 6.7072 16.9472 6.7072 6.6048 0 13.1584-2.6112 18.0224-7.7824 9.3696-9.9328 8.9088-25.6-1.0752-34.9696l-86.8352-81.8688z" fill="#F7F8F8" p-id="7268"></path></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,16 +1,12 @@
/** @format */
import { Avatar, Button, message } from "antd";
import {
DrawerForm,
ProCard,
ProForm,
ProFormText,
} from "@ant-design/pro-components";
import React, { createContext, useContext, useState } from "react";
import { EditOutlined, EllipsisOutlined, SettingOutlined } from "@ant-design/icons";
import bucket from "../../../../assets/icons/bucket.svg";
import { Avatar, Button, message, Skeleton } from "antd";
import { DrawerForm, ProCard, ProForm, ProFormText } from "@ant-design/pro-components";
import React, { createContext, useContext, useEffect, useState } from "react";
import styles from "./index.module.less";
import bucket from "@/assets/icons/bucket.svg";
import { getAllAliOSsBucket } from "@/api/oss/ali";
import { EditOutlined, EllipsisOutlined, ReloadOutlined, SettingOutlined } from "@ant-design/icons";
const DrawerContext = createContext<{
drawerVisit: boolean;
@@ -26,58 +22,77 @@ const AliDrawer = () => {
};
const ProCardComponent = () => {
const { drawerVisit, setDrawerVisit } = useContext(DrawerContext);
const list = [
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test3",
"test1",
"test2",
"test3",
];
const [buckets, setBuckets] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
async function getAllBucket() {
getAllAliOSsBucket("2").then((res: any) => {
if (res && res.success) {
setBuckets(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getAllBucket().then();
}, []);
const bucketList = () => {
return (
<ProCard
title={"存储桶列表"}
title={"阿里云OSS存储桶列表"}
headerBordered
extra={
<Button type="primary" onClick={() => setDrawerVisit(true)}>
</Button>
<>
<Button
type="default"
shape={"circle"}
style={{ marginRight: 20 }}
onClick={() => {
setLoading(false);
getAllBucket().then();
}}
icon={<ReloadOutlined />}></Button>
<Button type="primary" onClick={() => setDrawerVisit(true)}>
</Button>
</>
}>
<div className={styles.div_proCard}>
{list.map((item, index) => {
return (
<ProCard
headStyle={{ backgroundColor: "#f0f2f5" }}
hoverable
bordered
key={index}
title={<b>{item}</b>}
style={{
width: "180px",
borderWidth: "1px",
}}
actions={[
<SettingOutlined key="setting" />,
<EditOutlined key="edit" />,
<EllipsisOutlined key="ellipsis" />,
]}>
<Avatar shape={"square"} src={bucket} size={"large"} />
<b style={{ marginLeft: 10 }}> size</b>
</ProCard>
);
})}
<Skeleton loading={loading} paragraph={{ rows: 13 }} active>
{buckets &&
Array.from(buckets).map((item: any, index: number) => {
return (
<>
<div key={index}>
<ProCard
headStyle={{ backgroundColor: "#f0f2f5" }}
hoverable
bordered
title={<b>{item.name}</b>}
style={{
width: "180px",
height: 150,
borderWidth: "1px",
marginLeft: 10,
}}
actions={[
<SettingOutlined key="setting" />,
<EditOutlined key="edit" />,
<EllipsisOutlined key="ellipsis" />,
]}>
<Avatar
shape={"square"}
src={bucket as any}
size={"large"}
/>
<b style={{ marginLeft: 10 }}>{item.size}</b>
</ProCard>
</div>
</>
);
})}
</Skeleton>
</div>
</ProCard>
);

View File

@@ -1,11 +1,12 @@
/** @format */
import { Avatar, Button, message } from "antd";
import { Avatar, Button, message, Skeleton } from "antd";
import { DrawerForm, ProCard, ProForm, ProFormText } from "@ant-design/pro-components";
import React, { createContext, useContext, useState } from "react";
import { EditOutlined, EllipsisOutlined, SettingOutlined } from "@ant-design/icons";
import bucket from "../../../../assets/icons/bucket.svg";
import React, { createContext, useContext, useEffect, useState } from "react";
import { EditOutlined, EllipsisOutlined, ReloadOutlined, SettingOutlined } from "@ant-design/icons";
import bucket from "@/assets/icons/bucket.svg";
import styles from "./index.module.less";
import { getAllMinioBucket } from "@/api/oss/minio";
const DrawerContext = createContext<{
drawerVisit: boolean;
@@ -21,58 +22,74 @@ const MinioDrawer = () => {
};
const ProCardComponent = () => {
const { drawerVisit, setDrawerVisit } = useContext(DrawerContext);
const list = [
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test3",
"test1",
"test2",
"test3",
];
const [buckets, setBuckets] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
async function getAllBucket() {
getAllMinioBucket("1").then((res: any) => {
if (res && res.success) {
setBuckets(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getAllBucket().then();
}, []);
const bucketList = () => {
return (
<ProCard
title={"存储桶列表"}
title={"MinIO存储桶列表"}
headerBordered
extra={
<Button type="primary" onClick={() => setDrawerVisit(true)}>
</Button>
<>
<Button
type="default"
shape={"circle"}
style={{ marginRight: 20 }}
onClick={() => {
setLoading(false);
getAllBucket().then();
}}
icon={<ReloadOutlined />}></Button>
<Button type="primary" onClick={() => setDrawerVisit(true)}>
</Button>
</>
}>
<div className={styles.div_proCard}>
{list.map((item, index) => {
return (
<ProCard
headStyle={{ backgroundColor: "#f0f2f5" }}
hoverable
bordered
key={index}
title={<b>{item}</b>}
style={{
width: "180px",
borderWidth: "1px",
}}
actions={[
<SettingOutlined key="setting" />,
<EditOutlined key="edit" />,
<EllipsisOutlined key="ellipsis" />,
]}>
<Avatar shape={"square"} src={bucket} size={"large"} />
<b style={{ marginLeft: 10 }}> size</b>
</ProCard>
);
})}
<Skeleton loading={loading} paragraph={{ rows: 13 }} active>
{buckets &&
Array.from(buckets).map((item: any, index: number) => {
return (
<div key={index}>
<ProCard
headStyle={{ backgroundColor: "#f0f2f5" }}
hoverable
bordered
title={<b>{item.name}</b>}
style={{
width: "180px",
height: "150px",
marginLeft: 10,
}}
actions={[
<SettingOutlined key="setting" />,
<EditOutlined key="edit" />,
<EllipsisOutlined key="ellipsis" />,
]}>
<Avatar
shape={"square"}
src={bucket as any}
size={"large"}
/>
<b style={{ marginLeft: 10 }}>{item.size}</b>
</ProCard>
</div>
);
})}
</Skeleton>
</div>
</ProCard>
);

View File

@@ -1,16 +1,13 @@
/** @format */
import { Avatar, Button, message } from "antd";
import {
DrawerForm,
ProCard,
ProForm,
ProFormText,
} from "@ant-design/pro-components";
import React, { createContext, useContext, useState } from "react";
import { EditOutlined, EllipsisOutlined, SettingOutlined } from "@ant-design/icons";
import bucket from "../../../../assets/icons/bucket.svg";
import { Avatar, Button, message, Skeleton } from "antd";
import { DrawerForm, ProCard, ProForm, ProFormText } from "@ant-design/pro-components";
import React, { createContext, useContext, useEffect, useState } from "react";
import { EditOutlined, EllipsisOutlined, ReloadOutlined, SettingOutlined } from "@ant-design/icons";
import bucket from "@/assets/icons/bucket.svg";
import styles from "./index.module.less";
import { getAllMinioBucket } from "@/api/oss/minio";
import { getAllQiniuBucket } from "@/api/oss/qiniu";
const DrawerContext = createContext<{
drawerVisit: boolean;
@@ -26,24 +23,20 @@ const QingyunDrawer = () => {
};
const ProCardComponent = () => {
const { drawerVisit, setDrawerVisit } = useContext(DrawerContext);
const list = [
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test3",
"test1",
"test2",
"test3",
];
const [buckets, setBuckets] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
async function getAllBucket() {
getAllQiniuBucket("1").then((res: any) => {
if (res && res.success) {
setBuckets(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getAllBucket().then();
}, []);
const bucketList = () => {
return (
@@ -51,33 +44,53 @@ const ProCardComponent = () => {
title={"存储桶列表"}
headerBordered
extra={
<Button type="primary" onClick={() => setDrawerVisit(true)}>
</Button>
<>
<Button
type="default"
shape={"circle"}
style={{ marginRight: 20 }}
onClick={() => {
setLoading(false);
getAllBucket().then();
}}
icon={<ReloadOutlined />}></Button>
<Button type="primary" onClick={() => setDrawerVisit(true)}>
</Button>
</>
}>
<div className={styles.div_proCard}>
{list.map((item, index) => {
return (
<ProCard
headStyle={{ backgroundColor: "#f0f2f5" }}
hoverable
bordered
key={index}
title={<b>{item}</b>}
style={{
width: "180px",
borderWidth: "1px",
}}
actions={[
<SettingOutlined key="setting" />,
<EditOutlined key="edit" />,
<EllipsisOutlined key="ellipsis" />,
]}>
<Avatar shape={"square"} src={bucket} size={"large"} />
<b style={{ marginLeft: 10 }}> size</b>
</ProCard>
);
})}
<Skeleton loading={loading} paragraph={{ rows: 13 }} active>
{buckets &&
Array.from(buckets).map((item: any, index: number) => {
return (
<div key={index}>
<ProCard
headStyle={{ backgroundColor: "#f0f2f5" }}
hoverable
bordered
title={<b>{item.name}</b>}
style={{
width: "180px",
height: "150px",
marginLeft: 10,
}}
actions={[
<SettingOutlined key="setting" />,
<EditOutlined key="edit" />,
<EllipsisOutlined key="ellipsis" />,
]}>
<Avatar
shape={"square"}
src={bucket as any}
size={"large"}
/>
<b style={{ marginLeft: 10 }}>{item.size}</b>
</ProCard>
</div>
);
})}
</Skeleton>
</div>
</ProCard>
);

View File

@@ -1,16 +1,12 @@
/** @format */
import { Avatar, Button, message } from "antd";
import {
DrawerForm,
ProCard,
ProForm,
ProFormText,
} from "@ant-design/pro-components";
import React, { createContext, useContext, useState } from "react";
import { Avatar, Button, message, Skeleton } from "antd";
import { DrawerForm, ProCard, ProForm, ProFormText } from "@ant-design/pro-components";
import React, { createContext, useContext, useEffect, useState } from "react";
import { EditOutlined, EllipsisOutlined, SettingOutlined } from "@ant-design/icons";
import bucket from "../../../../assets/icons/bucket.svg";
import styles from "./index.module.less";
import { getAllTencentOSsBucket } from "@/api/oss/tencent";
const DrawerContext = createContext<{
drawerVisit: boolean;
@@ -26,29 +22,26 @@ const TencentDrawer = () => {
};
const ProCardComponent = () => {
const { drawerVisit, setDrawerVisit } = useContext(DrawerContext);
const list = [
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test3",
"test1",
"test2",
"test3",
];
const [buckets, setBuckets] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
async function getAllBucket() {
getAllTencentOSsBucket("1").then((res: any) => {
if (res && res.success) {
setBuckets(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getAllBucket().then();
}, []);
const bucketList = () => {
return (
<ProCard
title={"存储桶列表"}
title={"腾讯云COS存储桶列表"}
headerBordered
extra={
<Button type="primary" onClick={() => setDrawerVisit(true)}>
@@ -56,28 +49,37 @@ const ProCardComponent = () => {
</Button>
}>
<div className={styles.div_proCard}>
{list.map((item, index) => {
return (
<ProCard
headStyle={{ backgroundColor: "#f0f2f5" }}
hoverable
bordered
key={index}
title={<b>{item}</b>}
style={{
width: "180px",
borderWidth: "1px",
}}
actions={[
<SettingOutlined key="setting" />,
<EditOutlined key="edit" />,
<EllipsisOutlined key="ellipsis" />,
]}>
<Avatar shape={"square"} src={bucket} size={"large"} />
<b style={{ marginLeft: 10 }}> size</b>
</ProCard>
);
})}
<Skeleton loading={loading} paragraph={{ rows: 13 }} active>
{buckets &&
Array.from(buckets).map((item: any, index: number) => {
return (
<div key={index}>
<ProCard
headStyle={{ backgroundColor: "#f0f2f5" }}
hoverable
bordered
title={<b>{item.name}</b>}
style={{
width: "180px",
height: "150px",
marginLeft: 10,
}}
actions={[
<SettingOutlined key="setting" />,
<EditOutlined key="edit" />,
<EllipsisOutlined key="ellipsis" />,
]}>
<Avatar
shape={"square"}
src={bucket as any}
size={"large"}
/>
<b style={{ marginLeft: 10 }}>{item.size}</b>
</ProCard>
</div>
);
})}
</Skeleton>
</div>
</ProCard>
);

View File

@@ -1,11 +1,12 @@
/** @format */
import { Avatar, Button, message } from "antd";
import { Avatar, Button, message, Skeleton } from "antd";
import { DrawerForm, ProCard, ProForm, ProFormText } from "@ant-design/pro-components";
import React, { createContext, useContext, useState } from "react";
import { EditOutlined, EllipsisOutlined, SettingOutlined } from "@ant-design/icons";
import React, { createContext, useContext, useEffect, useState } from "react";
import { EditOutlined, EllipsisOutlined, ReloadOutlined, SettingOutlined } from "@ant-design/icons";
import bucket from "../../../../assets/icons/bucket.svg";
import styles from "./index.module.less";
import { getAllQiniuBucket } from "@/api/oss/qiniu";
const DrawerContext = createContext<{
drawerVisit: boolean;
@@ -21,24 +22,20 @@ const UpDrawer = () => {
};
const ProCardComponent = () => {
const { drawerVisit, setDrawerVisit } = useContext(DrawerContext);
const list = [
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test1",
"test2",
"test3",
"test3",
"test1",
"test2",
"test3",
];
const [buckets, setBuckets] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
async function getAllBucket() {
getAllQiniuBucket("1").then((res: any) => {
if (res && res.success) {
setBuckets(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getAllBucket().then();
}, []);
const bucketList = () => {
return (
@@ -46,33 +43,53 @@ const ProCardComponent = () => {
title={"存储桶列表"}
headerBordered
extra={
<Button type="primary" onClick={() => setDrawerVisit(true)}>
</Button>
<>
<Button
type="default"
shape={"circle"}
style={{ marginRight: 20 }}
onClick={() => {
setLoading(false);
getAllBucket().then();
}}
icon={<ReloadOutlined />}></Button>
<Button type="primary" onClick={() => setDrawerVisit(true)}>
</Button>
</>
}>
<div className={styles.div_proCard}>
{list.map((item, index) => {
return (
<ProCard
headStyle={{ backgroundColor: "#f0f2f5" }}
hoverable
bordered
key={index}
title={<b>{item}</b>}
style={{
width: "180px",
borderWidth: "1px",
}}
actions={[
<SettingOutlined key="setting" />,
<EditOutlined key="edit" />,
<EllipsisOutlined key="ellipsis" />,
]}>
<Avatar shape={"square"} src={bucket} size={"large"} />
<b style={{ marginLeft: 10 }}> size</b>
</ProCard>
);
})}
<Skeleton loading={loading} paragraph={{ rows: 13 }} active>
{buckets &&
Array.from(buckets).map((item: any, index: number) => {
return (
<div key={index}>
<ProCard
headStyle={{ backgroundColor: "#f0f2f5" }}
hoverable
bordered
title={<b>{item.name}</b>}
style={{
width: "180px",
height: "150px",
marginLeft: 10,
}}
actions={[
<SettingOutlined key="setting" />,
<EditOutlined key="edit" />,
<EllipsisOutlined key="ellipsis" />,
]}>
<Avatar
shape={"square"}
src={bucket as any}
size={"large"}
/>
<b style={{ marginLeft: 10 }}>{item.size}</b>
</ProCard>
</div>
);
})}
</Skeleton>
</div>
</ProCard>
);

View File

@@ -1,19 +1,12 @@
.div_proCard{
height: 62vh;
max-height: 62vh;
gap: 20px;
width: 105%;
width: 100%;
min-height: 62vh;
display: flex;
flex-wrap: wrap;
flex-direction: row;
overflow-y:scroll;
overflow-x: hidden;
justify-content: space-around;
justify-content: flex-start;
}
.proCard{
height: 75vh;
max-height: 75vh;
width: 105%;
}

View File

@@ -1,6 +1,6 @@
.proCard{
max-width: 30%;
min-height: 84vh;
}
.proCardBucket{
@@ -14,8 +14,6 @@
}
.div_checkCardArea{
height: 68vh;
max-height: 68vh;
overflow-y:scroll;
overflow-x: hidden;
}

View File

@@ -1,45 +1,66 @@
/** @format */
import { FunctionComponent, Suspense } from "react";
import { FunctionComponent, Suspense, useEffect, useState } from "react";
import { CheckCard, ProCard } from "@ant-design/pro-components";
import styles from "./index.module.less";
import { Outlet, useNavigate } from "react-router-dom";
import { Button, Empty } from "antd";
import { Button, Empty, Skeleton } from "antd";
import StorageIcon from "@/constant/stroage-icon.ts";
import { ReloadOutlined } from "@ant-design/icons";
import { getAllStorage } from "@/api/oss";
const Bucket: FunctionComponent = () => {
const navigate = useNavigate();
const checkList = ["minio", "ali", "tencent", "huawei", "baidu", "jd"];
const [userStorage, setUserStorage] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
async function getUserStorage() {
getAllStorage("1").then((res: any) => {
if (res && res.success) {
setUserStorage(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getUserStorage().then();
}, []);
return (
<div className={styles.div_proCard}>
<ProCard
extra={<Button type="primary" shape={"circle"} icon={<ReloadOutlined />}></Button>}
extra={
<Button
type="primary"
shape={"circle"}
onClick={() => {
getUserStorage().then();
}}
icon={<ReloadOutlined />}></Button>
}
title="存储商"
headerBordered
className={styles.proCard}
boxShadow={true}
colSpan={"100%"}
bordered>
<CheckCard.Group>
<div className={styles.div_checkCardArea}>
{checkList.map((item) => {
<Skeleton loading={loading} paragraph={{ rows: 14 }} active>
<CheckCard.Group style={{ width: "100%" }}>
{userStorage.map((item: any, index: number) => {
return (
<CheckCard
key={item}
avatar={StorageIcon[item]}
key={index}
avatar={StorageIcon[item.ossType]}
style={{ width: "100%" }}
title={item}
title={item.name}
description="点击查看"
value={item}
value={item.ossType}
onChange={() => {
navigate(`/main/bucket/${item}`);
navigate(`/main/bucket/${item.ossType}`);
}}
/>
);
})}
</div>
</CheckCard.Group>
</CheckCard.Group>
</Skeleton>
</ProCard>
<ProCard className={styles.proCardBucket} bordered boxShadow>
{location.pathname === "/main/bucket" || location.pathname === "/main/bucket/" ? (

View File

@@ -1,5 +1,5 @@
/** @format */
import { FunctionComponent, useEffect, useState } from "react";
import React, { FunctionComponent, useEffect, useState } from "react";
import { CheckCard, ProCard } from "@ant-design/pro-components";
import styles from "./index.module.less";
import {
@@ -8,6 +8,7 @@ import {
Card,
Divider,
Dropdown,
Empty,
Flex,
FloatButton,
Input,
@@ -16,9 +17,7 @@ import {
Select,
Tooltip,
} from "antd";
import ali from "@/assets/icons/aliyun.svg";
import bucket from "@/assets/icons/bucket.svg";
import tencent from "@/assets/icons/tencent.svg";
import {
CloudUploadOutlined,
CopyOutlined,
@@ -29,6 +28,7 @@ import {
LeftOutlined,
QrcodeOutlined,
RedoOutlined,
ReloadOutlined,
ScissorOutlined,
SearchOutlined,
SnippetsOutlined,
@@ -39,46 +39,8 @@ import { observer } from "mobx-react";
import FileIcon from "@/constant/file-icon.ts";
import file_icon from "@/assets/icons/files/file.svg";
import FileUpload from "@/components/Main/File/components/FileUpload.tsx";
const dataList: any = [
{
name: "demo01.java",
isDir: false,
path: "demo0.java",
length: "346",
createTime: "2024-06-26T08:22:13.244Z",
},
{
name: "测试.pdf",
isDir: false,
path: "测试.pdf",
length: "346",
createTime: "2024-06-26T08:22:13.244Z",
},
{
name: "test.jpg",
isDir: false,
path: "test.jpg",
length: "2057535",
createTime: "2024-06-27T02:27:05.472Z",
},
{
name: "test1.png",
isDir: false,
path: "test1.png",
length: "1766511",
createTime: "2024-06-29T10:28:03.224Z",
},
{
name: "schisandra",
isDir: true,
path: "schisandra/",
},
{
name: "测试文件夹",
isDir: true,
path: "测试文件夹/",
},
];
import { getAllStorage, getBucketFiles, getStorageBuckets } from "@/api/oss";
import StorageIcon from "@/constant/stroage-icon.ts";
const fileList: any = [
{
name: "test1.png",
@@ -98,148 +60,197 @@ const File: FunctionComponent = () => {
const store = useStore("file");
const [files, setFiles] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
const [bucketLoading, setBucketLoading] = useState<boolean>(true);
const [open, setOpen] = useState<boolean>(false);
async function getFile() {
setFiles(dataList);
const [userStorage, setUserStorage] = useState([]);
const [buckets, setBuckets] = useState<any[]>([]);
const [currentStorage, setCurrentStorage] = useState<any>(null);
const [currentBucket, setCurrentBucket] = useState<any>(null);
async function getUserStorage() {
getAllStorage("1").then((res: any) => {
if (res && res.success) {
setUserStorage(res.data);
setLoading(false);
}
});
}
async function getFiles(bucket: any, dirName: any, type: any) {
return getBucketFiles("1", bucket, dirName, type).then((res: any) => {
if (res && res.success) {
setFiles(res.data);
}
});
}
function getFileExtension(filename: any): string {
const dotIndex = filename.lastIndexOf(".");
return dotIndex !== -1 ? filename.slice(dotIndex + 1) : "";
}
async function getBuckets(type: any) {
getStorageBuckets("1", type).then((res: any) => {
if (res && res.success) {
setBuckets(res.data);
setBucketLoading(false);
}
});
}
useEffect(() => {
getFile().then();
setTimeout(() => {
setLoading(false);
}, 2000);
getUserStorage().then();
}, []);
return (
<>
<div className={styles.file_main}>
<div className={styles.file_content_left}>
<ProCard bordered boxShadow style={{ height: "83vh" }}>
<Select
size="large"
status="warning"
style={{
width: "100%",
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
showSearch={true}
allowClear={true}
notFoundContent={"未找到,请先配置存储商"}
placeholder={"请选择存储商"}>
<Select.Option value="ali">
<Card
bordered={false}
style={{
height: 35,
display: "flex",
alignItems: "center",
flexDirection: "row",
}}
size={"small"}>
<Avatar src={ali as any} size={"small"} />
<span style={{ marginLeft: "10px", fontWeight: "bolder" }}>
OSS
</span>
</Card>
</Select.Option>
<Select.Option value="腾讯">
<Card
style={{
height: 35,
display: "flex",
alignItems: "center",
flexDirection: "row",
}}
bordered={false}
size={"small"}>
<Avatar src={tencent as any} size={"small"} />{" "}
<span style={{ marginLeft: "10px", fontWeight: "bolder" }}>
COS
</span>
</Card>
</Select.Option>
</Select>
<ProCard bordered boxShadow style={{ minHeight: "83vh" }}>
<Flex vertical={false} align={"center"}>
<Select
size="large"
status="warning"
style={{
width: "100%",
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
showSearch={true}
allowClear={true}
onSelect={(value: any) => {
setCurrentStorage(value);
getBuckets(value).then();
}}
onClear={() => {
setCurrentStorage(null);
setBuckets([]);
}}
onChange={(value: any) => {
setCurrentStorage(value);
// getBuckets(value).then();
}}
notFoundContent={"未找到,请先配置存储商"}
placeholder={"请选择存储商"}>
{userStorage &&
userStorage.map((item: any, index: number) => {
return (
<>
<Select.Option value={item.ossType} key={index}>
<Card
key={item}
bordered={false}
style={{
height: 35,
display: "flex",
alignItems: "center",
flexDirection: "row",
}}
size={"small"}>
<Avatar
src={StorageIcon[item.ossType]}
size={"small"}
/>
<span
style={{
marginLeft: "10px",
fontWeight: "bolder",
}}>
{item.name}
</span>
</Card>
</Select.Option>
</>
);
})}
</Select>
<Button
type="default"
shape={"circle"}
style={{ marginLeft: 10 }}
onClick={() => {
if (currentStorage != null) {
getBuckets(currentStorage).then();
}
}}
icon={<ReloadOutlined />}></Button>
</Flex>
<Divider></Divider>
<div>
<CheckCard.Group
defaultValue="A"
size={"small"}
loading={bucketLoading}
onChange={(value: any) => {
store.clearAllFilePath();
store.setFilePath(`/${value}`);
setCurrentBucket(value);
console.log(value);
if (value !== undefined) {
getFiles(value, "", currentStorage).then();
}
}}
style={{ width: "100%" }}>
<CheckCard
style={{ width: "100%" }}
title="schisandra"
avatar={bucket as any}
description="100Mb"
value="schisandra"
extra={
<Dropdown
placement="top"
menu={{
onClick: ({ domEvent }) => {
domEvent.stopPropagation();
message.info("menu click");
},
items: [
{
label: "删除",
key: "1",
},
{
label: "编辑",
key: "2",
},
],
}}>
<EllipsisOutlined
style={{ fontSize: 22, color: "rgba(0,0,0,0.5)" }}
onClick={(e) => e.stopPropagation()}
/>
</Dropdown>
}
/>
<CheckCard
style={{ width: "100%" }}
title="schisandra2"
avatar={bucket as any}
description="100Mb"
value="schisandra2"
extra={
<Dropdown
placement="top"
menu={{
onClick: ({ domEvent }) => {
domEvent.stopPropagation();
message.info("menu click");
},
items: [
{
label: "删除",
key: "1",
},
{
label: "编辑",
key: "2",
},
],
}}>
<EllipsisOutlined
style={{ fontSize: 22, color: "rgba(0,0,0,0.5)" }}
onClick={(e) => e.stopPropagation()}
/>
</Dropdown>
}
/>
{buckets.length === 0 ? (
<>
<Empty description={"请选择存储商"} />
</>
) : (
<>
{buckets &&
Array.from(buckets).map((item: any, index: number) => {
return (
<>
<div key={index}>
<CheckCard
style={{ width: "100%" }}
title={item.name}
avatar={bucket as any}
description={item.size}
value={item.name}
extra={
<Dropdown
placement="top"
menu={{
onClick: ({
domEvent,
}) => {
domEvent.stopPropagation();
message.info(
"menu click",
);
},
items: [
{
label: "删除",
key: "1",
},
{
label: "查看",
key: "2",
},
],
}}>
<EllipsisOutlined
style={{
fontSize: 22,
color: "rgba(0,0,0,0.5)",
}}
onClick={(e) =>
e.stopPropagation()
}
/>
</Dropdown>
}
/>
</div>
</>
);
})}
</>
)}
</CheckCard.Group>
</div>
</ProCard>
</div>
<div className={styles.file_content_right}>
<ProCard bordered boxShadow style={{ height: "83vh" }}>
<ProCard bordered boxShadow style={{ minHeight: "83vh" }}>
<div className={styles.file_right_header}>
<Flex vertical={false} align={"center"} justify={"flex-start"}>
<Flex vertical={false} align={"center"}>
@@ -247,8 +258,13 @@ const File: FunctionComponent = () => {
shape="circle"
icon={<LeftOutlined />}
onClick={() => {
setFiles(dataList);
store.clearFilePath();
getFiles(
currentBucket,
store.getMiddlePath(),
currentStorage,
).then(() => {
store.clearFilePath();
});
}}
/>
<Button
@@ -348,8 +364,13 @@ const File: FunctionComponent = () => {
<div
style={{ marginLeft: 10 }}
onDoubleClick={() => {
store.setFilePath(file.name);
setFiles(fileList);
getFiles(
currentBucket,
`${file.name}/`,
currentStorage,
).then(() => {
store.setFilePath(file.name);
});
}}>
<CheckCard
size={"small"}

View File

@@ -31,3 +31,12 @@
margin-top: 30px;
}
.home_content_icon{
font-size: 20px;
color: lightgrey;
}
.home_content_icon:hover{
color: #ff6700;
}

View File

@@ -1,6 +1,6 @@
/** @format */
import React, { useEffect, useState } from "react";
import { Avatar, Card, Flex, Skeleton, Space, Tag } from "antd";
import React, { memo, useEffect, useState } from "react";
import { Avatar, Card, Flex, message, Skeleton, Space, Tag, Tooltip } from "antd";
import styles from "./index.module.less";
import ReactECharts from "echarts-for-react";
import { ProCard, ProList } from "@ant-design/pro-components";
@@ -8,49 +8,132 @@ import storage from "@/assets/icons/storage.svg";
import bucket from "@/assets/icons/bucket.svg";
import file from "@/assets/icons/file.svg";
import flux from "@/assets/icons/flux.svg";
import aliyun from "@/assets/icons/aliyun.svg";
// import * as echarts from "echarts/core";
import CalendarHeatmap from "react-calendar-heatmap";
import "react-calendar-heatmap/dist/styles.css";
import { Tiny } from "@ant-design/plots";
const defaultData = [
{
id: "1",
name: "语雀的天空",
image: aliyun,
desc: "我是一条测试的描述",
},
{
id: "2",
name: "Ant Design",
image: "https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg",
desc: "我是一条测试的描述",
},
{
id: "3",
name: "蚂蚁金服体验科技",
image: "https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg",
desc: "我是一条测试的描述",
},
{
id: "4",
name: "TechUI",
image: "https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg",
desc: "我是一条测试的描述",
},
];
import upload from "@/assets/icons/upload.svg";
import download from "@/assets/icons/download.svg";
import {
getStorageAndBuckets,
getUserDownloadFileDiagramPerMonth,
getUserFileCount,
getUserFileFlow,
getUserFileHeatMap, getUserRecentDownloadFile, getUserRecentPreviewFile, getUserRecentUploadFile,
getUserUploadFileDiagramPerMonth
} from "@/api/oss";
import { Link, useNavigate } from "react-router-dom";
import { EyeOutlined, InfoCircleOutlined } from "@ant-design/icons";
import FileIcon from "@/constant/file-icon.ts";
import file_icon from "@/assets/icons/files/file.svg";
type DataItem = (typeof defaultData)[number];
const MainHome: React.FC = () => {
const navigate = useNavigate();
const [loading, setLoading] = useState(true);
const [dataSource, setDataSource] = useState<DataItem[]>(defaultData);
const [loadingEChart, setLoadingEChart] = useState(true);
const [loadingHeatmap, setLoadingHeatmap] = useState(true);
const [loadingRecentFile, setLoadingRecentFile] = useState(true);
const [loadingPreviewFile, setLoadingPreviewFile] = useState(true);
const [storageCount, setStorageCount] = useState<any>(null);
const [bucketCount, setBucketCount] = useState<any>(null);
const [fileHeatmap, setFileHeatmap] = useState<any>([]);
const [downloadFlow, setDownloadFlow] = useState<any>(null);
const [uploadFlow, setUploadFlow] = useState<any>(null);
const [uploadFile, setUploadFile] = useState<any>(null);
const [downloadFile, setDownloadFile] = useState<any>(null);
const [monthUpload, setMonthUpload] = useState<any>([]);
const [monthDownload, setMonthDownload] = useState<any>([]);
const [recentUploadFile, setRecentUploadFile] = useState<any>([]);
const [recentDownloadFile, setRecentDownloadFile] = useState<any>([]);
const [recentPreviewFile, setRecentPreviewFile] = useState<any>([]);
// 获取存储同和存储商的个数
async function getStorageAndBucketsCount() {
return getStorageAndBuckets("1").then((res: any) => {
if (res && res.success && res.data) {
const from: any = Array.from(res.data);
setStorageCount(from.length);
const count = from.reduce(
(count: any, item: any) => (count += item.bucketCount),
0,
);
setBucketCount(count);
}
});
}
// 获取文件上传热力图
async function getFileHeatMap() {
return getUserFileHeatMap("1").then((res: any) => {
if (res && res.success && res.data) {
setFileHeatmap(res.data.upload);
}
});
}
// 获取文件上传下载流量
async function getUploadDownloadFlux() {
return getUserFileFlow("1").then((res: any) => {
if (res && res.success && res.data) {
setUploadFlow(res.data.uploadflow);
setDownloadFlow(res.data.downloadflow);
}
});
}
// 获取文件上传下载个数
async function getUploadDownloadCount() {
return getUserFileCount("1").then((res: any) => {
if (res && res.success && res.data) {
setUploadFile(res.data.upload);
setDownloadFile(res.data.download);
}
});
}
// 获取每月用户下载数量
async function getDownloadCountByMonth() {
getUserDownloadFileDiagramPerMonth(1).then((res: any) => {
if (res && res.success && res.data) {
setMonthDownload(res.data);
}
});
}
// 获取每月用户上传数量
async function getUploadCountByMonth() {
getUserUploadFileDiagramPerMonth(1).then((res: any) => {
if (res && res.success && res.data) {
setMonthUpload(res.data);
}
})
}
// 获取用户最近上传文件
async function getRecentUploadFile() {
getUserRecentUploadFile(1).then((res: any) => {
if (res && res.success && res.data) {
setRecentUploadFile(res.data);
}
})
}
//获取用户最近下载文件
async function getRecentDownloadFile() {
getUserRecentDownloadFile(1).then((res: any)=>{
if(res && res.success && res.data){
setRecentDownloadFile(res.data);
}
})
}
//获取用户最近预览文件
async function getRecentPreviewFile() {
getUserRecentPreviewFile(1).then((res:any)=>{
if(res && res.success && res.data){
setRecentPreviewFile(res.data);
}
})
}
const option = {
tooltip: {
trigger: "axis",
},
legend: {
color: ["#F58080", "#47D8BE", "#F9A589"],
data: ["文件", "流量", "存储桶"],
data: ["上传", "下载"],
left: "center",
bottom: "bottom",
},
@@ -62,15 +145,15 @@ const MainHome: React.FC = () => {
height: "80%",
containLabel: true,
},
xAxis: {
type: "category",
data: [100, 200, 20, 30, 60, 89],
xAxis: [{
type: "time",
// data: month,
axisLine: {
lineStyle: {
color: "#999",
},
},
},
}],
yAxis: {
type: "value",
@@ -95,9 +178,9 @@ const MainHome: React.FC = () => {
},
series: [
{
name: "文件",
name: "下载",
type: "line",
data: [800, 900, 220, 130, 660, 289],
data: monthDownload,
color: "#F58080",
lineStyle: {
width: 5,
@@ -134,9 +217,9 @@ const MainHome: React.FC = () => {
smooth: true,
},
{
name: "流量",
name: "上传",
type: "line",
data: [123, 568, 111, 222, 123, 56],
data: monthUpload,
lineStyle: {
width: 5,
color: {
@@ -171,67 +254,48 @@ const MainHome: React.FC = () => {
},
smooth: true,
},
{
name: "存储桶",
type: "line",
data: [125, 568, 25, 36, 784, 56],
lineStyle: {
width: 5,
color: {
type: "linear",
colorStops: [
{
offset: 0,
color: "#F6D06F", // 0% 处的颜色
},
{
offset: 0.4,
color: "#F9A589", // 100% 处的颜色
},
{
offset: 1,
color: "#F9A589", // 100% 处的颜色
},
],
globalCoord: false, // 缺省为 false
},
shadowColor: "rgba(249,165,137, 0.5)",
shadowBlur: 10,
shadowOffsetY: 7,
},
itemStyle: {
color: "#F6D06F",
borderWidth: 10,
/*shadowColor: 'rgba(72,216,191, 0.3)',
shadowBlur: 100,*/
borderColor: "#F6D06F",
},
smooth: true,
},
],
};
const data = [
264, 417, 438, 887, 309, 397, 550, 575, 563, 430, 525, 592, 492, 467, 513, 546,
].map((value, index) => ({ value, index }));
const config = {
data,
padding: 10,
width: 150,
height: 80,
shapeField: "smooth",
xField: "index",
yField: "value",
style: {
fill: "linear-gradient(-90deg, white 0%, orange 100%)",
fillOpacity: 0.6,
},
};
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 2000);
getStorageAndBucketsCount().then(()=>{
getUploadDownloadFlux().then(() => {
getUploadDownloadCount().then(() => {
setLoading(false);
});
});
});
}, []);
useEffect(() => {
getFileHeatMap().then(()=>{
setLoadingHeatmap(false);
});
}, []);
useEffect(() => {
getDownloadCountByMonth().then(()=>{
getUploadCountByMonth().then(()=>{
setLoadingEChart(false);
});
});
}, []);
useEffect(() => {
getRecentUploadFile().then(()=>{
setLoadingRecentFile(false);
});
getRecentPreviewFile().then(()=>{
setLoadingPreviewFile(false);
});
}, []);
function getFileExtension(filename: any): string {
const dotIndex = filename.lastIndexOf(".");
return dotIndex !== -1 ? filename.slice(dotIndex + 1) : "";
}
return (
<>
<div className={styles.home_content_main}>
@@ -272,18 +336,19 @@ const MainHome: React.FC = () => {
color: "coral",
fontWeight: "bolder",
}}>
{2}
{storageCount}
</span>
}
/
</span>
</Flex>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ width: "150px", height: "80px" }}>
<Tiny.Area {...config} />
<Flex vertical={false} align={"center"} justify={"flex-end"} style={{marginTop: 50}}>
<Tooltip title={"存储商个数,点击查看详情"} color={"#47D8BE"}>
<InfoCircleOutlined onClick={()=>{
navigate("/main/setting")
}} className={styles.home_content_icon}/>
</Tooltip>
</Flex>
</Flex>
</Skeleton>
@@ -323,18 +388,19 @@ const MainHome: React.FC = () => {
color: "lightblue",
fontWeight: "bolder",
}}>
{2}
{bucketCount}
</span>
}
/
</span>
</Flex>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ width: "10vw", height: "11vh" }}>
<Tiny.Area {...config} />
<Flex vertical={false} align={"center"} justify={"flex-end"} style={{marginTop: 50}}>
<Tooltip title={"存储桶个数,点击查看详情"} color={"#47D8BE"}>
<InfoCircleOutlined onClick={()=>{
navigate("/main/bucket")
}} className={styles.home_content_icon}/>
</Tooltip>
</Flex>
</Flex>
</Skeleton>
@@ -365,27 +431,40 @@ const MainHome: React.FC = () => {
</span>
</Flex>
</Flex>
<Flex vertical={true} style={{ marginLeft: 8, marginTop: 10 }}>
<Flex vertical={false} align={"center"}>
<span style={{ fontSize: 15 }}>
{
<span
style={{
fontSize: 30,
color: "orange",
fontWeight: "bolder",
}}>
{2}
</span>
}
/
<Avatar
src={upload as any}
shape={"square"}
size={"small"}>
{" "}
</Avatar>
<span
style={{
fontSize: 18,
color: "orange",
marginLeft: 5,
}}>
{uploadFile}
</span>
</Flex>
<Flex vertical={false} align={"center"}>
<Avatar
src={download as any}
shape={"square"}
size={"small"}>
{" "}
</Avatar>
<span
style={{
fontSize: 18,
color: "green",
marginLeft: 5,
}}>
{downloadFile}
</span>
</Flex>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ width: "10vw", height: "11vh" }}>
<Tiny.Area {...config} />
</Flex>
</Flex>
</Skeleton>
@@ -413,30 +492,43 @@ const MainHome: React.FC = () => {
fontWeight: "bolder",
}}>
{" "}
</span>
</Flex>
<Flex vertical={false} align={"center"}>
<span style={{ fontSize: 15 }}>
{
<span
style={{
fontSize: 30,
color: "lightgreen",
fontWeight: "bolder",
}}>
{2}
</span>
}
/M
</span>
</Flex>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ width: "10vw", height: "11vh" }}>
<Tiny.Area {...config} />
<Flex vertical={true} style={{ marginLeft: 8, marginTop: 10 }}>
<Flex vertical={false} align={"center"}>
<Avatar
src={upload as any}
shape={"square"}
size={"small"}>
{" "}
</Avatar>
<span
style={{
fontSize: 18,
color: "orange",
marginLeft: 5,
}}>
{uploadFlow}
</span>
</Flex>
<Flex vertical={false} align={"center"}>
<Avatar
src={download as any}
shape={"square"}
size={"small"}>
{" "}
</Avatar>
<span
style={{
fontSize: 18,
color: "green",
marginLeft: 5,
}}>
{downloadFlow}
</span>
</Flex>
</Flex>
</Flex>
</Skeleton>
@@ -445,7 +537,7 @@ const MainHome: React.FC = () => {
<div style={{ width: "55%" }}>
<ProCard bordered boxShadow>
<Skeleton
loading={loading}
loading={loadingEChart}
active
paragraph={{
rows: 7,
@@ -464,17 +556,37 @@ const MainHome: React.FC = () => {
}}
title={"文件上传热力图"}>
<Skeleton
loading={loading}
loading={loadingHeatmap}
active
paragraph={{
rows: 3,
}}>
<CalendarHeatmap
startDate={new Date("2024-01-01")}
endDate={new Date("2024-12-31")}
startDate={new Date(`${new Date().getFullYear()}-01-01`)}
endDate={new Date(`${new Date().getFullYear()}-12-31`)}
showMonthLabels={true}
horizontal={true}
showWeekdayLabels={false}
onClick={(value:any)=>{
if(value!==null) {
message.open({
content: (<>
<Flex vertical={true}>
<Flex vertical={false} align={"center"}>
{value.date}
</Flex>
<Flex vertical={false} align={"center"}>
{value.count}
</Flex>
</Flex>
</>),
type:"success",
duration: 2,
}).then();
}
}}
monthLabels={[
"一月",
"二月",
@@ -499,101 +611,107 @@ const MainHome: React.FC = () => {
"周六",
]}
gutterSize={3}
values={
[
{ date: "2024-01-02", count: 12 },
{ date: "2024-05-3", count: 122 },
{ date: "2024-06-30", count: 38 },
] as any
}></CalendarHeatmap>
values={fileHeatmap}></CalendarHeatmap>
</Skeleton>
</ProCard>
</div>
<div className={styles.home_content_list}>
<ProCard bordered boxShadow style={{ width: "49%" }}>
<Skeleton
loading={loading}
loading={loadingRecentFile}
active
paragraph={{
rows: 8,
}}>
<ProList<DataItem>
<ProList
rowKey="id"
headerTitle="最近上传文件"
dataSource={dataSource}
showActions="hover"
editable={{
onSave: async (key, record, originRow) => {
console.log(key, record, originRow);
return true;
},
}}
onDataSourceChange={setDataSource}
dataSource={recentUploadFile}
metas={{
title: {
dataIndex: "name",
dataIndex: "fileName",
},
avatar: {
dataIndex: "image",
editable: false,
render: (text: any,record: any) => {
if(record.fileName) {
return (<>
<Avatar
src={
FileIcon[getFileExtension(record.fileName)] || file_icon
}
shape={"square"}
size={"large"}
/>
</>)
}else {
return (<>
<Avatar
src={file_icon as any}
shape={"square"}
size={"large"}
/>
</>)
}
}
},
description: {
dataIndex: "desc",
},
subTitle: {
render: () => {
return (
<Space size={0}>
<Tag color="blue">Ant Design</Tag>
<Tag color="#5BD8A6">TechUI</Tag>
</Space>
);
},
dataIndex: "size",
valueType: "text"
},
content: {
dataIndex: "time"
}
}}
/>
</Skeleton>
</ProCard>
<ProCard bordered boxShadow style={{ width: "49%" }}>
<Skeleton
loading={loading}
loading={loadingPreviewFile}
active
paragraph={{
rows: 8,
}}>
<ProList<DataItem>
<ProList
rowKey="id"
headerTitle="最近浏览文件"
dataSource={dataSource}
showActions="hover"
editable={{
onSave: async (key, record, originRow) => {
console.log(key, record, originRow);
return true;
},
}}
onDataSourceChange={setDataSource}
dataSource={recentPreviewFile}
metas={{
title: {
dataIndex: "name",
dataIndex: "fileName",
},
avatar: {
dataIndex: "image",
editable: false,
render: (text: any,record: any) => {
if(record.fileName) {
return (<>
<Avatar
src={
FileIcon[getFileExtension(record.fileName)] || file_icon
}
shape={"square"}
size={"large"}
/>
</>)
}else {
return (<>
<Avatar
src={file_icon as any}
shape={"square"}
size={"large"}
/>
</>)
}
}
},
description: {
dataIndex: "desc",
},
subTitle: {
render: () => {
return (
<Space size={0}>
<Tag color="blue">Ant Design</Tag>
<Tag color="#5BD8A6">TechUI</Tag>
</Space>
);
},
dataIndex: "size",
valueType: "text",
},
content: {
dataIndex: "time"
}
}}
/>
</Skeleton>
@@ -603,4 +721,4 @@ const MainHome: React.FC = () => {
</>
);
};
export default MainHome;
export default memo(MainHome);

View File

@@ -3,7 +3,8 @@ import { PlusOutlined } from "@ant-design/icons";
import type { ActionType, ProColumns } from "@ant-design/pro-components";
import { ProTable, TableDropdown } from "@ant-design/pro-components";
import { Button, Col, Drawer, Form, Input, Row, Space } from "antd";
import React, { useRef, useState } from "react";
import React, { useEffect, useRef, useState } from "react";
import { getAllAliOSSConfig } from "@/api/oss/ali";
type AliOssConfigItem = {
id: number;
@@ -12,21 +13,9 @@ type AliOssConfigItem = {
accessKeyId: string;
accessKeySecret: string;
createdTime: string;
updatedTime: string;
updateTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
endpoint: "https://oss.aliyuncs.com",
accessKeyId: "LTAI5tG3",
accessKeySecret: "G3",
createdTime: "2024-06-28 10:51:59",
updatedTime: "2024-06-29 10:51:59",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
@@ -47,6 +36,7 @@ const columns: ProColumns<AliOssConfigItem>[] = [
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
copyable: true,
},
{
disable: true,
@@ -54,6 +44,7 @@ const columns: ProColumns<AliOssConfigItem>[] = [
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
copyable: true,
},
{
disable: true,
@@ -61,12 +52,7 @@ const columns: ProColumns<AliOssConfigItem>[] = [
dataIndex: "accessKeySecret",
tooltip: "access key secret",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
copyable: true,
},
{
title: "创建时间",
@@ -76,10 +62,16 @@ const columns: ProColumns<AliOssConfigItem>[] = [
},
{
title: "更新时间",
dataIndex: "updatedTime",
dataIndex: "updateTime",
valueType: "dateTime",
sorter: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "操作",
valueType: "option",
@@ -112,13 +104,25 @@ const columns: ProColumns<AliOssConfigItem>[] = [
const AliSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const [configs, setConfigs] = useState<AliOssConfigItem[]>([]);
async function getAllConfig() {
getAllAliOSSConfig(1).then((res) => {
console.log(res);
if (res && res.success && res.data) {
setConfigs(res.data);
}
});
}
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
useEffect(() => {
getAllConfig();
}, []);
const AddAliOssConfigDrawer = () => {
return (
<>
@@ -179,7 +183,7 @@ const AliSettings: React.FC = () => {
<div style={{ height: "65vh" }}>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
dataSource={configs}
actionRef={actionRef}
cardBordered={true}
editable={{

View File

@@ -3,7 +3,8 @@ import { PlusOutlined } from "@ant-design/icons";
import type { ActionType, ProColumns } from "@ant-design/pro-components";
import { ProTable, TableDropdown } from "@ant-design/pro-components";
import { Button, Col, Drawer, Form, Input, Row, Space } from "antd";
import React, { ReactNode, useRef, useState } from "react";
import React, { ReactNode, useEffect, useRef, useState } from "react";
import { getAllMinioConfig } from "@/api/oss/minio";
type MinioOssConfigItem = {
id: number;
@@ -12,21 +13,9 @@ type MinioOssConfigItem = {
accessKey: string;
secretKey: string;
createdTime: string;
updatedTime: string;
updateTime: string;
status: string;
};
const data: MinioOssConfigItem[] = [
{
id: 1,
userId: 1,
endpoint: "https://oss.aliyuncs.com",
accessKey: "LTAI5tG3",
secretKey: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<MinioOssConfigItem>[] = [
{
@@ -46,6 +35,7 @@ const columns: ProColumns<MinioOssConfigItem>[] = [
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
copyable: true,
ellipsis: true,
},
{
@@ -54,6 +44,7 @@ const columns: ProColumns<MinioOssConfigItem>[] = [
dataIndex: "accessKey",
tooltip: "access key",
ellipsis: true,
copyable: true,
},
{
disable: true,
@@ -61,6 +52,7 @@ const columns: ProColumns<MinioOssConfigItem>[] = [
dataIndex: "secretKey",
tooltip: "secret key",
ellipsis: true,
copyable: true,
},
{
disable: true,
@@ -77,7 +69,7 @@ const columns: ProColumns<MinioOssConfigItem>[] = [
},
{
title: "更新时间",
dataIndex: "updatedTime",
dataIndex: "updateTime",
valueType: "dateTime",
sorter: true,
},
@@ -113,6 +105,7 @@ const columns: ProColumns<MinioOssConfigItem>[] = [
const MinioSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const [configs, setConfigs] = useState<MinioOssConfigItem[]>([]);
const showDrawer = () => {
setOpen(true);
};
@@ -120,6 +113,18 @@ const MinioSettings: React.FC = () => {
const onClose = () => {
setOpen(false);
};
async function getAllConfig() {
getAllMinioConfig(1).then((res: any) => {
if (res && res.success && res.data) {
setConfigs(res.data);
}
});
}
useEffect(() => {
getAllConfig().then();
}, []);
const AddMinioOssConfigDrawer = () => {
return (
<>
@@ -180,7 +185,7 @@ const MinioSettings: React.FC = () => {
<div style={{ height: "65vh" }}>
<ProTable<MinioOssConfigItem>
columns={columns}
dataSource={data}
dataSource={configs}
actionRef={actionRef}
cardBordered={true}
editable={{

View File

@@ -3,7 +3,8 @@ import { PlusOutlined } from "@ant-design/icons";
import type { ActionType, ProColumns } from "@ant-design/pro-components";
import { ProTable, TableDropdown } from "@ant-design/pro-components";
import { Button, Col, Drawer, Form, Input, Row, Space } from "antd";
import React, { ReactNode, useRef, useState } from "react";
import React, { ReactNode, useEffect, useRef, useState } from "react";
import { getAllQiniuConfigs } from "@/api/oss/qiniu";
type QiniuOssConfigItem = {
id: number;
@@ -12,21 +13,9 @@ type QiniuOssConfigItem = {
accessKey: string;
secretKey: string;
createdTime: string;
updatedTime: string;
updateTime: string;
status: string;
};
const data: QiniuOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "https://oss.aliyuncs.com",
accessKey: "LTAI5tG3",
secretKey: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<QiniuOssConfigItem>[] = [
{
@@ -46,20 +35,23 @@ const columns: ProColumns<QiniuOssConfigItem>[] = [
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
copyable: true,
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
dataIndex: "accessKey",
tooltip: "access key id",
copyable: true,
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessKeySecret",
dataIndex: "secretKey",
tooltip: "access key secret",
copyable: true,
ellipsis: true,
},
{
@@ -77,7 +69,7 @@ const columns: ProColumns<QiniuOssConfigItem>[] = [
},
{
title: "更新时间",
dataIndex: "updatedTime",
dataIndex: "updateTime",
valueType: "dateTime",
sorter: true,
},
@@ -113,6 +105,7 @@ const columns: ProColumns<QiniuOssConfigItem>[] = [
const QiniuSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const [config, setConfig] = useState<QiniuOssConfigItem[]>([]);
const showDrawer = () => {
setOpen(true);
};
@@ -120,6 +113,17 @@ const QiniuSettings: React.FC = () => {
const onClose = () => {
setOpen(false);
};
async function getAllCOnfigs() {
getAllQiniuConfigs(1).then((res: any) => {
if (res && res.success && res.data) {
setConfig(res.data);
}
});
}
useEffect(() => {
getAllCOnfigs().then();
}, []);
const AddQiniuOssConfigDrawer = () => {
return (
<>
@@ -180,7 +184,7 @@ const QiniuSettings: React.FC = () => {
<div style={{ height: "65vh" }}>
<ProTable<QiniuOssConfigItem>
columns={columns}
dataSource={data}
dataSource={config}
actionRef={actionRef}
cardBordered={true}
editable={{

View File

@@ -3,30 +3,18 @@ import { PlusOutlined } from "@ant-design/icons";
import type { ActionType, ProColumns } from "@ant-design/pro-components";
import { ProTable, TableDropdown } from "@ant-design/pro-components";
import { Button, Col, Drawer, Form, Input, Row, Space } from "antd";
import React, { ReactNode, useRef, useState } from "react";
import React, { ReactNode, useEffect, useRef, useState } from "react";
import { getAllTencentOSsConfig } from "@/api/oss/tencent";
type TencentOssConfigItem = {
id: number;
userId: number;
bucketName: string;
secretId: string;
secretKey: string;
createdTime: string;
updatedTime: string;
updateTime: string;
status: string;
};
const data: TencentOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "https://oss.aliyuncs.com",
secretId: "LTAI5tG3",
secretKey: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<TencentOssConfigItem>[] = [
{
@@ -41,17 +29,11 @@ const columns: ProColumns<TencentOssConfigItem>[] = [
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "secretId",
copyable: true,
tooltip: "secret Id",
ellipsis: true,
},
@@ -60,6 +42,7 @@ const columns: ProColumns<TencentOssConfigItem>[] = [
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secret Key",
copyable: true,
ellipsis: true,
},
{
@@ -77,7 +60,7 @@ const columns: ProColumns<TencentOssConfigItem>[] = [
},
{
title: "更新时间",
dataIndex: "updatedTime",
dataIndex: "updateTime",
valueType: "dateTime",
sorter: true,
},
@@ -113,6 +96,7 @@ const columns: ProColumns<TencentOssConfigItem>[] = [
const TencentSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const [configs, setConfigs] = useState<TencentOssConfigItem[]>([]);
const showDrawer = () => {
setOpen(true);
};
@@ -120,6 +104,17 @@ const TencentSettings: React.FC = () => {
const onClose = () => {
setOpen(false);
};
async function getAllConfigs() {
getAllTencentOSsConfig(5).then((res: any) => {
if (res && res.success && res.data) {
setConfigs(res.data);
}
});
}
useEffect(() => {
getAllConfigs().then();
}, []);
const AddTencentOssConfigDrawer = () => {
return (
<>
@@ -170,7 +165,7 @@ const TencentSettings: React.FC = () => {
<div style={{ height: "65vh" }}>
<ProTable<TencentOssConfigItem>
columns={columns}
dataSource={data}
dataSource={configs}
actionRef={actionRef}
cardBordered={true}
editable={{

View File

@@ -8,53 +8,53 @@ const selectOptions = [
name: "腾讯云COS",
value: "tencent",
},
{
name: "华为云OBS",
value: "huawei",
},
{
name: "百度云BOS",
value: "baidu",
},
// {
// name: "华为云OBS",
// value: "huawei",
// },
// {
// name: "百度云BOS",
// value: "baidu",
// },
{
name: "MinIO",
value: "minio",
},
{
name: "京东云OSS",
value: "jd",
},
{
name: "亚马逊S3",
value: "aws",
},
{
name: "网易数帆NOS",
value: "wangyi",
},
// {
// name: "京东云OSS",
// value: "jd",
// },
// {
// name: "亚马逊S3",
// value: "aws",
// },
// {
// name: "网易数帆NOS",
// value: "wangyi",
// },
{
name: "七牛云Kodo",
value: "qiniu",
},
{
name: "又拍云USS",
value: "up",
},
{
name: "平安云OSS",
value: "pinan",
},
{
name: "青云QingCloud",
value: "qingyun",
},
{
name: "UCloud US3",
value: "ucloud",
},
{
name: "金山云OBS",
value: "jinshan",
},
// {
// name: "又拍云USS",
// value: "up",
// },
// {
// name: "平安云OSS",
// value: "pinan",
// },
// {
// name: "青云QingCloud",
// value: "qingyun",
// },
// {
// name: "UCloud US3",
// value: "ucloud",
// },
// {
// name: "金山云OBS",
// value: "jinshan",
// },
];
export default selectOptions;

View File

@@ -29,6 +29,15 @@ const ShareAdd: React.FunctionComponent = () => {
enable: true,
items: ["ai", "Bold", "Italic", "Underline", "Strike", "code", "comment"],
},
ai: {
models: {
wenxin: {
access_token: "****",
protocol: "ws",
version: "v3.5",
},
},
},
onChange: async (value: any) => {
fromRef.current.setFieldsValue({
content: value.getHtml(),

View File

@@ -128,7 +128,7 @@ export default () => {
vertical={false}
align={"center"}
justify={"space-between"}
style={{ width: "25%" }}>
style={{ width: "300px" }}>
<Flex vertical={false} align={"center"}>
<Avatar
src={logo as any}

View File

@@ -13,9 +13,6 @@ import Meta from "antd/es/card/Meta";
const MainShare: FunctionComponent = () => {
const navigate = useNavigate();
const [open, setOpen] = useState(false);
// const showDrawer = () => {
// setOpen(true);
// };
const onClose = () => {
setOpen(false);

View File

@@ -1,125 +1,163 @@
/** @format */
import { FunctionComponent, useEffect, useState } from "react";
import { Avatar, Card, Empty, List, Skeleton } from "antd";
import {
AntDesignOutlined,
BankOutlined,
BulbOutlined,
EnvironmentOutlined,
} from "@ant-design/icons";
import styles from "./index.module.less";
import { ProCard } from "@ant-design/pro-components";
import Meta from "antd/es/card/Meta";
import gitee from "@/assets/icons/gitee.svg";
import { Link } from "react-router-dom";
const UserInfo: FunctionComponent = () => {
const [loading, setLoading] = useState(true);
const data = [
{
title: "Ant Design Title 1",
},
{
title: "Ant Design Title 2",
},
{
title: "Ant Design Title 3",
},
{
title: "Ant Design Title 4",
},
];
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 2000);
}, []);
return (
<>
<div className={styles.user_info_header}>
<div className={styles.user_info_header_avatar}>
<Avatar
size={{ xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 }}
icon={<AntDesignOutlined />}
/>
<span className={styles.user_info_header_name}></span>
<div className={styles.user_info_header_desc}>
<div>
<BulbOutlined />
</div>
<div>
<EnvironmentOutlined />
</div>
<div>
<BankOutlined />
</div>
</div>
</div>
</div>
<div className={styles.user_info_center_content}>
<ProCard
bordered
style={{ maxWidth: "64%" }}
title="我的存储商"
boxShadow
extra={<Link to={"#"}></Link>}>
<Skeleton loading={loading} active>
<Card style={{ width: 300, marginTop: 16 }} hoverable={true}>
<Meta
avatar={<Avatar src={gitee} />}
title="Card title"
description="This is the description"
/>
</Card>
</Skeleton>
</ProCard>
<ProCard bordered style={{ maxWidth: "34%" }} title="我的存储桶" boxShadow>
<Skeleton loading={loading} active>
<Card style={{ width: 300, marginTop: 16 }} hoverable={true}>
<Meta
avatar={
<Avatar src="https://api.dicebear.com/7.x/miniavs/svg?seed=1" />
}
title="Card title"
description="This is the description"
/>
</Card>
</Skeleton>
</ProCard>
</div>
<div className={styles.user_info_bottom_content}>
<ProCard
bordered
style={{ maxWidth: "64%" }}
title="最近动态"
boxShadow
extra={<Link to={"#"}></Link>}>
<Skeleton loading={loading} active avatar>
<List
itemLayout="horizontal"
dataSource={data}
renderItem={(item, index) => (
<List.Item>
<List.Item.Meta
avatar={
<Avatar
src={`https://api.dicebear.com/7.x/miniavs/svg?seed=${index}`}
/>
}
title={<a href="https://ant.design">{item.title}</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
</List.Item>
)}
/>
</Skeleton>
</ProCard>
<ProCard bordered style={{ maxWidth: "34%" }} title="站内通知" boxShadow>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE}></Empty>
</ProCard>
</div>
</>
);
};
export default UserInfo;
/** @format */
import { FunctionComponent, useEffect, useState } from "react";
import { Avatar, Card, Empty, Flex, List, Skeleton } from "antd";
import {
AntDesignOutlined,
BankOutlined,
BulbOutlined,
EnvironmentOutlined,
} from "@ant-design/icons";
import styles from "./index.module.less";
import { ProCard } from "@ant-design/pro-components";
import Meta from "antd/es/card/Meta";
import gitee from "@/assets/icons/gitee.svg";
import { Link, useNavigate } from "react-router-dom";
import { getAllStorage } from "@/api/oss";
import StorageIcon from "@/constant/stroage-icon.ts";
import { getUserInfoApi } from "@/api/user";
const UserInfo: FunctionComponent = () => {
const navigate = useNavigate();
const [loading, setLoading] = useState(true);
const [userStorage, setUserStorage] = useState([]);
const [userInfo, setUserInfo] = useState<any>({} as any);
const data = [
{
title: "Ant Design Title 1",
},
{
title: "Ant Design Title 2",
},
{
title: "Ant Design Title 3",
},
{
title: "Ant Design Title 4",
},
];
async function getUserStorage() {
const res = await getAllStorage("1");
if (res.success) {
setUserStorage(res.data);
setLoading(false);
}
}
const getUserInfo = async () => {
const res = await getUserInfoApi("9");
if (res.success) {
setUserInfo(res.data);
}
};
useEffect(() => {
getUserInfo().then();
getUserStorage().then();
}, []);
return (
<>
<div className={styles.user_info_header}>
<div className={styles.user_info_header_avatar}>
<Avatar
size={{ xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 }}
icon={<AntDesignOutlined />}
/>
<span className={styles.user_info_header_name}></span>
<div className={styles.user_info_header_desc}>
<div>
<BulbOutlined />
</div>
<div>
<EnvironmentOutlined />
</div>
<div>
<BankOutlined />
</div>
</div>
</div>
</div>
<div className={styles.user_info_center_content}>
<ProCard
bordered
style={{ maxWidth: "64%" }}
title="我的存储商"
boxShadow
extra={<Link to={"/main/setting"}></Link>}>
<Flex vertical={false} align={"center"} justify={"space-between"} wrap={true}>
<Skeleton loading={loading} active>
{userStorage.map((item: any, index: number) => {
return (
<>
<Card
key={index}
onClick={() => {
navigate(`/main/setting/${item.ossType}`);
}}
style={{ width: 350, marginTop: 16, marginLeft: 10 }}
hoverable={true}>
<Meta
avatar={<Avatar src={StorageIcon[item.ossType]} />}
title={item.name}
description={
<>
<span> {item.configCount}</span>
<span style={{ marginLeft: 10 }}>
{item.bucketCount}
</span>
</>
}></Meta>
</Card>
</>
);
})}
</Skeleton>
</Flex>
</ProCard>
<ProCard bordered style={{ maxWidth: "34%" }} title="我的存储桶" boxShadow>
<Skeleton loading={loading} active>
<Card style={{ width: 300, marginTop: 16 }} hoverable={true}>
<Meta
avatar={
<Avatar src="https://api.dicebear.com/7.x/miniavs/svg?seed=1" />
}
title="Card title"
description="This is the description"
/>
</Card>
</Skeleton>
</ProCard>
</div>
<div className={styles.user_info_bottom_content}>
<ProCard
bordered
style={{ maxWidth: "64%" }}
title="最近动态"
boxShadow
extra={<Link to={"#"}></Link>}>
<Skeleton loading={loading} active avatar>
<List
itemLayout="horizontal"
dataSource={data}
renderItem={(item, index) => (
<List.Item>
<List.Item.Meta
avatar={
<Avatar
src={`https://api.dicebear.com/7.x/miniavs/svg?seed=${index}`}
/>
}
title={<a href="https://ant.design">{item.title}</a>}
description="Ant Design, a design language for background applications, is refined by Ant UED Team"
/>
</List.Item>
)}
/>
</Skeleton>
</ProCard>
<ProCard bordered style={{ maxWidth: "34%" }} title="站内通知" boxShadow>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE}></Empty>
</ProCard>
</div>
</>
);
};
export default UserInfo;

View File

@@ -5,7 +5,7 @@ import { isHydrated, makePersistable } from "mobx-persist-store";
import { handleLocalforage } from "@/utils/localforage";
export class useFileStore {
filePath: [any] = ["/root"];
filePath: [any] = [];
constructor() {
makeObservable(this, {
@@ -14,6 +14,8 @@ export class useFileStore {
getFilePath: action,
clearFilePath: action,
getFilePathSecondLast: action,
getMiddlePath: action,
clearAllFilePath: action,
isHydrated: action,
});
makePersistable(
@@ -54,10 +56,21 @@ export class useFileStore {
}
this.filePath.pop();
}
// 清空所有文件路径
clearAllFilePath() {
this.filePath.splice(0);
}
// 获取文件路径倒数第二个
getFilePathSecondLast() {
return this.filePath.slice(0, -1).pop();
}
// 获取文件路径中间路径
getMiddlePath() {
if (this.filePath.length <= 2) {
return " ";
}
return this.filePath.slice(1, this.filePath.length - 1).join("/");
}
isHydrated() {
return isHydrated(this);

View File

@@ -6,7 +6,13 @@ import {
LogoutOutlined,
QuestionCircleFilled,
} from "@ant-design/icons";
import { DefaultFooter, PageContainer, ProCard, ProLayout } from "@ant-design/pro-components";
import {
DefaultFooter,
PageContainer,
ProCard,
ProLayout,
SettingDrawer,
} from "@ant-design/pro-components";
import { Link, Outlet, useLocation } from "react-router-dom";
import logo from "@/assets/images/logo.png";
import { Suspense } from "react";