19 Commits
dev ... master

Author SHA1 Message Date
landaiqing
79f951bac8 feat: 去掉多余import 2024-07-24 01:01:38 +08:00
landaiqing
190fda426c fix: bug修复 2024-07-24 00:59:28 +08:00
landaiqing
8fa1c50fb3 feat: update 2024-07-23 11:00:17 +08:00
landaiqing
757f494f1f feat: update 2024-07-23 10:17:28 +08:00
landaiqing
c218006dd9 fix: bug修复 2024-07-23 09:44:11 +08:00
landaiqing
8e10d4a253 fix: bug修复 2024-07-22 22:44:09 +08:00
landaiqing
ac41e00105 feat: update 2024-07-22 09:04:46 +08:00
landaiqing
3dacedf7fd feat: 更新我的分享页面 2024-07-20 16:54:08 +08:00
landaiqing
6e8b2ae643 feat: 评论接口对接 2024-07-19 18:58:47 +08:00
landaiqing
359ef60128 feat: 首页仪表盘接口对接完成 2024-07-17 00:12:32 +08:00
landaiqing
d63b76b639 feat: 评论界面 2024-07-13 10:44:31 +08:00
landaiqing
4a3809e959 feat: 修复打包报错问题 2024-07-13 00:06:43 +08:00
landaiqing
6ec4a92853 feat: 界面调整 2024-07-12 23:46:40 +08:00
landaiqing
8677b975db feat: update 2024-07-12 11:33:41 +08:00
landaiqing
59cd675028 feat: 首页仪表盘调整 2024-07-12 10:48:43 +08:00
landaiqing
e79b193b27 feat: 更新依赖包版本 2024-07-11 17:34:27 +08:00
landaiqing
36625c10c6 feat: 添加我的分享页面 2024-07-11 16:43:56 +08:00
landaiqing
b7a16c3c59 feat: 文件分享update 2024-07-11 14:56:57 +08:00
landaiqing
32dff4adbb feat: update 2024-07-10 15:54:41 +08:00
104 changed files with 17956 additions and 9584 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:5050'
# the websocket url
VITE_WEB_SOCKET_URL='ws://127.0.0.1:3010/wx/socket'

View File

@@ -1,18 +1,18 @@
# 生产环境配置
VITE_NODE_ENV='production'
# 生产环境
VITE_APP_BASE_API='/api'
# 页面 title 前缀
VITE_APP_TITLE=生产环境
# 网络请求公用地址
VITE_API_BASE_URL='http://1.95.0.111:3000'
VITE_TITLE_NAME='五味子云存储'
# token key
VITE_APP_TOKEN_KEY='schisandra'
# the upload url
VITE_UPLOAD_URL='http://1.95.0.111:3000'
# 生产环境配置
VITE_NODE_ENV='production'
# 生产环境
VITE_APP_BASE_API='/api'
# 页面 title 前缀
VITE_APP_TITLE=生产环境
# 网络请求公用地址
VITE_API_BASE_URL='http://1.95.0.111:5050'
VITE_TITLE_NAME='五味子云存储'
# token key
VITE_APP_TOKEN_KEY='schisandra'
# the upload url
VITE_UPLOAD_URL='http://1.95.0.111:5050'

View File

@@ -1,3 +1,3 @@
node_modules
.eslintrc.cjs
dist
node_modules
.eslintrc.cjs
dist

View File

@@ -1,56 +1,56 @@
module.exports = {
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:prettier/recommended"
],
"overrides": [
{
"env": {
"node": true
},
"files": [
".eslintrc.{js,cjs}"
],
"parserOptions": {
"sourceType": "script"
}
}
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"react",
"prettier"
],
"rules": {
"react/jsx-use-react": 0, // React V17开始JSX已经不再需要引入React
"react/react-in-jsx-scope": 0, // 同上
"import/first": 0, // 消除绝对路径必须要在相对路径前引入,
// 'no-mixed-spaces-and-tabs': 2, // 禁止空格和 tab 的混合缩进
"no-debugger": 2, // 禁止有debugger
"space-infix-ops": 2, // 要求操作符周围有空格
"space-before-blocks": 2, // 要求语句块之前有空格
"@typescript-eslint/explicit-function-return-type": 0, // 禁止函数必须要定义返回类型
"react/display-name": "off",
"@typescript-eslint/no-explicit-any": ["off"],
"@typescript-eslint/no-var-requires": ["off"],
"@typescript-eslint/no-use-before-define": ["off"],
"@typescript-eslint/no-empty-function": ["off"],
"@typescript-eslint/no-empty-interface": ["off"],
"@typescript-eslint/no-unused-vars": ["off"],
"@typescript-eslint/no-non-null-assertion": ["off"],
"no-control-regex": "off",
"no-eval": 0
}
};
module.exports = {
"env": {
"browser": true,
"es2021": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:prettier/recommended"
],
"overrides": [
{
"env": {
"node": true
},
"files": [
".eslintrc.{js,cjs}"
],
"parserOptions": {
"sourceType": "script"
}
}
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": [
"@typescript-eslint",
"react",
"prettier"
],
"rules": {
"react/jsx-use-react": 0, // React V17开始JSX已经不再需要引入React
"react/react-in-jsx-scope": 0, // 同上
"import/first": 0, // 消除绝对路径必须要在相对路径前引入,
// 'no-mixed-spaces-and-tabs': 2, // 禁止空格和 tab 的混合缩进
"no-debugger": 2, // 禁止有debugger
"space-infix-ops": 2, // 要求操作符周围有空格
"space-before-blocks": 2, // 要求语句块之前有空格
"@typescript-eslint/explicit-function-return-type": 0, // 禁止函数必须要定义返回类型
"react/display-name": "off",
"@typescript-eslint/no-explicit-any": ["off"],
"@typescript-eslint/no-var-requires": ["off"],
"@typescript-eslint/no-use-before-define": ["off"],
"@typescript-eslint/no-empty-function": ["off"],
"@typescript-eslint/no-empty-interface": ["off"],
"@typescript-eslint/no-unused-vars": ["off"],
"@typescript-eslint/no-non-null-assertion": ["off"],
"no-control-regex": "off",
"no-eval": 0
}
};

View File

@@ -10,29 +10,34 @@
"preview": "vite preview"
},
"dependencies": {
"@ant-design/charts": "^2.1.1",
"@ant-design/icons": "^5.3.7",
"@ant-design/pro-components": "^2.7.9",
"@ant-design/pro-components": "^2.7.10",
"@ant-design/pro-provider": "^2.14.7",
"@ant-design/use-emotion-css": "^1.0.4",
"@babel/preset-env": "^7.24.6",
"@babel/preset-env": "^7.24.7",
"@types/crypto-js": "^4.2.2",
"@types/react-calendar-heatmap": "^1.6.7",
"@vitejs/plugin-legacy": "^5.4.0",
"antd": "^5.17.4",
"@vitejs/plugin-legacy": "^5.4.1",
"aieditor": "^1.0.12",
"antd": "^5.19.1",
"autoprefixer": "^10.4.19",
"axios": "^1.7.2",
"base-64": "^1.0.0",
"core-js": "^3.37.1",
"crypto-js": "^4.2.0",
"echarts-for-react": "^3.0.2",
"jsencrypt": "^3.3.2",
"localforage": "^1.10.0",
"mobx": "^6.12.3",
"mobx": "^6.13.0",
"mobx-persist-store": "^1.1.5",
"mobx-react": "^9.1.1",
"react": "^18.3.1",
"react-calendar-heatmap": "^1.9.0",
"react-dom": "^18.3.1",
"react-infinite-scroll-component": "^6.1.0",
"react-rotate-captcha": "^1.0.26",
"react-router-dom": "^6.23.1",
"react-router-dom": "^6.24.1",
"regenerator-runtime": "^0.14.1",
"timer-manager-lib": "^1.0.2",
"vite-plugin-compression": "^0.5.1",
@@ -40,28 +45,28 @@
},
"devDependencies": {
"@rollup/plugin-babel": "^6.0.4",
"@types/node": "^20.12.12",
"@types/node": "^20.14.10",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.11.0",
"@typescript-eslint/parser": "^7.11.0",
"@vitejs/plugin-react": "^4.3.0",
"@typescript-eslint/eslint-plugin": "^7.16.0",
"@typescript-eslint/parser": "^7.16.0",
"@vitejs/plugin-react": "^4.3.1",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react": "^7.34.3",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7",
"eslint-plugin-react-refresh": "^0.4.8",
"less": "^4.2.0",
"postcss-less": "^6.0.0",
"postcss-preset-env": "^9.5.14",
"prettier": "^3.2.5",
"postcss-preset-env": "^9.6.0",
"prettier": "^3.3.2",
"stylelint": "^16.6.1",
"stylelint-config-recess-order": "^5.0.1",
"stylelint-config-standard-less": "^3.0.1",
"stylelint-order": "^6.0.4",
"typescript": "^5.4.5",
"vite": "^5.2.12",
"typescript": "^5.5.3",
"vite": "^5.3.3",
"vite-plugin-node-polyfills": "^0.22.0",
"vite-plugin-svgr": "^4.2.0"
}

4214
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;

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

@@ -0,0 +1,134 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 初始化ali oss
* @param data 用户id
* @param Id id
*/
export const initAliOSS = (data: any, Id: any) => {
return web.request({
url: "/oss/oss/ali/init",
method: "get",
params: {
userId: data,
Id: Id,
},
});
};
/**
* 获取文件目录信息
* @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,
},
});
};
/**
* 新增阿里云oss配置
* @param data
*/
export const addAliOSSConfig = (data: API.AliOSSConfigRequest) => {
return web.request({
url: `/oss/oss/ali/add`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 注销阿里云oss配置
* @param userId
* @param Id
*/
export const setAliShutdown = (userId: any, Id: any) => {
return web.request({
url: `/oss/oss/ali/shutdown`,
method: "post",
params: {
userId: userId,
Id: Id,
},
});
};
/**
* 删除阿里云oss配置
* @param data
*/
export const deleteAliConfig = (data: any) => {
return web.request({
url: `/oss/oss/ali/delete`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 修改阿里云oss配置
* @param data
*/
export const updateAliConfig = (data: any) => {
return web.request({
url: `/oss/oss/ali/update`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 获取阿里云oss配置详情
* @param id
*/
export const getAliConfigDetailById = (id: any) => {
return web.request({
url: `/oss/oss/ali/one`,
method: "get",
params: {
id: id,
},
});
};

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

@@ -0,0 +1,357 @@
/** @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,
},
});
};
/**
* 获取存储桶
* @param userId
* @param bucket
* @param type
*/
export const deleteBucket = (userId: any, bucket: any, type: any) => {
return web.request({
url: `/oss/oss/` + type + `/deleteBucket`,
method: "post",
params: {
userId: userId,
bucket: bucket,
},
});
};
/**
* 获取存储桶大小
* @param userId
* @param bucket
* @param type
*/
export const getBucketSize = (userId: any, bucket: any, type: any) => {
return web.request({
url: `/oss/oss/` + type + `/getBucketSize`,
method: "post",
params: {
userId: userId,
bucket: bucket,
},
});
};
/**
* 创建存储桶
* @param userId
* @param bucket
* @param type
*/
export const creatBucket = (userId: any, bucket: any, type: any) => {
return web.request({
url: `/oss/oss/` + type + `/createBucket`,
method: "post",
params: {
userId: userId,
bucket: bucket,
},
});
};
/**
* 删除文件
* @param userId
* @param bucket
* @param type
* @param filePath
*/
export const deleteFile = (userId: any, bucket: any, type: any, filePath: any) => {
return web.request({
url: `/oss/oss/` + type + `/deleteFile`,
method: "post",
params: {
userId: userId,
bucket: bucket,
filePath: filePath,
},
});
};
/**
* 下载文件
* @param userId
* @param bucket
* @param type
* @param listObjectsArgs
*/
export const downloadFiles = (userId: any, bucket: any, type: any, listObjectsArgs: any) => {
return web.request({
url: `/oss/oss/` + type + `/downloadFile`,
method: "get",
responseType: "blob",
params: {
userId: userId,
bucket: bucket,
listObjectsArgs: listObjectsArgs,
},
});
};
/**
* 预览文件
* @param userId
* @param bucket
* @param type
* @param filePath
*/
export const previewFile = (userId: any, bucket: any, type: any, filePath: any) => {
return web.request({
url: `/oss/oss/` + type + `/previewFile`,
method: "post",
params: {
userId: userId,
bucket: bucket,
filePath: filePath,
},
});
};
/**
* 重命名文件
* @param userId
* @param bucket
* @param type
* @param oldFileName
* @param newFileName
*/
export const renameFile = (
userId: any,
bucket: any,
type: any,
oldFileName: any,
newFileName: any,
) => {
return web.request({
url: `/oss/oss/` + type + `/renameFile`,
method: "post",
params: {
userId: userId,
bucket: bucket,
oldFileName: oldFileName,
newFileName: newFileName,
},
});
};
/**
* 拷贝文件
* @param userId
* @param bucket
* @param type
* @param oldFilePath
* @param newFilePath
*/
export const copyFile = (
userId: any,
bucket: any,
type: any,
oldFilePath: any,
newFilePath: any,
) => {
return web.request({
url: `/oss/oss/` + type + `/copyFile`,
method: "post",
params: {
userId: userId,
bucket: bucket,
oldFilePath: oldFilePath,
newFilePath: newFilePath,
},
});
};
/**
* 创建存储桶
* @param userId
* @param bucket
* @param type
*/
export const createBucket = (userId: any, bucket: any, type: any) => {
return web.request({
url: `/oss/oss/` + type + `/createBucket`,
method: "post",
params: {
userId: userId,
bucket: bucket,
},
});
};
/**
* 上传文件
* @param type
* @param data
* @param peram
*/
export const uploadFiles = (type: any, data: any, peram: any) => {
return web.request({
url: `/oss/oss/` + type + `/uploadFile`,
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
data: data,
params: peram,
});
};

View File

@@ -5,13 +5,15 @@ import web from "@/utils/axios/web.ts";
/**
* 初始化minio
* @param data 用户id
* @param id
*/
export const initMinio = (data: any) => {
export const initMinioOSS = (data: any, id: any) => {
return web.request({
url: "/oss/oss/minio/init",
method: "post",
params: {
userId: data,
Id: id,
},
});
};
@@ -33,15 +35,100 @@ 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,
},
});
};
/**
* 新增阿里云oss配置
* @param data
*/
export const addMinioOSSConfig = (data: API.MinioOSSConfigRequest) => {
return web.request({
url: `/oss/oss/minio/add`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 注销MinIo oss配置
* @param userId
* @param Id
*/
export const setMinioShutdown = (userId: any, Id: any) => {
return web.request({
url: `/oss/oss/minio/shutdown`,
method: "post",
params: {
userId: userId,
Id: Id,
},
});
};
/**
* 删除Minio oss配置
* @param data
*/
export const deleteMinioConfig = (data: any) => {
return web.request({
url: `/oss/oss/minio/delete`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 删除Minio oss配置
* @param data
*/
export const updateMinioConfig = (data: any) => {
return web.request({
url: `/oss/oss/minio/update`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 获取Minio oss配置详情
* @param id
*/
export const getMinioConfigDetailById = (id: any) => {
return web.request({
url: `/oss/oss/minio/one`,
method: "get",
params: {
Id: id,
},
});
};

133
src/api/oss/qiniu/index.ts Normal file
View File

@@ -0,0 +1,133 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 初始化qiniu
* @param data 用户id
* @param id
*/
export const initQiniuOSS = (data: any, id: any) => {
return web.request({
url: "/oss/oss/qiniu/init",
method: "post",
params: {
userId: data,
Id: id,
},
});
};
/**
* 获取文件目录信息
* @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,
},
});
};
/**
* 新增七牛oss配置
* @param data
*/
export const addQiniuOSSConfig = (data: API.QiniuOSSConfigRequest) => {
return web.request({
url: `/oss/oss/qiniu/add`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 注销 Qiniu oss配置
* @param userId
* @param Id
*/
export const setQiniuShutdown = (userId: any, Id: any) => {
return web.request({
url: `/oss/oss/qiniu/shutdown`,
method: "post",
params: {
userId: userId,
Id: Id,
},
});
};
/**
* 删除Qiniu oss配置
* @param data
*/
export const deleteQiniuConfig = (data: any) => {
return web.request({
url: `/oss/oss/qiniu/delete`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 更新Qiniu oss配置
* @param data
*/
export const updateQiniuConfig = (data: any) => {
return web.request({
url: `/oss/oss/qiniu/update`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 获取Qiniu oss配置
* @param id
*/
export const getQiniuConfigDetailById = (id: any) => {
return web.request({
url: `/oss/oss/qiniu/one`,
method: "get",
params: {
Id: id,
},
});
};

View File

@@ -0,0 +1,135 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 初始化Tencent oss
* @param data 用户id
* @param id
*/
export const initTencentOSS = (data: any, id: any) => {
return web.request({
url: "/oss/oss/tencent/init",
method: "post",
params: {
userId: data,
Id: id,
},
});
};
/**
* 获取文件目录信息
* @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,
},
});
};
/**
* 新增腾讯云oss
* @param data
*/
export const addTencentOSSConfig = (data: API.TencentOSSConfigRequest) => {
return web.request({
url: `/oss/oss/tencent/add`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 注销 Tencent oss配置
* @param userId
* @param Id
*/
export const setTencentShutdown = (userId: any, Id: any) => {
return web.request({
url: `/oss/oss/tencent/shutdown`,
method: "post",
params: {
userId: userId,
Id: Id,
},
});
};
/**
* 删除Tencent oss配置
* @param data
*/
export const deleteTencentConfig = (data: any) => {
return web.request({
url: `/oss/oss/tencent/delete`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 更新Tencent oss配置
* @param data
*/
export const updateTencentConfig = (data: any) => {
return web.request({
url: `/oss/oss/tencent/update`,
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 获取腾讯云oss配置详情
* @param id
*/
export const getTencentConfigDetailById = (id: any) => {
return web.request({
url: `/oss/oss/tencent/one`,
method: "get",
params: {
Id: id,
},
});
};

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,
},
});
};

212
src/api/share/index.ts Normal file
View File

@@ -0,0 +1,212 @@
/** @format */
import web from "@/utils/axios/web.ts";
/**
* 获取分享圈列表
*/
export const getShareCircleList = () => {
return web.request({
url: `/share/share/circle/sharelist`,
method: "get",
});
};
/**
* 新增分享圈
* @param data
* @constructor
*/
export const addShareCircle = (data: any) => {
return web.request({
url: `/share/share/circle/add`,
method: "post",
data: data,
});
};
/**
* 分享圈详情列表
* @param circleId
*/
export const shareDetailList = (circleId: any) => {
return web.request({
url: `/share/share/detail/list`,
method: "post",
params: {
circleId: circleId,
},
});
};
/**
* 分享圈详情
* @param id
*/
export const getShareDetail = (id: any) => {
return web.request({
url: `/share/share/detail/get_detail`,
method: "get",
params: {
Id: id,
},
});
};
/**
* 新增分享圈详情
* @param data
*/
export const addShareDetail = (data: any) => {
return web.request({
url: `/share/share/detail/add_detail`,
method: "post",
data: data,
});
};
/**
* 分享圈详情评论列表
* @param detailId
* @param userId
*/
export const listComment = (detailId: any, userId: any) => {
return web.request({
url: `/share/share/comment/reply/listcomment`,
method: "get",
params: {
detailId: detailId,
userId: userId,
},
});
};
/**
* 分享圈详情热门评论列表
* @param detailId
* @param userId
*/
export const listCommentHot = (detailId: any, userId: any) => {
return web.request({
url: `/share/share/comment/reply/listcommenthot`,
method: "get",
params: {
detailId: detailId,
userId: userId,
},
});
};
/**
* 分享圈详情回复列表
* @param commentId
* @param userId
*/
export const listReply = (commentId: any, userId: any) => {
return web.request({
url: `/share/share/comment/reply/listreply`,
method: "get",
params: {
commentId: commentId,
userId: userId,
},
});
};
/**
* 新增评论
* @param data
*/
export const addComment = (data: any) => {
return web.request({
url: `/share/share/comment/reply/addcomment`,
method: "post",
data: data,
});
};
/**
* 新增回复
* @param data
*/
export const addReply = (data: any) => {
return web.request({
url: `/share/share/comment/reply/addreply`,
method: "post",
data: data,
});
};
/**
* 返回评论总数
* @param detailId
*/
export const returnAllCommentAndReplyCount = (detailId: any) => {
return web.request({
url: `/share/share/detail/returncount`,
method: "get",
params: {
detailId: detailId,
},
});
};
/**
* 获取我的分享圈列表
* @param userId
*/
export const getMyShareList = (userId: any) => {
return web.request({
url: `/share/share/detail/mydetail`,
method: "get",
params: {
userId: userId,
},
});
};
/**
* 获取我的分享圈收藏
* @param userId
*/
export const getMyFavor = (userId: any) => {
return web.request({
url: `/share/share/user/favorites/myfavor`,
method: "get",
params: {
userId: userId,
},
});
};
/**
* 新增点赞
* @param data
*/
export const addLikeComment = (data: any) => {
return web.request({
url: `/share/share/comment/reply/addlike`,
method: "post",
data: data,
});
};
/**
* 删除点赞
* @param data
*/
export const deletedLikeComment = (data: any) => {
return web.request({
url: `/share/share/comment/reply/dellike`,
method: "post",
data: data,
});
};
/**
* 新增点赞
* @param data
*/
export const addLikeDetail = (data: any) => {
return web.request({
url: `/share/share/detail/addlike`,
method: "post",
data: data,
});
};
/**
* 删除点赞
* @param data
*/
export const deletedLikeDetail = (data: any) => {
return web.request({
url: `/share/share/detail/dellike`,
method: "post",
data: data,
});
};

View File

@@ -1,137 +1,226 @@
/** @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/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,
},
});
};
/**
* 更新用户信息
* @param data
*/
export const updateUserInfo = (data: any): any => {
return web.request({
url: "/auth/auth/user/update",
method: "post",
headers: {
"Content-Type": "application/json;charset=UTF-8",
},
data: data,
});
};
/**
* 新增用户收藏
* @param data
*/
export const addFavorites = (data: any): any => {
return web.request({
url: "/share/share/user/favorites/add",
method: "post",
data: data,
});
};
/**
* 取消用户收藏
* @param data
*/
export const deleteFavorites = (data: any): any => {
return web.request({
url: "/share/share/user/favorites/delete",
method: "post",
data: data,
});
};
/**
* 退出登录
* @param userId
*/
export const logout = (userId: any): any => {
return web.request({
url: "/auth/auth/user/logout",
method: "post",
params: {
userId: userId,
},
});
};
/**
* 检查用户名是否已存在
* @param userName
*/
export const checkUserName = (userName: any): any => {
return web.request({
url: "/auth/auth/user/checkUserName",
method: "post",
params: {
userName: userName,
},
});
};
/**
* 获取最近分享
* @param userId
*/
export const getRecentShare = (userId: any): any => {
return web.request({
url: "/share/share/detail/getRecentShare",
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="1720834001446" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4550" width="200" height="200"><path d="M512 512.8704m-432.3328 0a432.3328 432.3328 0 1 0 864.6656 0 432.3328 432.3328 0 1 0-864.6656 0Z" fill="#F8A10F" p-id="4551"></path><path d="M287.0272 418.7136c-85.0432 0-160.4096 41.3696-207.104 105.0624 4.5568 182.7328 122.368 337.3056 285.952 396.032 103.2192-33.28 177.92-130.048 177.92-244.3776 0-141.7216-114.944-256.7168-256.768-256.7168z" fill="#FFBD48" p-id="4552"></path><path d="M573.184 251.4944L624.64 355.7888a45.8752 45.8752 0 0 0 34.5088 25.088l115.0976 16.7424c37.5808 5.4784 52.5824 51.6608 25.3952 78.1824l-83.3024 81.2032a45.78816 45.78816 0 0 0-13.1584 40.5504l19.6608 114.6368c6.4 37.4272-32.8704 65.9968-66.5088 48.3328l-102.9632-54.1184a45.8496 45.8496 0 0 0-42.6496 0l-102.9632 54.1184c-33.6384 17.664-72.9088-10.8544-66.5088-48.3328l19.6608-114.6368c2.56-14.848-2.3552-30.0544-13.1584-40.5504L264.4992 475.7504c-27.1872-26.5216-12.1856-72.704 25.3952-78.1824l115.0976-16.7424a45.63968 45.63968 0 0 0 34.5088-25.088L491.008 251.4944c16.7936-34.048 65.3824-34.048 82.176 0z" fill="#FFFFFF" p-id="4553"></path><path d="M510.7712 706.3552a45.8496 45.8496 0 0 1 42.6496 0l102.9632 54.1184c33.6384 17.664 72.9088-10.8544 66.5088-48.3328l-19.6608-114.6368c-2.56-14.848 2.3552-30.0544 13.1584-40.5504l-205.6192 149.4016z" fill="#FFEACC" p-id="4554"></path></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1 @@
<svg t="1720833921345" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1614" width="200" height="200"><path d="M511.4368 512m-432.3328 0a432.3328 432.3328 0 1 0 864.6656 0 432.3328 432.3328 0 1 0-864.6656 0Z" fill="#FF6161" p-id="1615"></path><path d="M286.464 417.8432c-85.0432 0-160.4096 41.3696-207.104 105.0624 4.5568 182.7328 122.368 337.3056 285.952 396.032 103.2192-33.28 177.92-130.048 177.92-244.3776 0-141.7728-114.944-256.7168-256.768-256.7168z" fill="#FF7D7D" p-id="1616"></path><path d="M342.6304 721.6128h6.7584V427.9808h-6.7584c-36.096 0-65.3824 29.2864-65.3824 65.3824v162.9184c0.0512 36.0448 29.2864 65.3312 65.3824 65.3312z" fill="#FFCAC7" p-id="1617"></path><path d="M710.656 390.9632h-136.8064c10.6496-34.9696 24.9344-106.8032-25.088-137.1648-23.5008-14.1824-78.8992-24.1664-77.568 37.9904 1.28 62.1568-2.2528 130.4064-81.152 136.192v293.632h280.2688c31.744 0 59.136-22.3232 65.4848-53.4528l40.2944-196.9152c8.5504-41.472-23.0912-80.2816-65.4336-80.2816z" fill="#FFFFFF" p-id="1618"></path></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 376 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1,33 +1,40 @@
/*定义滚动条宽高及背景,宽高分别对应横竖滚动条的尺寸*/
// 滚动条整体部分
&::-webkit-scrollbar {
width: 6px;
height: 8px;
}
// 滚动条的轨道的两端按钮,允许通过点击微调小方块的位置。
&::-webkit-scrollbar-button {
visibility: hidden;
}
// 滚动条里面的小方块,能向上向下移动(或往左往右移动,取决于是垂直滚动条还是水平滚动条)
&::-webkit-scrollbar-thumb {
background: rgba(144, 147, 153, 0.3);
cursor: pointer;
border-radius: 4px;
}
// 边角,即两个滚动条的交汇处
&::-webkit-scrollbar-corner {
visibility: hidden;
}
// 两个滚动条的交汇处上用于通过拖动调整元素大小的小控件
&::-webkit-resizer {
visibility: hidden;
}
body {
background-image: url("@/assets/images/background.png");
background-size: cover;
}
/*定义滚动条宽高及背景,宽高分别对应横竖滚动条的尺寸*/
// 滚动条整体部分
&::-webkit-scrollbar {
width: 6px;
height: 8px;
}
// 滚动条的轨道的两端按钮,允许通过点击微调小方块的位置。
&::-webkit-scrollbar-button {
visibility: hidden;
}
// 滚动条里面的小方块,能向上向下移动(或往左往右移动,取决于是垂直滚动条还是水平滚动条)
&::-webkit-scrollbar-thumb {
background: rgba(144, 147, 153, 0.3);
cursor: pointer;
border-radius: 4px;
}
// 边角,即两个滚动条的交汇处
&::-webkit-scrollbar-corner {
visibility: hidden;
}
// 两个滚动条的交汇处上用于通过拖动调整元素大小的小控件
&::-webkit-resizer {
visibility: hidden;
}
body {
background-image: url("@/assets/images/background.png");
background-size: cover;
}
.ant-pro-page-container-children-container-no-header {
padding-block-start: 10px !important;
}
.ant-pro-page-container-children-container {
padding-inline: 10px !important;
}

View File

@@ -1,24 +0,0 @@
/** @format */
import { Tree, TreeDataNode } from "antd";
import React from "react";
const { DirectoryTree } = Tree;
interface FileDirectoryTreeProps {
treeData: TreeDataNode[];
}
const FileDirectoryTree: React.FC<FileDirectoryTreeProps> = (props: any) => {
return (
<DirectoryTree
style={{ width: "20%", fontSize: "20px" }}
multiple={false}
defaultExpandAll
treeData={props.treeData}
blockNode={true}
showIcon={true}
{...props}
/>
);
};
export default FileDirectoryTree;

View File

@@ -1,83 +1,152 @@
/** @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, Form, Input, message, Modal, Popconfirm, Popover, Skeleton } from "antd";
import { ProCard } from "@ant-design/pro-components";
import { useEffect, useState } from "react";
import { ClusterOutlined, DeleteOutlined, ReloadOutlined } from "@ant-design/icons";
import bucket from "@/assets/icons/bucket.svg";
import styles from "./index.module.less";
import { creatBucket, deleteBucket, getBucketSize } from "@/api/oss";
import { getAllAliOSsBucket } from "@/api/oss/ali";
import { observer } from "mobx-react";
import useStore from "@/utils/store/useStore.tsx";
const DrawerContext = createContext<{
drawerVisit: boolean;
setDrawerVisit: React.Dispatch<React.SetStateAction<boolean>>;
}>({} as any);
const AliDrawer = () => {
const [drawerVisit, setDrawerVisit] = useState(false);
return (
<DrawerContext.Provider value={{ drawerVisit, setDrawerVisit }}>
<ProCardComponent />
</DrawerContext.Provider>
);
};
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 AliDrawer = observer(() => {
const [buckets, setBuckets] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
const [bucketSize, setBucketSize] = useState<string>("");
const [form] = Form.useForm();
const [open, setOpen] = useState<boolean>(false);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
async function getAllBucket() {
getAllAliOSsBucket(userId).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={() => setOpen(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={}
style={{
width: "180px",
marginLeft: 10,
}}
actions={[
// eslint-disable-next-line react/jsx-key
<Popover
content={bucketSize}
title={`size:`}
trigger="click">
<ClusterOutlined
key={"calculate"}
onClick={() => {
getBucketSize(
userId,
item.name,
"minio",
).then((res: any) => {
if (
res &&
res.success &&
res.data
) {
setBucketSize(res.data);
} else {
message
.open({
content: "计算出错!",
type: "error",
})
.then();
}
});
}}
/>
</Popover>,
// eslint-disable-next-line react/jsx-key
<Popconfirm
title={`删除存储桶:${item.name}`}
description="你知道你要做什么吗?"
onConfirm={() => {
deleteBucket(
userId,
item.name,
"minio",
).then((res: any) => {
if (
res &&
res.data &&
res.data === "success"
) {
message
.open({
content: "删除成功!",
type: "success",
})
.then();
} else {
message
.open({
content: res.data,
type: "error",
})
.then();
}
});
}}
okText="Yes"
cancelText="No">
<DeleteOutlined key="delete" />
</Popconfirm>,
]}>
<Avatar
shape={"square"}
src={bucket as any}
size={"large"}
/>
<b style={{ marginLeft: 5 }}>{item.name}</b>
</ProCard>
</div>
);
})}
</Skeleton>
</div>
</ProCard>
);
@@ -86,34 +155,51 @@ const ProCardComponent = () => {
return (
<>
{bucketList()}
<DrawerForm
<Modal
title="创建存储桶"
open={drawerVisit}
onOpenChange={setDrawerVisit}
onFinish={async (values) => {
console.log(values.name);
message.success("提交成功");
return true;
}}>
<ProForm.Group>
<ProFormText
width="md"
width={"30%"}
open={open}
closable={true}
onOk={() => {
const bucketName = form.getFieldValue("name" as any);
if (bucketName === "" || bucketName === null) {
message.open({
content: " 请输入存储桶名称!",
type: "warning",
});
} else {
creatBucket(userId, bucketName, "ali").then((res: any) => {
if (res && res.success) {
message
.open({
content: "创建成功!",
type: "success",
})
.then();
setOpen(false);
} else {
message
.open({
content: res.data,
type: "error",
})
.then();
}
});
}
}}
onCancel={() => setOpen(false)}>
<Form layout="vertical" form={form}>
<Form.Item
name="name"
label="存储桶名"
tooltip="最长为 24 位"
placeholder="请输入名称"
/>
<ProFormText
width="md"
name="capacity"
label="我方公司名称"
placeholder="请输入名称"
/>
</ProForm.Group>
</DrawerForm>
label="存储桶名"
rules={[{ required: true, message: "请输入存储桶名称!" }]}>
<Input placeholder="请输入存储桶名称" />
</Form.Item>
</Form>
</Modal>
</>
);
};
});
export default AliDrawer;

View File

@@ -1,78 +1,151 @@
/** @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, Form, Input, message, Modal, Popconfirm, Popover, Skeleton } from "antd";
import { ProCard } from "@ant-design/pro-components";
import { useEffect, useState } from "react";
import { ClusterOutlined, DeleteOutlined, ReloadOutlined } from "@ant-design/icons";
import bucket from "@/assets/icons/bucket.svg";
import styles from "./index.module.less";
import { getAllMinioBucket } from "@/api/oss/minio";
import { creatBucket, deleteBucket, getBucketSize } from "@/api/oss";
import { observer } from "mobx-react";
import useStore from "@/utils/store/useStore.tsx";
const DrawerContext = createContext<{
drawerVisit: boolean;
setDrawerVisit: React.Dispatch<React.SetStateAction<boolean>>;
}>({} as any);
const MinioDrawer = () => {
const [drawerVisit, setDrawerVisit] = useState(false);
return (
<DrawerContext.Provider value={{ drawerVisit, setDrawerVisit }}>
<ProCardComponent />
</DrawerContext.Provider>
);
};
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 MinioDrawer = observer(() => {
const [buckets, setBuckets] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
const [bucketSize, setBucketSize] = useState<string>("");
const [form] = Form.useForm();
const [open, setOpen] = useState<boolean>(false);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
async function getAllBucket() {
getAllMinioBucket(userId).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={() => setOpen(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={}
style={{
width: "200px",
marginLeft: 20,
}}
actions={[
// eslint-disable-next-line react/jsx-key
<Popover
content={bucketSize}
title={`size:`}
trigger="click">
<ClusterOutlined
key={"calculate"}
onClick={() => {
getBucketSize(
userId,
item.name,
"minio",
).then((res: any) => {
if (
res &&
res.success &&
res.data
) {
setBucketSize(res.data);
} else {
message
.open({
content: "计算出错!",
type: "error",
})
.then();
}
});
}}
/>
</Popover>,
// eslint-disable-next-line react/jsx-key
<Popconfirm
title={`删除存储桶:${item.name}`}
description="你知道你要做什么吗?"
onConfirm={() => {
deleteBucket(
userId,
item.name,
"minio",
).then((res: any) => {
if (
res &&
res.data &&
res.data === "success"
) {
message
.open({
content: "删除成功!",
type: "success",
})
.then();
} else {
message
.open({
content: res.data,
type: "error",
})
.then();
}
});
}}
okText="Yes"
cancelText="No">
<DeleteOutlined key="delete" />
</Popconfirm>,
]}>
<Avatar
shape={"square"}
src={bucket as any}
size={"large"}
/>
<b style={{ marginLeft: 5 }}>{item.name}</b>
</ProCard>
</div>
);
})}
</Skeleton>
</div>
</ProCard>
);
@@ -81,34 +154,51 @@ const ProCardComponent = () => {
return (
<>
{bucketList()}
<DrawerForm
<Modal
title="创建存储桶"
open={drawerVisit}
onOpenChange={setDrawerVisit}
onFinish={async (values) => {
console.log(values.name);
message.success("提交成功");
return true;
}}>
<ProForm.Group>
<ProFormText
width="md"
width={"30%"}
open={open}
closable={true}
onOk={() => {
const bucketName = form.getFieldValue("name" as any);
if (bucketName === "" || bucketName === null) {
message.open({
content: " 请输入存储桶名称!",
type: "warning",
});
} else {
creatBucket(userId, bucketName, "minio").then((res: any) => {
if (res && res.success) {
message
.open({
content: "创建成功!",
type: "success",
})
.then();
setOpen(false);
} else {
message
.open({
content: res.data,
type: "error",
})
.then();
}
});
}
}}
onCancel={() => setOpen(false)}>
<Form layout="vertical" form={form}>
<Form.Item
name="name"
label="存储桶名"
tooltip="最长为 24 位"
placeholder="请输入名称"
/>
<ProFormText
width="md"
name="capacity"
label="我方公司名称"
placeholder="请输入名称"
/>
</ProForm.Group>
</DrawerForm>
label="存储桶名"
rules={[{ required: true, message: "请输入存储桶名称!" }]}>
<Input placeholder="请输入存储桶名称" />
</Form.Item>
</Form>
</Modal>
</>
);
};
});
export default MinioDrawer;

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 { 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;
@@ -26,24 +22,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 +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,83 +1,152 @@
/** @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, Form, Input, message, Modal, Popconfirm, Popover, Skeleton } from "antd";
import { ProCard } from "@ant-design/pro-components";
import { useEffect, useState } from "react";
import { ClusterOutlined, DeleteOutlined, ReloadOutlined } from "@ant-design/icons";
import bucket from "@/assets/icons/bucket.svg";
import styles from "./index.module.less";
import { getAllMinioBucket } from "@/api/oss/minio";
import { creatBucket, deleteBucket, getBucketSize } from "@/api/oss";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
const DrawerContext = createContext<{
drawerVisit: boolean;
setDrawerVisit: React.Dispatch<React.SetStateAction<boolean>>;
}>({} as any);
const QiniuDrawer = () => {
const [drawerVisit, setDrawerVisit] = useState(false);
return (
<DrawerContext.Provider value={{ drawerVisit, setDrawerVisit }}>
<ProCardComponent />
</DrawerContext.Provider>
);
};
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 QiniuDrawer = observer(() => {
const [buckets, setBuckets] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
const [bucketSize, setBucketSize] = useState<string>("");
const [form] = Form.useForm();
const [open, setOpen] = useState<boolean>(false);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
async function getAllBucket() {
getAllMinioBucket(userId).then((res: any) => {
if (res && res.success) {
setBuckets(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getAllBucket().then();
}, []);
const bucketList = () => {
return (
<ProCard
title={"存储桶列表"}
title={"Qiniu存储桶列表"}
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={() => setOpen(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={}
style={{
width: "180px",
marginLeft: 10,
}}
actions={[
// eslint-disable-next-line react/jsx-key
<Popover
content={bucketSize}
title={`size:`}
trigger="click">
<ClusterOutlined
key={"calculate"}
onClick={() => {
getBucketSize(
userId,
item.name,
"minio",
).then((res: any) => {
if (
res &&
res.success &&
res.data
) {
setBucketSize(res.data);
} else {
message
.open({
content: "计算出错!",
type: "error",
})
.then();
}
});
}}
/>
</Popover>,
// eslint-disable-next-line react/jsx-key
<Popconfirm
title={`删除存储桶:${item.name}`}
description="你知道你要做什么吗?"
onConfirm={() => {
deleteBucket(
userId,
item.name,
"minio",
).then((res: any) => {
if (
res &&
res.data &&
res.data === "success"
) {
message
.open({
content: "删除成功!",
type: "success",
})
.then();
} else {
message
.open({
content: res.data,
type: "error",
})
.then();
}
});
}}
okText="Yes"
cancelText="No">
<DeleteOutlined key="delete" />
</Popconfirm>,
]}>
<Avatar
shape={"square"}
src={bucket as any}
size={"large"}
/>
<b style={{ marginLeft: 5 }}>{item.name}</b>
</ProCard>
</div>
);
})}
</Skeleton>
</div>
</ProCard>
);
@@ -86,34 +155,51 @@ const ProCardComponent = () => {
return (
<>
{bucketList()}
<DrawerForm
<Modal
title="创建存储桶"
open={drawerVisit}
onOpenChange={setDrawerVisit}
onFinish={async (values) => {
console.log(values.name);
message.success("提交成功");
return true;
}}>
<ProForm.Group>
<ProFormText
width="md"
width={"30%"}
open={open}
closable={true}
onOk={() => {
const bucketName = form.getFieldValue("name" as any);
if (bucketName === "" || bucketName === null) {
message.open({
content: " 请输入存储桶名称!",
type: "warning",
});
} else {
creatBucket(userId, bucketName, "qiniu").then((res: any) => {
if (res && res.success) {
message
.open({
content: "创建成功!",
type: "success",
})
.then();
setOpen(false);
} else {
message
.open({
content: res.data,
type: "error",
})
.then();
}
});
}
}}
onCancel={() => setOpen(false)}>
<Form layout="vertical" form={form}>
<Form.Item
name="name"
label="存储桶名"
tooltip="最长为 24 位"
placeholder="请输入名称"
/>
<ProFormText
width="md"
name="capacity"
label="我方公司名称"
placeholder="请输入名称"
/>
</ProForm.Group>
</DrawerForm>
label="存储桶名"
rules={[{ required: true, message: "请输入存储桶名称!" }]}>
<Input placeholder="请输入存储桶名称" />
</Form.Item>
</Form>
</Modal>
</>
);
};
});
export default QiniuDrawer;

View File

@@ -1,83 +1,152 @@
/** @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, Form, Input, message, Modal, Popconfirm, Popover, Skeleton } from "antd";
import { ProCard } from "@ant-design/pro-components";
import { useEffect, useState } from "react";
import { ClusterOutlined, DeleteOutlined, ReloadOutlined } from "@ant-design/icons";
import bucket from "@/assets/icons/bucket.svg";
import styles from "./index.module.less";
import { getAllMinioBucket } from "@/api/oss/minio";
import { creatBucket, deleteBucket, getBucketSize } from "@/api/oss";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
const DrawerContext = createContext<{
drawerVisit: boolean;
setDrawerVisit: React.Dispatch<React.SetStateAction<boolean>>;
}>({} as any);
const TencentDrawer = () => {
const [drawerVisit, setDrawerVisit] = useState(false);
return (
<DrawerContext.Provider value={{ drawerVisit, setDrawerVisit }}>
<ProCardComponent />
</DrawerContext.Provider>
);
};
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 TencentDrawer = observer(() => {
const [buckets, setBuckets] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
const [bucketSize, setBucketSize] = useState<string>("");
const [form] = Form.useForm();
const [open, setOpen] = useState<boolean>(false);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
async function getAllBucket() {
getAllMinioBucket(userId).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)}>
</Button>
<>
<Button
type="default"
shape={"circle"}
style={{ marginRight: 20 }}
onClick={() => {
setLoading(false);
getAllBucket().then();
}}
icon={<ReloadOutlined />}></Button>
<Button type="primary" onClick={() => setOpen(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={}
style={{
width: "180px",
marginLeft: 10,
}}
actions={[
// eslint-disable-next-line react/jsx-key
<Popover
content={bucketSize}
title={`size:`}
trigger="click">
<ClusterOutlined
key={"calculate"}
onClick={() => {
getBucketSize(
userId,
item.name,
"minio",
).then((res: any) => {
if (
res &&
res.success &&
res.data
) {
setBucketSize(res.data);
} else {
message
.open({
content: "计算出错!",
type: "error",
})
.then();
}
});
}}
/>
</Popover>,
// eslint-disable-next-line react/jsx-key
<Popconfirm
title={`删除存储桶:${item.name}`}
description="你知道你要做什么吗?"
onConfirm={() => {
deleteBucket(
userId,
item.name,
"minio",
).then((res: any) => {
if (
res &&
res.data &&
res.data === "success"
) {
message
.open({
content: "删除成功!",
type: "success",
})
.then();
} else {
message
.open({
content: res.data,
type: "error",
})
.then();
}
});
}}
okText="Yes"
cancelText="No">
<DeleteOutlined key="delete" />
</Popconfirm>,
]}>
<Avatar
shape={"square"}
src={bucket as any}
size={"large"}
/>
<b style={{ marginLeft: 5 }}>{item.name}</b>
</ProCard>
</div>
);
})}
</Skeleton>
</div>
</ProCard>
);
@@ -86,34 +155,51 @@ const ProCardComponent = () => {
return (
<>
{bucketList()}
<DrawerForm
<Modal
title="创建存储桶"
open={drawerVisit}
onOpenChange={setDrawerVisit}
onFinish={async (values) => {
console.log(values.name);
message.success("提交成功");
return true;
}}>
<ProForm.Group>
<ProFormText
width="md"
width={"30%"}
open={open}
closable={true}
onOk={() => {
const bucketName = form.getFieldValue("name" as any);
if (bucketName === "" || bucketName === null) {
message.open({
content: " 请输入存储桶名称!",
type: "warning",
});
} else {
creatBucket(userId, bucketName, "tencent").then((res: any) => {
if (res && res.success) {
message
.open({
content: "创建成功!",
type: "success",
})
.then();
setOpen(false);
} else {
message
.open({
content: res.data,
type: "error",
})
.then();
}
});
}
}}
onCancel={() => setOpen(false)}>
<Form layout="vertical" form={form}>
<Form.Item
name="name"
label="存储桶名"
tooltip="最长为 24 位"
placeholder="请输入名称"
/>
<ProFormText
width="md"
name="capacity"
label="我方公司名称"
placeholder="请输入名称"
/>
</ProForm.Group>
</DrawerForm>
label="存储桶名"
rules={[{ required: true, message: "请输入存储桶名称!" }]}>
<Input placeholder="请输入存储桶名称" />
</Form.Item>
</Form>
</Modal>
</>
);
};
});
export default TencentDrawer;

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 { 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 { getAllQiniuBucket } from "@/api/oss/qiniu";
const DrawerContext = createContext<{
drawerVisit: boolean;
@@ -26,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 (
@@ -51,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,13 +1,9 @@
.proCard{
max-width: 30%;
height: 75vh;
max-height: 75vh;
min-height: 84vh;
}
.proCardBucket{
height: 75vh;
max-height: 75vh;
width: 100%;
}
@@ -18,11 +14,6 @@
}
.div_checkCardArea{
height: 65vh;
max-height: 65vh;
overflow-y:scroll;
overflow-x: hidden;
}
//.div_checkCardArea::-webkit-scrollbar {
//
//}

View File

@@ -1,16 +1,33 @@
/** @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 StorageIcon from "@/context/stroage-icon.ts";
import { Button, Empty, Skeleton } from "antd";
import StorageIcon from "@/constant/stroage-icon.ts";
import { ReloadOutlined } from "@ant-design/icons";
import { getAllStorage } from "@/api/oss";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
const Bucket: FunctionComponent = () => {
const Bucket: FunctionComponent = observer(() => {
const navigate = useNavigate();
const checkList = ["minio", "ali", "tencent", "huawei", "baidu", "jd"];
const [userStorage, setUserStorage] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
async function getUserStorage() {
getAllStorage(userId).then((res: any) => {
if (res && res.success) {
setUserStorage(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getUserStorage().then();
}, []);
return (
<div className={styles.div_proCard}>
<ProCard
@@ -18,8 +35,10 @@ const Bucket: FunctionComponent = () => {
<Button
type="primary"
shape={"circle"}
icon={<ReloadOutlined />}
onClick={() => navigate("/main/bucket/add")}></Button>
onClick={() => {
getUserStorage().then();
}}
icon={<ReloadOutlined />}></Button>
}
title="存储商"
headerBordered
@@ -27,29 +46,25 @@ const Bucket: FunctionComponent = () => {
boxShadow={true}
colSpan={"100%"}
bordered>
<CheckCard.Group
onChange={(value) => {
console.log("value", value);
}}>
<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={() => {
console.log(`/main/bucket/${item}`);
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/" ? (
@@ -67,5 +82,5 @@ const Bucket: FunctionComponent = () => {
</ProCard>
</div>
);
};
});
export default Bucket;

View File

@@ -0,0 +1,265 @@
/** @format */
import { useState } from "react";
import { Avatar, Card, Flex, Input, message, Select, Upload } from "antd";
import { CloudUploadOutlined } from "@ant-design/icons";
import { ProCard } from "@ant-design/pro-components";
import StorageIcon from "@/constant/stroage-icon.ts";
import { getStorageBuckets, uploadFiles } from "@/api/oss";
import useStore from "@/utils/store/useStore.tsx";
const { Dragger } = Upload;
const FileUpload = (props: any) => {
const [buckets, setBuckets] = useState<any[]>([]);
const store = useStore("file");
const [defaultFileList, setDefaultFileList] = useState([]);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
async function getBuckets(type: any) {
getStorageBuckets(userId, type).then((res: any) => {
if (res && res.success) {
setBuckets(res.data);
}
});
}
const handleOnChange = ({ fileList }: { fileList: any }) => {
setDefaultFileList(fileList);
};
const uploadFile = async (options: any) => {
const { onSuccess, onError, file }: { onSuccess: any; onError: any; file: any } = options;
if (store.getUploadFileBucket() === null || store.getUploadFileStorage() === null) {
message.open({
content: "请选择存储桶和存储路径",
type: "error",
});
return;
}
const fileData = new FormData();
fileData.append("file", file);
const formData: any = {
userId: userId,
bucketName: store.getUploadFileBucket(),
path: store.getUploadFilePath(),
};
console.log(formData);
uploadFiles(store.getUploadFileStorage(), fileData, formData).then((res: any) => {
if (res && res.success) {
message.open({
content: "上传成功",
type: "success",
});
onSuccess(res.success);
} else {
message.open({
content: "上传失败",
type: "error",
});
setDefaultFileList([]);
onError(res.success);
}
});
};
return (
<>
<Flex vertical={false} align={"center"}>
<ProCard bordered={false} boxShadow={false}>
<Flex vertical={false}>
<Select
size="large"
status="warning"
style={{
width: "30%",
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
showSearch={true}
allowClear={true}
onSelect={(value: any) => {
store.setUploadFileStorage(value);
getBuckets(value).then();
}}
onClear={() => {
store.setUploadFileStorage("");
setBuckets([]);
}}
onChange={(value: any) => {
store.setUploadFileStorage(value);
}}
fieldNames={{
label: "name",
value: "ossType",
}}
labelRender={(label: any) => {
return (
<>
<Card
bordered={false}
style={{
height: 35,
display: "flex",
alignItems: "center",
flexDirection: "row",
}}
size={"small"}>
<Avatar src={StorageIcon[label.value]} size={"small"} />
<span
style={{
marginLeft: "10px",
fontWeight: "bolder",
}}>
{label.label}
</span>
</Card>
</>
);
}}
options={props.userStorage}
notFoundContent={"未找到,请先配置存储商"}
optionRender={(item: any) => {
return (
<>
<Card
bordered={false}
style={{
height: 35,
display: "flex",
alignItems: "center",
flexDirection: "row",
}}
size={"small"}>
<Avatar src={StorageIcon[item.value]} size={"small"} />
<span
style={{
marginLeft: "10px",
fontWeight: "bolder",
}}>
{item.label}
</span>
</Card>
</>
);
}}
placeholder={"请选择存储商"}></Select>
<Select
size="large"
status="warning"
style={{
width: "30%",
display: "flex",
flexDirection: "row",
alignItems: "center",
marginLeft: "10px",
}}
onSelect={(value: any) => {
store.setUploadFileBucket(value);
}}
onClear={() => {
store.setUploadFileBucket("");
setBuckets([]);
}}
onChange={(value: any) => {
store.setUploadFileBucket(value);
}}
showSearch={true}
allowClear={true}
notFoundContent={"未找到,请先配置存储商"}
fieldNames={{
label: "name",
value: "name",
}}
labelRender={(label: any) => {
return (
<>
<Card
bordered={false}
style={{
height: 35,
display: "flex",
alignItems: "center",
flexDirection: "row",
}}
size={"small"}>
<Avatar
src={StorageIcon["bucket"]}
shape={"square"}
size={"small"}
/>
<span
style={{
marginLeft: "10px",
fontWeight: "bolder",
}}>
{label.label}
</span>
</Card>
</>
);
}}
options={buckets}
optionRender={(item: any) => {
return (
<>
<Card
bordered={false}
style={{
height: 35,
display: "flex",
alignItems: "center",
flexDirection: "row",
}}
size={"small"}>
<Avatar
src={StorageIcon["bucket"]}
size={"small"}
shape={"square"}
/>{" "}
<span
style={{
marginLeft: "10px",
fontWeight: "bolder",
}}>
{item.label}
</span>
</Card>
</>
);
}}
placeholder={"请选择存储桶"}></Select>
<Input
placeholder={"请输入路径/默认当前打开的路径"}
onChange={(e: any) => {
store.setUploadFilePath(e.target.value);
}}
style={{ marginLeft: 10, width: "40%" }}></Input>
</Flex>
</ProCard>
</Flex>
<ProCard>
<Dragger
name={"file"}
multiple={false}
directory={false}
maxCount={1}
defaultFileList={defaultFileList}
headers={{
ContentType: "multipart/form-data",
}}
onChange={handleOnChange}
customRequest={uploadFile}
onDrop={() => uploadFile}>
<p className="ant-upload-drag-icon">
<CloudUploadOutlined />
</p>
<p className="ant-upload-text"></p>
<p className="ant-upload-hint"></p>
</Dragger>
</ProCard>
</>
);
};
export default FileUpload;

View File

@@ -1,48 +1,47 @@
.file_main {
display: flex;
flex-direction: row;
justify-content: space-between;
.file_content_left {
width: 25%;
display: flex;
flex-direction: column;
}
.file_content_right {
width: 73%;
height: 75vh;
.file_right_content {
display: flex;
flex-wrap: wrap;
flex-direction: row;
margin-top: 20px;
.file_card:hover {
background-color: rgba(16, 15, 15, 0.08);
}
}
.file_right_header {
display: flex;
flex-direction: row;
align-items: center;
}
}
}
.file_name {
width: 65px;
text-align: center;
font-size: 12px;
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
-o-text-overflow: ellipsis;
}
.file_main {
display: flex;
flex-direction: row;
justify-content: space-between;
.file_content_left {
width: 25%;
display: flex;
flex-direction: column;
}
.file_content_right {
width: 73%;
height: 75vh;
.file_right_content {
display: flex;
flex-wrap: wrap;
flex-direction: row;
margin-top: 10px;
.file_card:hover {
background-color: rgba(16, 15, 15, 0.08);
}
}
.file_right_header {
display: flex;
flex-direction: column;
}
}
}
.file_name {
width: 65px;
text-align: center;
font-size: 12px;
margin-top: 5px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: inline-block;
-o-text-overflow: ellipsis;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,32 +1,42 @@
.home_content_main {
display: flex;
flex-direction: column;
}
.home_content_head {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.home_content_head_left {
height: 51vh;
width: 43%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
flex-wrap: wrap;
}
.home_content_list {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 30px;
}
.home_content_main {
display: flex;
flex-direction: column;
}
.home_content_head {
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
.home_content_head_left {
height: 50vh;
width: 43%;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
flex-wrap: wrap;
}
.home_content_list {
display: flex;
flex-direction: row;
justify-content: space-between;
margin-top: 30px;
}
.home_content_icon{
font-size: 20px;
color: lightgrey;
}
.home_content_icon:hover{
color: #ff6700;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,224 +1,429 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
endpoint: string;
accessKeyId: string;
accessKeySecret: string;
createdTime: string;
updatedTime: 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>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessKeySecret",
tooltip: "access key secret",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const AliSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddAliOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKeyId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="accessKeySecret"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="阿里云OSS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddAliOssConfigDrawer />
</>
);
};
export default AliSettings;
/** @format */
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,
Flex,
Form,
Input,
message,
Modal,
Row,
Space,
} from "antd";
import React, { useEffect, useRef, useState } from "react";
import {
addAliOSSConfig,
deleteAliConfig,
getAliConfigDetailById,
getAllAliOSSConfig,
initAliOSS,
setAliShutdown,
updateAliConfig,
} from "@/api/oss/ali";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
const AliSettings: React.FC = observer(() => {
const [form] = Form.useForm();
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const [openModal, setOpenModal] = useState(false);
const [configs, setConfigs] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
const [configDetail, setConfigDetail] = useState<any>({} as any);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
const columns: ProColumns<any[]>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
valueType: "text",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
editable: false,
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
copyable: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
copyable: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessKeySecret",
tooltip: "access key secret",
ellipsis: true,
copyable: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
editable: false,
},
{
title: "更新时间",
dataIndex: "updateTime",
valueType: "dateTime",
sorter: true,
editable: false,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
valueEnum: {
true: { text: "开启", status: "Success" },
false: { text: "关闭", status: "Error" },
},
editable: false,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: any, record: any, _, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a
target="_blank"
rel="noopener noreferrer"
key="view"
onClick={() => {
getConfigDetail(record.id).then(() => {
setOpenModal(true);
setLoading(false);
});
}}>
</a>,
<TableDropdown
key="actionGroup"
onSelect={(key: string) => {
if (key === "open") {
init(record.id).then();
} else if (key === "close") {
shutdown(record.id).then();
}
}}
menus={[
{ key: "open", name: "开启" },
{ key: "close", name: "关闭" },
]}
/>,
],
},
];
async function getAllConfig() {
getAllAliOSSConfig(userId).then((res: any) => {
if (res && res.success && res.data) {
setConfigs(res.data);
}
});
}
async function getConfigDetail(id: any) {
getAliConfigDetailById(id).then((res: any) => {
if (res && res.success && res.data) {
setConfigDetail(res.data);
}
});
}
async function init(id: any) {
initAliOSS(userId, id).then((res: any) => {
if (res && res.success) {
message.open({
content: "开启成功",
type: "success",
});
getAllConfig().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
async function shutdown(id: any) {
setAliShutdown(userId, id).then((res: any) => {
if (res && res.success) {
message.open({
content: res.data,
type: "success",
});
getAllConfig().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
async function deleteConfig(id: any) {
const form: any = {
id: id,
isDeleted: 1,
};
deleteAliConfig(form).then((res: any) => {
if (res && res.success) {
message.open({
content: "删除成功",
type: "success",
});
getAllConfig().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
async function addConfigs() {
const fieldsValue = form.getFieldsValue();
const AliOssConfig = {
userId: userId,
...fieldsValue,
};
addAliOSSConfig(AliOssConfig).then((res: any) => {
if (res && res.success) {
onClose();
getAllConfig().then(() => {
message
.open({
content: "新增成功",
type: "success",
})
.then();
});
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
useEffect(() => {
getAllConfig().then();
}, []);
const AddAliOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={addConfigs} type="primary">
</Button>
</Space>
}>
<Form layout="vertical" form={form}>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKeyId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="accessKeySecret"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ minHeight: "65vh" }}>
<ProTable
columns={columns}
dataSource={configs}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
onSave: async (__: any, originRow: any, _: any) => {
const updateForm: any = {
id: originRow.id,
endpoint: originRow.endpoint,
accessKeyId: originRow.accessKeyId,
accessKeySecret: originRow.accessKeySecret,
};
updateAliConfig(updateForm).then((res: any) => {
if (res && res.success) {
message.open({
content: "修改成功!",
type: "success",
});
getAllConfig().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
},
onDelete: async (row: any) => {
deleteConfig(row).then((res: any) => {
if (res && res.success) {
message.open({
content: "删除成功",
type: "success",
});
getAllConfig().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
},
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="阿里云OSS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddAliOssConfigDrawer />
<Modal
title={<p></p>}
loading={loading}
footer={false}
open={openModal}
afterClose={() => {
setConfigDetail({});
}}
onCancel={() => setOpenModal(false)}>
<Flex vertical={false} align={"center"}>
<h4>ID:</h4> <span style={{ marginLeft: 10 }}>{configDetail.id}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>endpoint: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.endpoint}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>accessKeyId: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.accessKeyId} </span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>accessKeySecret: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.accessKeySecret}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>status: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.status}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>createdTime: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.createdTime}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>updateTime: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.updateTime}</span>
</Flex>
</Modal>
</div>
</>
);
});
export default AliSettings;

View File

@@ -1,261 +1,265 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
bucketName: string;
accessKeyId: string;
secretAccessKey: string;
region: string;
mode: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "https://oss.aliyuncs.com",
accessKeyId: "LTAI5tG3",
secretAccessKey: "G3",
region: "2024-06-28 10:51:59",
mode: "2024-06-29 10:51:59",
createdTime: "2024-06-28 10:51:59",
updatedTime: "2024-06-29 10:51:59",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucket",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretAccessKey",
tooltip: "secret access key",
ellipsis: true,
},
{
disable: true,
title: "地区",
dataIndex: "region",
tooltip: "region",
ellipsis: true,
},
{
disable: true,
title: "模式",
dataIndex: "mode",
tooltip: "mode",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const AwsSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddAwsOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="region"
label="地区"
rules={[{ required: true, message: "请输入地区!" }]}>
<Input placeholder="请输入地区!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKeyId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretAccessKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="mode"
label="模式"
rules={[{ required: true, message: "请输入模式!" }]}>
<Input placeholder="请输入模式!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="亚马逊S3配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddAwsOssConfigDrawer />
</>
);
};
export default AwsSettings;
/** @format */
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";
type AwsOssConfigItem = {
id: number;
userId: number;
bucketName: string;
accessKeyId: string;
secretAccessKey: string;
region: string;
mode: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AwsOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "https://oss.aliyuncs.com",
accessKeyId: "LTAI5tG3",
secretAccessKey: "G3",
region: "2024-06-28 10:51:59",
mode: "2024-06-29 10:51:59",
createdTime: "2024-06-28 10:51:59",
updatedTime: "2024-06-29 10:51:59",
status: "正常",
},
];
const columns: ProColumns<AwsOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucket",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretAccessKey",
tooltip: "secret access key",
ellipsis: true,
},
{
disable: true,
title: "地区",
dataIndex: "region",
tooltip: "region",
ellipsis: true,
},
{
disable: true,
title: "模式",
dataIndex: "mode",
tooltip: "mode",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: AwsOssConfigItem, _, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const AwsSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddAwsOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="region"
label="地区"
rules={[{ required: true, message: "请输入地区!" }]}>
<Input placeholder="请输入地区!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKeyId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretAccessKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="mode"
label="模式"
rules={[{ required: true, message: "请输入模式!" }]}>
<Input placeholder="请输入模式!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<AwsOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="亚马逊S3配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddAwsOssConfigDrawer />
</div>
</>
);
};
export default AwsSettings;

View File

@@ -1,290 +1,294 @@
/** @format */
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, DatePicker, Drawer, Form, Input, Row, Select, Space } from "antd";
import React, { useRef, useState } from "react";
type AliOssConfigItem = {
id: number;
userId: number;
endpoint: string;
accessKeyId: string;
accessKeySecret: string;
created_time: string;
updated_time: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
endpoint: "https://oss.aliyuncs.com",
accessKeyId: "LTAI5tG3",
accessKeySecret: "G3",
created_time: "2022-01-01",
updated_time: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessKeySecret",
tooltip: "access key secret",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "date",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updateTime",
valueType: "date",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const BaiduSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddBaiduOssConfigDrawer = () => {
return (
<>
<Drawer
title="Create a new account"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}>Cancel</Button>
<Button onClick={onClose} type="primary">
Submit
</Button>
</Space>
}>
<Form layout="vertical" hideRequiredMark>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="name"
label="Name"
rules={[{ required: true, message: "Please enter user name" }]}>
<Input placeholder="Please enter user name" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="url"
label="Url"
rules={[{ required: true, message: "Please enter url" }]}>
<Input
style={{ width: "100%" }}
addonBefore="http://"
addonAfter=".com"
placeholder="Please enter url"
/>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="owner"
label="Owner"
rules={[{ required: true, message: "Please select an owner" }]}>
<Select placeholder="Please select an owner">
<Select.Option value="xiao">Xiaoxiao Fu</Select.Option>
<Select.Option value="mao">Maomao Zhou</Select.Option>
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="type"
label="Type"
rules={[{ required: true, message: "Please choose the type" }]}>
<Select placeholder="Please choose the type">
<Select.Option value="private">Private</Select.Option>
<Select.Option value="public">Public</Select.Option>
</Select>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="approver"
label="Approver"
rules={[
{ required: true, message: "Please choose the approver" },
]}>
<Select placeholder="Please choose the approver">
<Select.Option value="jack">Jack Ma</Select.Option>
<Select.Option value="tom">Tom Liu</Select.Option>
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="dateTime"
label="DateTime"
rules={[
{ required: true, message: "Please choose the dateTime" },
]}>
<DatePicker.RangePicker
style={{ width: "100%" }}
getPopupContainer={(trigger) => trigger.parentElement!}
/>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={24}>
<Form.Item
name="description"
label="Description"
rules={[
{
required: true,
message: "please enter url description",
},
]}>
<Input.TextArea
rows={4}
placeholder="please enter url description"
/>
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="百度云BOS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddBaiduOssConfigDrawer />
</>
);
};
export default BaiduSettings;
/** @format */
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, DatePicker, Drawer, Form, Input, Row, Select, Space } from "antd";
import React, { ReactNode, useRef, useState } from "react";
type BaiduOssConfigItem = {
id: number;
userId: number;
endpoint: string;
accessKeyId: string;
accessKeySecret: string;
created_time: string;
updated_time: string;
status: string;
};
const data: BaiduOssConfigItem[] = [
{
id: 1,
userId: 1,
endpoint: "https://oss.aliyuncs.com",
accessKeyId: "LTAI5tG3",
accessKeySecret: "G3",
created_time: "2022-01-01",
updated_time: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<BaiduOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessKeySecret",
tooltip: "access key secret",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "date",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updateTime",
valueType: "date",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: BaiduOssConfigItem, _, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const BaiduSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddBaiduOssConfigDrawer = () => {
return (
<>
<Drawer
title="Create a new account"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}>Cancel</Button>
<Button onClick={onClose} type="primary">
Submit
</Button>
</Space>
}>
<Form layout="vertical" hideRequiredMark>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="name"
label="Name"
rules={[{ required: true, message: "Please enter user name" }]}>
<Input placeholder="Please enter user name" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="url"
label="Url"
rules={[{ required: true, message: "Please enter url" }]}>
<Input
style={{ width: "100%" }}
addonBefore="http://"
addonAfter=".com"
placeholder="Please enter url"
/>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="owner"
label="Owner"
rules={[{ required: true, message: "Please select an owner" }]}>
<Select placeholder="Please select an owner">
<Select.Option value="xiao">Xiaoxiao Fu</Select.Option>
<Select.Option value="mao">Maomao Zhou</Select.Option>
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="type"
label="Type"
rules={[{ required: true, message: "Please choose the type" }]}>
<Select placeholder="Please choose the type">
<Select.Option value="private">Private</Select.Option>
<Select.Option value="public">Public</Select.Option>
</Select>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="approver"
label="Approver"
rules={[
{ required: true, message: "Please choose the approver" },
]}>
<Select placeholder="Please choose the approver">
<Select.Option value="jack">Jack Ma</Select.Option>
<Select.Option value="tom">Tom Liu</Select.Option>
</Select>
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="dateTime"
label="DateTime"
rules={[
{ required: true, message: "Please choose the dateTime" },
]}>
<DatePicker.RangePicker
style={{ width: "100%" }}
getPopupContainer={(trigger) => trigger.parentElement!}
/>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={24}>
<Form.Item
name="description"
label="Description"
rules={[
{
required: true,
message: "please enter url description",
},
]}>
<Input.TextArea
rows={4}
placeholder="please enter url description"
/>
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<BaiduOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="百度云BOS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddBaiduOssConfigDrawer />
</div>
</>
);
};
export default BaiduSettings;

View File

@@ -1,242 +1,246 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
bucketName: string;
endpoint: string;
accessKey: string;
secretKey: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "666",
endpoint: "https://oss.aliyuncs.com",
accessKey: "LTAI5tG3",
secretKey: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "access key",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secret key",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const HuawaiSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddHuaweiOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKeyId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="accessKeySecret"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="华为云OBS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddHuaweiOssConfigDrawer />
</>
);
};
export default HuawaiSettings;
/** @format */
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";
type HuaweiOssConfigItem = {
id: number;
userId: number;
bucketName: string;
endpoint: string;
accessKey: string;
secretKey: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: HuaweiOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "666",
endpoint: "https://oss.aliyuncs.com",
accessKey: "LTAI5tG3",
secretKey: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<HuaweiOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "access key",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secret key",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: HuaweiOssConfigItem, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const HuawaiSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddHuaweiOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKeyId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="accessKeySecret"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<HuaweiOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="华为云OBS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddHuaweiOssConfigDrawer />
</div>
</>
);
};
export default HuawaiSettings;

View File

@@ -1,244 +1,248 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
bucketName: number;
endpoint: string;
accessKey: string;
secretKey: string;
region: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: 666,
endpoint: "https://oss.aliyuncs.com",
accessKey: "LTAI5tG3",
secretKey: "G3",
region: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "access key",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secret key",
ellipsis: true,
},
{
disable: true,
title: "地区",
dataIndex: "region",
tooltip: "region",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const JdSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddJdOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="region"
label="地区"
rules={[{ required: true, message: "请输入地区!" }]}>
<Input placeholder="请输入地区!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKey"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="京东云OSS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddJdOssConfigDrawer />
</>
);
};
export default JdSettings;
/** @format */
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";
type JdOssConfigItem = {
id: number;
userId: number;
bucketName: number;
endpoint: string;
accessKey: string;
secretKey: string;
region: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: JdOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: 666,
endpoint: "https://oss.aliyuncs.com",
accessKey: "LTAI5tG3",
secretKey: "G3",
region: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<JdOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "access key",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secret key",
ellipsis: true,
},
{
disable: true,
title: "地区",
dataIndex: "region",
tooltip: "region",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: JdOssConfigItem, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const JdSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddJdOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="region"
label="地区"
rules={[{ required: true, message: "请输入地区!" }]}>
<Input placeholder="请输入地区!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKey"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<JdOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="京东云OSS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddJdOssConfigDrawer />
</div>
</>
);
};
export default JdSettings;

View File

@@ -1,278 +1,282 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
endpoint: string;
bucketName: string;
accessKeyId: string;
accessKeySecret: string;
region: string;
securityToken: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "6666",
endpoint: "https://oss.aliyuncs.com",
accessKeyId: "LTAI5tG3",
accessKeySecret: "G3",
region: "G3",
securityToken: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessKeySecret",
tooltip: "access key secret",
ellipsis: true,
},
{
disable: true,
title: "地区",
dataIndex: "region",
tooltip: "region",
ellipsis: true,
},
{
disable: true,
title: "令牌",
dataIndex: "securityToken",
tooltip: "security token",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const JinshanSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddJinshanOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKeyId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="accessKeySecret"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="securityToken"
label="令牌Token"
rules={[{ required: true, message: "请输入令牌Token!" }]}>
<Input placeholder="请输入令牌Token" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="region"
label="地区"
rules={[{ required: true, message: "请输入地区!" }]}>
<Input placeholder="请输入地区!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="金山OBS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddJinshanOssConfigDrawer />
</>
);
};
export default JinshanSettings;
/** @format */
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";
type JinshanOssConfigItem = {
id: number;
userId: number;
endpoint: string;
bucketName: string;
accessKeyId: string;
accessKeySecret: string;
region: string;
securityToken: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: JinshanOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "6666",
endpoint: "https://oss.aliyuncs.com",
accessKeyId: "LTAI5tG3",
accessKeySecret: "G3",
region: "G3",
securityToken: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<JinshanOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessKeySecret",
tooltip: "access key secret",
ellipsis: true,
},
{
disable: true,
title: "地区",
dataIndex: "region",
tooltip: "region",
ellipsis: true,
},
{
disable: true,
title: "令牌",
dataIndex: "securityToken",
tooltip: "security token",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: JinshanOssConfigItem, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const JinshanSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddJinshanOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKeyId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="accessKeySecret"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="securityToken"
label="令牌Token"
rules={[{ required: true, message: "请输入令牌Token!" }]}>
<Input placeholder="请输入令牌Token" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="region"
label="地区"
rules={[{ required: true, message: "请输入地区!" }]}>
<Input placeholder="请输入地区!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<JinshanOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="金山OBS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddJinshanOssConfigDrawer />
</div>
</>
);
};
export default JinshanSettings;

View File

@@ -1,225 +1,436 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
endpoint: string;
accessKey: string;
secretKey: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
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<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "access key",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secret key",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const MinioSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddMinioOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKey"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="MinIO配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddMinioOssConfigDrawer />
</>
);
};
export default MinioSettings;
/** @format */
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, Flex, Form, Input, message, Modal, Row, Space } from "antd";
import React, { ReactNode, useEffect, useRef, useState } from "react";
import {
addMinioOSSConfig,
deleteMinioConfig,
getAllMinioConfig,
getMinioConfigDetailById,
initMinioOSS,
setMinioShutdown,
updateMinioConfig,
} from "@/api/oss/minio";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
type MinioOssConfigItem = {
id: number;
userId: number;
endpoint: string;
accessKey: string;
secretKey: string;
createdTime: string;
updateTime: string;
status: string;
};
const MinioSettings: React.FC = observer(() => {
const [form] = Form.useForm();
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const [configs, setConfigs] = useState<MinioOssConfigItem[]>([]);
const [openModal, setOpenModal] = useState(false);
const [loading, setLoading] = useState<boolean>(true);
const [configDetail, setConfigDetail] = useState<any>({} as any);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
const columns: ProColumns<MinioOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
editable: false,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
editable: false,
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
copyable: true,
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "access key",
ellipsis: true,
copyable: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secret key",
ellipsis: true,
copyable: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
editable: false,
},
{
title: "更新时间",
dataIndex: "updateTime",
valueType: "dateTime",
sorter: true,
editable: false,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
valueEnum: {
true: { text: "开启", status: "Success" },
false: { text: "关闭", status: "Error" },
},
editable: false,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: any, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a
target="_blank"
rel="noopener noreferrer"
key="view"
onClick={() => {
getConfigDetail(record.id).then(() => {
setOpenModal(true);
setLoading(false);
});
}}>
</a>,
<TableDropdown
key="actionGroup"
onSelect={(key: string) => {
if (key === "open") {
init(record.id).then();
} else if (key === "close") {
shutdown(record.id).then();
}
}}
menus={[
{ key: "open", name: "开启" },
{ key: "close", name: "关闭" },
]}
/>,
],
},
];
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
async function getConfigDetail(id: any) {
getMinioConfigDetailById(id).then((res: any) => {
if (res && res.success && res.data) {
setConfigDetail(res.data);
}
});
}
async function init(id: any) {
initMinioOSS(userId, id).then((res: any) => {
if (res && res.success) {
message.open({
content: "开启成功",
type: "success",
});
getAllConfig().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
async function shutdown(id: any) {
setMinioShutdown(userId, id).then((res: any) => {
if (res && res.success) {
message.open({
content: res.data,
type: "success",
});
getAllConfig().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
async function deleteConfig(id: any) {
const form: any = {
id: id,
isDeleted: 1,
};
deleteMinioConfig(form).then((res: any) => {
if (res && res.success) {
message.open({
content: "删除成功",
type: "success",
});
getAllConfig().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
async function getAllConfig() {
getAllMinioConfig(userId).then((res: any) => {
if (res && res.success && res.data) {
setConfigs(res.data);
}
});
}
async function addMinioConfig() {
const fieldsValue = form.getFieldsValue();
const MinioOssConfig = {
userId: userId,
...fieldsValue,
};
addMinioOSSConfig(MinioOssConfig).then((res: any) => {
if (res && res.success) {
message.open({
content: "新增成功",
type: "success",
});
getAllConfig().then(() => {
onClose();
});
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
useEffect(() => {
getAllConfig().then();
}, []);
const AddMinioOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={"45%"}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={addMinioConfig} type="primary">
</Button>
</Space>
}>
<Form layout="vertical" form={form}>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKey"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ minHeight: "65vh" }}>
<ProTable<MinioOssConfigItem>
columns={columns}
dataSource={configs}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
onSave: async (__: any, originRow: any, _: any) => {
const updateForm: any = {
id: originRow.id,
endpoint: originRow.endpoint,
accessKey: originRow.accessKey,
secretKey: originRow.secretKey,
};
updateMinioConfig(updateForm).then((res: any) => {
if (res && res.success) {
message.open({
content: "修改成功!",
type: "success",
});
getAllConfig().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
},
onDelete: async (row: any) => {
deleteConfig(row).then((res: any) => {
if (res && res.success) {
message.open({
content: "删除成功",
type: "success",
});
getAllConfig().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
},
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="MinIO配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddMinioOssConfigDrawer />
<Modal
title={<p></p>}
loading={loading}
footer={false}
afterClose={() => {
setConfigDetail({});
}}
open={openModal}
onCancel={() => setOpenModal(false)}>
<Flex vertical={false} align={"center"}>
<h4>ID:</h4> <span style={{ marginLeft: 10 }}>{configDetail.id}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>endpoint: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.endpoint}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>accessKey: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.accessKey} </span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>secretKey: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.secretKey}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>status: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.status}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>createdTime: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.createdTime}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>updateTime: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.updateTime}</span>
</Flex>
</Modal>
</div>
</>
);
});
export default MinioSettings;

View File

@@ -1,225 +1,229 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
endpoint: string;
accessKeyId: string;
accessKeySecret: string;
created_time: string;
updated_time: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
endpoint: "https://oss.aliyuncs.com",
accessKeyId: "LTAI5tG3",
accessKeySecret: "G3",
created_time: "2022-01-01",
updated_time: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessKeySecret",
tooltip: "access key secret",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updateTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const PinanSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddPinanOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKeyId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="accessKeySecret"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="平安云OSS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddPinanOssConfigDrawer />
</>
);
};
export default PinanSettings;
/** @format */
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";
type PinanOssConfigItem = {
id: number;
userId: number;
endpoint: string;
accessKeyId: string;
accessKeySecret: string;
created_time: string;
updated_time: string;
status: string;
};
const data: PinanOssConfigItem[] = [
{
id: 1,
userId: 1,
endpoint: "https://oss.aliyuncs.com",
accessKeyId: "LTAI5tG3",
accessKeySecret: "G3",
created_time: "2022-01-01",
updated_time: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<PinanOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessKeySecret",
tooltip: "access key secret",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updateTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: PinanOssConfigItem, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const PinanSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddPinanOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKeyId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="accessKeySecret"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<PinanOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="平安云OSS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddPinanOssConfigDrawer />
</div>
</>
);
};
export default PinanSettings;

View File

@@ -1,254 +1,258 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
zone: string;
endpoint: string;
accessKey: string;
bucketName: string;
accessSecret: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "1",
zone: "1",
endpoint: "https://oss.aliyuncs.com",
accessKey: "LTAI5tG3",
accessSecret: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "地区",
dataIndex: "zone",
tooltip: "zone",
ellipsis: true,
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "access Key",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessSecret",
tooltip: "access Secret",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const QingyunSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddQingyunOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKey"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="accessSecret"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="zone"
label="地区"
rules={[{ required: true, message: "请输入地区!" }]}>
<Input placeholder="请输入地区!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="青云OSS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddQingyunOssConfigDrawer />
</>
);
};
export default QingyunSettings;
/** @format */
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";
type QingyunOssConfigItem = {
id: number;
userId: number;
zone: string;
endpoint: string;
accessKey: string;
bucketName: string;
accessSecret: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: QingyunOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "1",
zone: "1",
endpoint: "https://oss.aliyuncs.com",
accessKey: "LTAI5tG3",
accessSecret: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<QingyunOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "地区",
dataIndex: "zone",
tooltip: "zone",
ellipsis: true,
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "access Key",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessSecret",
tooltip: "access Secret",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: QingyunOssConfigItem, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const QingyunSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddQingyunOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKey"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="accessSecret"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="zone"
label="地区"
rules={[{ required: true, message: "请输入地区!" }]}>
<Input placeholder="请输入地区!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<QingyunOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="青云OSS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddQingyunOssConfigDrawer />
</div>
</>
);
};
export default QingyunSettings;

View File

@@ -1,225 +1,445 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
bucketName: string;
accessKey: string;
secretKey: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
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<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKeyId",
tooltip: "access key id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "accessKeySecret",
tooltip: "access key secret",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const QiniuSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddQiniuOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKey"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="七牛Kodo配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddQiniuOssConfigDrawer />
</>
);
};
export default QiniuSettings;
/** @format */
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, Flex, Form, Input, message, Modal, Row, Space } from "antd";
import React, { ReactNode, useEffect, useRef, useState } from "react";
import {
addQiniuOSSConfig,
deleteQiniuConfig,
getAllQiniuConfigs,
getQiniuConfigDetailById,
initQiniuOSS,
setQiniuShutdown,
updateQiniuConfig,
} from "@/api/oss/qiniu";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
type QiniuOssConfigItem = {
id: number;
userId: number;
bucketName: string;
accessKey: string;
secretKey: string;
createdTime: string;
updateTime: string;
status: string;
};
const QiniuSettings: React.FC = observer(() => {
const [form] = Form.useForm();
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const [config, setConfig] = useState<QiniuOssConfigItem[]>([]);
const [openModal, setOpenModal] = useState(false);
const [loading, setLoading] = useState<boolean>(true);
const [configDetail, setConfigDetail] = useState<any>({} as any);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
const columns: ProColumns<QiniuOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
editable: false,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
editable: false,
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
copyable: true,
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "access key id",
copyable: true,
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "access key secret",
copyable: true,
ellipsis: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
editable: false,
},
{
title: "更新时间",
dataIndex: "updateTime",
valueType: "dateTime",
sorter: true,
editable: false,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
valueEnum: {
true: { text: "开启", status: "Success" },
false: { text: "关闭", status: "Error" },
},
editable: false,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: QiniuOssConfigItem, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a
target="_blank"
rel="noopener noreferrer"
key="view"
onClick={() => {
getConfigDetail(record.id).then(() => {
setOpenModal(true);
setLoading(false);
});
}}>
</a>,
<TableDropdown
key="actionGroup"
onSelect={(key: string) => {
if (key === "open") {
init(record.id).then();
} else if (key === "close") {
shutdown(record.id).then();
}
}}
menus={[
{ key: "open", name: "开启" },
{ key: "close", name: "关闭" },
]}
/>,
],
},
];
async function init(id: any) {
initQiniuOSS(userId, id).then((res: any) => {
if (res && res.success) {
message.open({
content: "开启成功",
type: "success",
});
getAllConfigs().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
async function getConfigDetail(id: any) {
getQiniuConfigDetailById(id).then((res: any) => {
if (res && res.success && res.data) {
setConfigDetail(res.data);
}
});
}
async function shutdown(id: any) {
setQiniuShutdown(userId, id).then((res: any) => {
if (res && res.success) {
message.open({
content: res.data,
type: "success",
});
getAllConfigs().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
async function deleteConfig(id: any) {
const form: any = {
id: id,
isDeleted: 1,
};
deleteQiniuConfig(form).then((res: any) => {
if (res && res.success) {
message.open({
content: "删除成功",
type: "success",
});
getAllConfigs().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
async function getAllConfigs() {
getAllQiniuConfigs(userId).then((res: any) => {
if (res && res.success && res.data) {
setConfig(res.data);
}
});
}
async function addQiniuoConfig() {
const fieldsValue = form.getFieldsValue();
const QiniuOssConfig = {
userId: userId,
...fieldsValue,
};
addQiniuOSSConfig(QiniuOssConfig).then((res: any) => {
if (res && res.success) {
message.open({
content: "新增成功",
type: "success",
});
getAllConfigs().then(() => {
onClose();
});
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
useEffect(() => {
getAllConfigs().then();
}, []);
const AddQiniuOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={"45%"}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={addQiniuoConfig} type="primary">
</Button>
</Space>
}>
<Form layout="vertical" form={form}>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKey"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<QiniuOssConfigItem>
columns={columns}
dataSource={config}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
onSave: async (__: any, originRow: any, _: any) => {
const updateForm: any = {
id: originRow.id,
endpoint: originRow.endpoint,
accessKey: originRow.accessKey,
secretKey: originRow.secretKey,
};
updateQiniuConfig(updateForm).then((res: any) => {
if (res && res.success) {
message.open({
content: "修改成功!",
type: "success",
});
getAllConfigs().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
},
onDelete: async (row: any) => {
deleteConfig(row).then((res: any) => {
if (res && res.success) {
message.open({
content: "删除成功",
type: "success",
});
getAllConfigs().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
},
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="七牛Kodo配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddQiniuOssConfigDrawer />
<Modal
title={<p></p>}
loading={loading}
afterClose={() => {
setConfigDetail({});
}}
footer={false}
open={openModal}
onCancel={() => setOpenModal(false)}>
<Flex vertical={false} align={"center"}>
<h4>ID:</h4> <span style={{ marginLeft: 10 }}>{configDetail.id}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>endpoint: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.endpoint}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>accessKey: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.accessKey} </span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>secretKey: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.secretKey}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>status: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.status}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>createdTime: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.createdTime}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>updateTime: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.updateTime}</span>
</Flex>
</Modal>
</div>
</>
);
});
export default QiniuSettings;

View File

@@ -1,215 +1,470 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
bucketName: string;
secretId: string;
secretKey: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
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<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "secretId",
tooltip: "secret Id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secret Key",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const TencentSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddTencentOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="secretId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="腾讯云COS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddTencentOssConfigDrawer />
</>
);
};
export default TencentSettings;
/** @format */
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, Flex, Form, Input, message, Modal, Row, Space } from "antd";
import React, { ReactNode, useEffect, useRef, useState } from "react";
import {
addTencentOSSConfig,
deleteTencentConfig,
getAllTencentOSsConfig,
getTencentConfigDetailById,
initTencentOSS,
setTencentShutdown,
updateTencentConfig,
} from "@/api/oss/tencent";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
type TencentOssConfigItem = {
id: number;
userId: number;
endpoint: number;
secretId: string;
secretKey: string;
appId: string;
region: string;
createdTime: string;
updateTime: string;
status: string;
};
const TencentSettings: React.FC = observer(() => {
const [form] = Form.useForm();
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const [configs, setConfigs] = useState<TencentOssConfigItem[]>([]);
const [openModal, setOpenModal] = useState(false);
const [loading, setLoading] = useState<boolean>(true);
const [configDetail, setConfigDetail] = useState<any>({} as any);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
const columns: ProColumns<TencentOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
editable: false,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
editable: false,
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
copyable: true,
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "secretId",
copyable: true,
tooltip: "secret Id",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secret Key",
copyable: true,
ellipsis: true,
},
{
disable: true,
title: "appId",
dataIndex: "appId",
tooltip: "appId",
copyable: true,
ellipsis: true,
},
{
disable: true,
title: "地域",
dataIndex: "region",
tooltip: "region",
copyable: true,
ellipsis: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
editable: false,
},
{
title: "更新时间",
dataIndex: "updateTime",
valueType: "dateTime",
sorter: true,
editable: false,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
valueEnum: {
true: { text: "开启", status: "Success" },
false: { text: "关闭", status: "Error" },
},
editable: false,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: TencentOssConfigItem, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a
target="_blank"
rel="noopener noreferrer"
key="view"
onClick={() => {
getConfigDetail(record.id).then(() => {
setOpenModal(true);
setLoading(false);
});
}}>
</a>,
<TableDropdown
key="actionGroup"
onSelect={(key: string) => {
if (key === "open") {
init(record.id).then();
} else if (key === "close") {
shutdown(record.id).then();
}
}}
menus={[
{ key: "open", name: "开启" },
{ key: "close", name: "关闭" },
]}
/>,
],
},
];
async function init(id: any) {
initTencentOSS(userId, id).then((res: any) => {
if (res && res.success) {
message.open({
content: "开启成功",
type: "success",
});
getAllConfigs().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
async function getConfigDetail(id: any) {
getTencentConfigDetailById(id).then((res: any) => {
if (res && res.success && res.data) {
setConfigDetail(res.data);
}
});
}
async function shutdown(id: any) {
setTencentShutdown(userId, id).then((res: any) => {
if (res && res.success) {
message.open({
content: res.data,
type: "success",
});
getAllConfigs().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
async function deleteConfig(id: any) {
const form: any = {
id: id,
isDeleted: 1,
};
deleteTencentConfig(form).then((res: any) => {
if (res && res.success) {
message.open({
content: "删除成功",
type: "success",
});
getAllConfigs().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
async function getAllConfigs() {
getAllTencentOSsConfig(userId).then((res: any) => {
if (res && res.success && res.data) {
setConfigs(res.data);
}
});
}
async function addTencentConfig() {
const fieldsValue = form.getFieldsValue();
const TencentOssConfig = {
userId: userId,
...fieldsValue,
};
addTencentOSSConfig(TencentOssConfig).then((res: any) => {
if (res && res.success) {
message.open({
content: "新增成功",
type: "success",
});
getAllConfigs().then(() => {
onClose();
});
} else {
message.open({
content: res.data,
type: "error",
});
}
});
}
useEffect(() => {
getAllConfigs().then();
}, []);
const AddTencentOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={addTencentConfig} type="primary">
</Button>
</Space>
}>
<Form layout="vertical" form={form}>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="secretId"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="appId"
label="appId"
rules={[{ required: true, message: "请输入appID!" }]}>
<Input placeholder="请输入appID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="region"
label="地区"
rules={[{ required: true, message: "请输入地区!" }]}>
<Input placeholder="请输入地区!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<TencentOssConfigItem>
columns={columns}
dataSource={configs}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
onSave: async (__: any, originRow: any, _: any) => {
const updateForm: any = {
id: originRow.id,
endpoint: originRow.endpoint,
secretId: originRow.secretId,
secretKey: originRow.secretKey,
appId: originRow.appId,
region: originRow.region,
};
updateTencentConfig(updateForm).then((res: any) => {
if (res && res.success) {
message.open({
content: "修改成功!",
type: "success",
});
getAllConfigs().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
},
onDelete: async (row: any) => {
deleteConfig(row).then((res: any) => {
if (res && res.success) {
message.open({
content: "删除成功",
type: "success",
});
getAllConfigs().then();
} else {
message.open({
content: res.data,
type: "error",
});
}
});
},
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="腾讯云COS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddTencentOssConfigDrawer />
<Modal
title={<p></p>}
loading={loading}
footer={false}
open={openModal}
afterClose={() => {
setConfigDetail({});
}}
onCancel={() => setOpenModal(false)}>
<Flex vertical={false} align={"center"}>
<h4>ID:</h4> <span style={{ marginLeft: 10 }}>{configDetail.id}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>endpoint: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.endpoint}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>secretId: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.secretId} </span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>secretKey: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.secretKey}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>appId: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.appId}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>region: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.region}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>status: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.status}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>createdTime: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.createdTime}</span>
</Flex>
<Flex vertical={false} align={"center"}>
<h4>updateTime: </h4>{" "}
<span style={{ marginLeft: 10 }}>{configDetail.updateTime}</span>
</Flex>
</Modal>
</div>
</>
);
});
export default TencentSettings;

View File

@@ -1,242 +1,246 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
bucketName: string;
publicKey: string;
privateKey: string;
customHost: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "https://oss.aliyuncs.com",
publicKey: "LTAI5tG3",
privateKey: "G3",
customHost: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "公钥",
dataIndex: "publicKey",
tooltip: "publicKey",
ellipsis: true,
},
{
disable: true,
title: "私钥",
dataIndex: "privateKey",
tooltip: "privateKey",
ellipsis: true,
},
{
disable: true,
title: "服务地址",
dataIndex: "customHost",
tooltip: "customHost",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const UcloudSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddUcloudOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="customHost"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="publicKey"
label="公钥"
rules={[{ required: true, message: "请输入公钥!" }]}>
<Input placeholder="请输入公钥!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="privateKey"
label="私钥"
rules={[{ required: true, message: "请输入私钥!" }]}>
<Input placeholder="请输入私钥!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="UCloud US3配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddUcloudOssConfigDrawer />
</>
);
};
export default UcloudSettings;
/** @format */
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";
type UcloudOssConfigItem = {
id: number;
userId: number;
bucketName: string;
publicKey: string;
privateKey: string;
customHost: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: UcloudOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "https://oss.aliyuncs.com",
publicKey: "LTAI5tG3",
privateKey: "G3",
customHost: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<UcloudOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "公钥",
dataIndex: "publicKey",
tooltip: "publicKey",
ellipsis: true,
},
{
disable: true,
title: "私钥",
dataIndex: "privateKey",
tooltip: "privateKey",
ellipsis: true,
},
{
disable: true,
title: "服务地址",
dataIndex: "customHost",
tooltip: "customHost",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: UcloudOssConfigItem, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const UcloudSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddUcloudOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="customHost"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="publicKey"
label="公钥"
rules={[{ required: true, message: "请输入公钥!" }]}>
<Input placeholder="请输入公钥!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="privateKey"
label="私钥"
rules={[{ required: true, message: "请输入私钥!" }]}>
<Input placeholder="请输入私钥!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<UcloudOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="UCloud US3配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddUcloudOssConfigDrawer />
</div>
</>
);
};
export default UcloudSettings;

View File

@@ -1,225 +1,229 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
bucketName: string;
userName: string;
password: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "https://oss.aliyuncs.com",
userName: "LTAI5tG3",
password: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "用户名",
dataIndex: "userName",
tooltip: "userName",
ellipsis: true,
},
{
disable: true,
title: "密码",
dataIndex: "password",
tooltip: "password",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const UpSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddUpOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="userName"
label="用户名"
rules={[{ required: true, message: "请输入用户名!" }]}>
<Input placeholder="请输入用户名!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="password"
label="密码"
rules={[{ required: true, message: "请输入密码!" }]}>
<Input placeholder="请输入密码!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="又拍云USS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddUpOssConfigDrawer />
</>
);
};
export default UpSettings;
/** @format */
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";
type UpOssConfigItem = {
id: number;
userId: number;
bucketName: string;
userName: string;
password: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: UpOssConfigItem[] = [
{
id: 1,
userId: 1,
bucketName: "https://oss.aliyuncs.com",
userName: "LTAI5tG3",
password: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<UpOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "用户名",
dataIndex: "userName",
tooltip: "userName",
ellipsis: true,
},
{
disable: true,
title: "密码",
dataIndex: "password",
tooltip: "password",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: UpOssConfigItem, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const UpSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddUpOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="userName"
label="用户名"
rules={[{ required: true, message: "请输入用户名!" }]}>
<Input placeholder="请输入用户名!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="password"
label="密码"
rules={[{ required: true, message: "请输入密码!" }]}>
<Input placeholder="请输入密码!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<UpOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="又拍云USS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddUpOssConfigDrawer />
</div>
</>
);
};
export default UpSettings;

View File

@@ -1,242 +1,246 @@
/** @format */
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";
type AliOssConfigItem = {
id: number;
userId: number;
endpoint: string;
bucketName: string;
accessKey: string;
secretKey: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: AliOssConfigItem[] = [
{
id: 1,
userId: 1,
endpoint: "https://oss.aliyuncs.com",
bucketName: "https://oss.aliyuncs.com",
accessKey: "LTAI5tG3",
secretKey: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<AliOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "accessKey",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secretKey",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text, record, _, action) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const WangyiSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddWangyiOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKey"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<ProTable<AliOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={{
pageSize: 5,
}}
dateFormatter="string"
headerTitle="阿里云OSS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddWangyiOssConfigDrawer />
</>
);
};
export default WangyiSettings;
/** @format */
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";
type WangyiOssConfigItem = {
id: number;
userId: number;
endpoint: string;
bucketName: string;
accessKey: string;
secretKey: string;
createdTime: string;
updatedTime: string;
status: string;
};
const data: WangyiOssConfigItem[] = [
{
id: 1,
userId: 1,
endpoint: "https://oss.aliyuncs.com",
bucketName: "https://oss.aliyuncs.com",
accessKey: "LTAI5tG3",
secretKey: "G3",
createdTime: "2022-01-01",
updatedTime: "2022-01-01",
status: "正常",
},
];
const columns: ProColumns<WangyiOssConfigItem>[] = [
{
dataIndex: "index",
valueType: "indexBorder",
width: 48,
},
{
title: "ID",
dataIndex: "id",
copyable: true,
ellipsis: true,
tooltip: "Id",
},
{
disable: true,
title: "服务地址",
dataIndex: "endpoint",
tooltip: "endpoint",
ellipsis: true,
},
{
disable: true,
title: "存储桶",
dataIndex: "bucketName",
tooltip: "bucketName",
ellipsis: true,
},
{
disable: true,
title: "密钥ID",
dataIndex: "accessKey",
tooltip: "accessKey",
ellipsis: true,
},
{
disable: true,
title: "密钥值",
dataIndex: "secretKey",
tooltip: "secretKey",
ellipsis: true,
},
{
disable: true,
title: "状态",
dataIndex: "status",
search: true,
},
{
title: "创建时间",
dataIndex: "createdTime",
valueType: "dateTime",
sorter: true,
hideInSearch: true,
},
{
title: "更新时间",
dataIndex: "updatedTime",
valueType: "dateTime",
sorter: true,
},
{
title: "操作",
valueType: "option",
key: "option",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (text: ReactNode, record: WangyiOssConfigItem, _: number, action: any) => [
<a
key="editable"
onClick={() => {
action?.startEditable?.(record.id);
}}>
</a>,
<a target="_blank" rel="noopener noreferrer" key="view">
</a>,
<TableDropdown
key="actionGroup"
onSelect={() => action?.reload()}
menus={[
{ key: "copy", name: "复制" },
{ key: "delete", name: "删除" },
]}
/>,
],
},
];
const WangyiSettings: React.FC = () => {
const actionRef = useRef<ActionType>();
const [open, setOpen] = useState(false);
const showDrawer = () => {
setOpen(true);
};
const onClose = () => {
setOpen(false);
};
const AddWangyiOssConfigDrawer = () => {
return (
<>
<Drawer
title="创建连接配置"
width={720}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
extra={
<Space>
<Button onClick={onClose}></Button>
<Button onClick={onClose} type="primary">
</Button>
</Space>
}>
<Form layout="vertical">
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="endpoint"
label="服务地址"
rules={[{ required: true, message: "请输入服务地址!" }]}>
<Input placeholder="请输入服务地址!" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="bucketName"
label="存储桶"
rules={[{ required: true, message: "请输入存储桶!" }]}>
<Input placeholder="请输入存储桶!" />
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
<Form.Item
name="accessKey"
label="密钥ID"
rules={[{ required: true, message: "请输入密钥ID!" }]}>
<Input placeholder="请输入密钥ID" />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
name="secretKey"
label="密钥值"
rules={[{ required: true, message: "请输入密钥值!" }]}>
<Input placeholder="请输入密钥值!" />
</Form.Item>
</Col>
</Row>
</Form>
</Drawer>
</>
);
};
return (
<>
<div style={{ height: "65vh" }}>
<ProTable<WangyiOssConfigItem>
columns={columns}
dataSource={data}
actionRef={actionRef}
cardBordered={true}
editable={{
type: "multiple",
}}
columnsState={{
persistenceKey: "pro-table-singe-demos",
persistenceType: "localStorage",
defaultValue: {
option: { fixed: "right", disable: true },
},
}}
rowKey="id"
search={false}
options={{
setting: {
listsHeight: 400,
},
}}
pagination={
{
pageSize: 5,
} as any
}
dateFormatter="string"
headerTitle="阿里云OSS配置"
bordered={false}
toolBarRender={() => [
<Button
key="button"
icon={<PlusOutlined />}
onClick={() => {
showDrawer();
}}
type="primary">
</Button>,
]}
/>
<AddWangyiOssConfigDrawer />
</div>
</>
);
};
export default WangyiSettings;

View File

@@ -1,60 +0,0 @@
/** @format */
const selectOptions = [
{
name: "阿里云OSS",
value: "ali",
},
{
name: "腾讯云COS",
value: "tencent",
},
{
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: "七牛云Kodo",
value: "qiniu",
},
{
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

@@ -1,9 +1,10 @@
.settings_container{
height: 75vh;
}
.settings_header{
display: flex;
flex-direction: row;
justify-content: space-between;
}
.settings_container{
width: 100%;
height: 100%;
}
.settings_header{
display: flex;
flex-direction: row;
justify-content: space-between;
}

View File

@@ -5,9 +5,10 @@ import { Avatar, Card, Empty, Select } from "antd";
import styles from "./index.module.less";
import { Outlet, useLocation, useNavigate } from "react-router-dom";
import { Suspense } from "react";
import selectOptions from "@/components/Main/Settings/defaultSettings.ts";
import StorageIcon from "@/context/stroage-icon.ts";
export default () => {
import selectOptions from "@/components/Main/Settings/settings.ts";
import StorageIcon from "@/constant/stroage-icon.ts";
import { observer } from "mobx-react";
export default observer(() => {
const navigate = useNavigate();
const location = useLocation();
return (
@@ -27,10 +28,13 @@ export default () => {
onSelect={(value: any) => {
navigate("/main/setting/" + value);
}}
placeholder={"请选择存储商"}>
{selectOptions.map((storage: any, index: any) => {
fieldNames={{
label: "name",
value: "value",
}}
labelRender={(label: any) => {
return (
<Select.Option value={storage.value} key={index}>
<>
<Card
bordered={false}
style={{
@@ -40,25 +44,50 @@ export default () => {
flexDirection: "row",
}}
size={"small"}>
<Avatar src={StorageIcon[storage.value]} size={"small"} />{" "}
<Avatar src={StorageIcon[label.value]} size={"small"} />
<span
style={{
marginLeft: "10px",
fontWeight: "bolder",
}}>
{storage.name}
{label.label}
</span>
</Card>
</Select.Option>
</>
);
})}
</Select>
}}
options={selectOptions}
optionRender={(item: any) => {
return (
<>
<Card
bordered={false}
style={{
height: 35,
display: "flex",
alignItems: "center",
flexDirection: "row",
}}
size={"small"}>
<Avatar src={StorageIcon[item.value]} size={"small"} />
<span
style={{
marginLeft: "10px",
fontWeight: "bolder",
}}>
{item.label}
</span>
</Card>
</>
);
}}
placeholder={"请选择存储商"}></Select>
</div>
</ProCard>
<ProCard style={{ marginTop: 20, height: "60vh" }} bordered boxShadow>
<ProCard style={{ marginTop: 20, height: "100%" }} bordered boxShadow>
{location.pathname === "/main/setting" || location.pathname === "/main/setting/" ? (
<>
<Empty description={"请选择存储商"} />
<Empty description={"请选择存储商"} style={{ height: "65vh" }} />
</>
) : (
<>
@@ -70,4 +99,4 @@ export default () => {
</ProCard>
</div>
);
};
});

View File

@@ -0,0 +1,60 @@
/** @format */
const selectOptions = [
{
name: "阿里云OSS",
value: "ali",
},
{
name: "腾讯云COS",
value: "tencent",
},
// {
// 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: "七牛云Kodo",
value: "qiniu",
},
// {
// 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

@@ -0,0 +1,377 @@
/** @format */
import React, { useEffect, useRef, useState } from "react";
import { AiEditor } from "aieditor";
import "aieditor/dist/style.css";
import { useNavigate } from "react-router-dom";
import styles from "./index.module.less";
import { ProCard } from "@ant-design/pro-components";
import type { ColorPickerProps } from "antd";
import {
Button,
Card,
Col,
ColorPicker,
Divider,
Flex,
Form,
FormListFieldData,
FormProps,
Input,
message,
Row,
Select,
theme,
} from "antd";
import { CloseOutlined, LeftOutlined, MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
import selectOptions from "@/components/Main/Settings/settings.ts";
import { addShareDetail } from "@/api/share";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
import { cyan, generate, green, presetPalettes, red } from "@ant-design/colors";
type Presets = Required<ColorPickerProps>["presets"][number];
const ShareAdd: React.FunctionComponent = () => {
const navigate = useNavigate();
const divRef = useRef(null);
const [form] = Form.useForm();
const [isDisabled, setIsDisabled] = useState(false);
const store = useStore("share");
const userStore = useStore("user");
const userId: any = userStore.getUserId();
const onFinish: FormProps["onFinish"] = (values) => {
const formData: any = {
circleId: store.getCircleId(),
userId: userId,
...values,
};
addShareDetail(formData).then((res: any) => {
if (res && res.success) {
message
.open({
content: "新增成功",
type: "success",
})
.then();
} else {
message
.open({
content: "新增失败",
type: "warning",
})
.then();
}
});
};
const genPresets = (presets: any = presetPalettes) =>
Object.entries(presets).map<Presets>(([label, colors]: [label: any, colors: any]) => ({
label,
colors,
}));
const HorizontalLayoutDemo = () => {
const { token } = theme.useToken();
const presets = genPresets({
primary: generate(token.colorPrimary),
red,
green,
cyan,
});
const customPanelRender: ColorPickerProps["panelRender"] = (
_,
{ components: { Picker, Presets } },
) => (
<Row justify="space-between" wrap={false}>
<Col span={12}>
<Presets />
</Col>
<Divider type="vertical" style={{ height: "auto" }} />
<Col flex="auto">
<Picker />
</Col>
</Row>
);
return (
<ColorPicker
defaultValue={token.colorPrimary}
styles={{ popupOverlayInner: { width: 480 } }}
presets={presets}
panelRender={customPanelRender}
/>
);
};
useEffect(() => {
if (divRef.current) {
const aiEditor = new AiEditor({
element: divRef.current,
placeholder: "点击输入描述...",
contentRetention: true,
textSelectionBubbleMenu: {
enable: true,
items: ["ai", "Bold", "Italic", "Underline", "Strike", "code", "comment"],
},
ai: {
models: {
wenxin: {
access_token: "****",
protocol: "ws",
version: "v3.5",
},
},
},
onChange: async (value: any) => {
form.setFieldValue("content" as any, value.getHtml());
},
} as any);
return () => {
aiEditor.destroy();
};
}
}, []);
return (
<>
<div className={styles.share_add_main}>
<ProCard bordered={true}>
<Flex vertical={false} align={"center"}>
<Button
shape="circle"
icon={<LeftOutlined />}
onClick={() => {
navigate("/main/share/list/" + store.getCircleId());
}}
/>
<Flex
vertical={false}
align={"center"}
justify={"center"}
style={{ width: "90%" }}>
<h3></h3>
</Flex>
</Flex>
</ProCard>
<div className={styles.share_add_content}>
<Form
onFinish={onFinish}
autoComplete="off"
form={form}
initialValues={{ color: "#1677ff" }}>
<Form.Item
label={
<>
<h4></h4>
</>
}
name="title"
id={"title"}
rules={[{ required: true, message: "请输入标题" }]}>
<Input name="title" maxLength={50} showCount></Input>
</Form.Item>
<Form.Item
label={
<>
<h4></h4>
</>
}
id={"icon"}
name="icon"
rules={[{ required: true, message: "请输入图标" }]}>
<Input name="icon"></Input>
</Form.Item>
<Form.Item
label={
<>
<h4></h4>
</>
}
id={"description"}
name="description"
rules={[{ required: true, message: "请输入摘要" }]}>
<Input name="description" maxLength={100} showCount></Input>
</Form.Item>
<Form.Item
label={
<>
<h4></h4>
</>
}
rules={[{ required: true, message: "请输入介绍" }]}
name="content"
id={"content"}>
<div
ref={divRef}
style={{ height: "300px", maxWidth: "100%", minWidth: "100%" }}
/>
</Form.Item>
<Form.List
name="tags"
rules={[
{
validator: async (_, tags) => {
if (!tags) {
return Promise.reject(new Error("请至少填写一个标签"));
}
if (tags.length >= 4) {
setIsDisabled(true);
return Promise.reject(
new Error("最多只能添加三个标签"),
);
}
},
},
]}>
{(fields: FormListFieldData[], { add, remove }, { errors }) => (
<>
{fields.map((field: FormListFieldData, index: number) => (
<Flex vertical={false} align={"center"} key={index}>
<Form.Item
required={true}
label={
<>
<h4>{"标签" + (index + 1)}</h4>
</>
}
key={index}
id={"tags"}>
<Flex vertical={false} align={"center"}>
<Form.Item
validateTrigger={["onChange", "onBlur"]}
name={[field.name, "tagName"] as any}
noStyle>
<Input
placeholder="请输入标签"
maxLength={10}
showCount
style={{ width: "250px" }}
/>
</Form.Item>
<Form.Item
validateTrigger={["onChange", "onBlur"]}
name={[field.name, "color"] as any}
noStyle>
<Input
addonBefore={"#"}
style={{ width: 150 }}></Input>
</Form.Item>
<HorizontalLayoutDemo />
{fields.length > 0 ? (
<MinusCircleOutlined
className="dynamic-delete-button"
onClick={() => {
setIsDisabled(false);
remove(field.name);
}}
/>
) : null}
</Flex>
</Form.Item>
</Flex>
))}
<Form.Item>
<Button
type="default"
disabled={isDisabled}
onClick={() => add()}
style={{ width: "100%" }}
icon={<PlusOutlined />}>
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
</>
)}
</Form.List>
<Form.List name="urls">
{(fields: FormListFieldData[], { add, remove }) => (
<div
style={{
display: "flex",
rowGap: 16,
flexDirection: "column",
}}>
{fields.map((field: FormListFieldData, index: number) => (
<Card
size="small"
title={
<>
<h4>{`链接 ${index + 1}`}</h4>
</>
}
key={index}
bordered
hoverable
extra={
<CloseOutlined
onClick={() => {
remove(field.name);
}}
/>
}>
<Form.Item
name={[field.name, "type"] as any}
label="分享类型">
<Select
size="middle"
style={{ width: "20%" }}
showSearch={true}
allowClear={true}
notFoundContent={"未找到哦"}
placeholder={"请选择分享类型"}>
{selectOptions.map(
(storage: any, index: any) => {
return (
<Select.Option
value={storage.value}
key={index}>
{storage.name}
</Select.Option>
);
},
)}
</Select>
</Form.Item>
<Form.Item
name={[field.name, "description"] as any}
label="资源描述">
<Input name={"description"} />
</Form.Item>
<Form.Item
name={[field.name, "url"] as any}
label="资源链接">
<Input name={"url"} />
</Form.Item>
<Form.Item
name={[field.name, "password"] as any}
label={"提取密码"}>
<Input name={"password"} />
</Form.Item>
</Card>
))}
<Button type="default" onClick={() => add()} block>
+
</Button>
</div>
)}
</Form.List>
<Form.Item
style={{
display: "flex",
flexDirection: "row",
justifyContent: "flex-end",
marginTop: "2%",
}}>
<Button type="primary" htmlType="submit">
</Button>
</Form.Item>
</Form>
</div>
</div>
</>
);
};
export default observer(ShareAdd);

View File

@@ -0,0 +1,7 @@
.share_add_main{
display: flex;
flex-direction: column;
.share_add_content{
margin-top: 2%;
}
}

View File

@@ -1,7 +0,0 @@
/** @format */
import React from "react";
const ShareList: React.FunctionComponent = () => {
return <></>;
};
export default ShareList;

View File

@@ -0,0 +1,374 @@
/** @format */
import React, { useEffect, useState } from "react";
import { Avatar, Button, Card, Divider, Flex, message, Skeleton, Tag, Tooltip } from "antd";
import {
CommentOutlined,
ExportOutlined,
EyeOutlined,
HeartOutlined,
InfoCircleOutlined,
LeftOutlined,
LikeOutlined,
StarOutlined,
TagsOutlined,
WarningOutlined,
} from "@ant-design/icons";
import { useNavigate, useParams } from "react-router-dom";
import "aieditor/dist/style.css";
import { ProCard } from "@ant-design/pro-components";
import styles from "./index.module.less";
import { Typography } from "antd";
import Comment from "@/components/Main/Share/components/ShareDetail/components/Comment";
const { Paragraph } = Typography;
import like from "@/assets/icons/like.svg";
import favorite from "@/assets/icons/favorite.svg";
import useStore from "@/utils/store/useStore.tsx";
import { addLikeDetail, deletedLikeDetail, getShareDetail } from "@/api/share";
import StorageIcon from "@/constant/stroage-icon.ts";
import { observer } from "mobx-react";
import { addFavorites, deleteFavorites } from "@/api/user";
const ShareDetail: React.FunctionComponent = () => {
const navigate = useNavigate();
const store = useStore("share");
const userStore = useStore("user");
const userId: any = userStore.getUserId();
const params = useParams();
const [detail, setDetail] = useState<any>({} as any);
const [loading, setLoading] = useState(true);
async function getDetail() {
getShareDetail(params.id).then((res: any) => {
if (res && res.success && res.data) {
setDetail(res.data);
setLoading(false);
}
});
}
async function addLike() {
const data: any = {
circleId: store.getCircleId(),
userId: userId,
detailId: params.id,
};
addLikeDetail(data).then();
}
async function delLike() {
const data: any = {
circleId: store.getCircleId(),
userId: userId,
detailId: params.id,
};
deletedLikeDetail(data).then();
}
async function setFavorites() {
const data: any = {
userId: userId,
detailId: params.id,
circleId: store.getCircleId(),
};
addFavorites(data).then((res: any) => {
if (res && res.success) {
message.open({
type: "success",
content: "收藏成功",
});
getDetail().then();
} else {
message.open({
type: "error",
content: "收藏失败",
});
}
});
}
async function cancelFavorites() {
const data: any = {
userId: userId,
detailId: params.id,
circleId: store.getCircleId(),
};
deleteFavorites(data).then((res: any) => {
if (res && res.success) {
message.open({
type: "success",
content: "取消成功",
});
getDetail().then();
} else {
message.open({
type: "error",
content: "取消失败",
});
}
});
}
useEffect(() => {
getDetail().then();
}, []);
return (
<>
<Skeleton loading={loading} active={true} paragraph={{ rows: 16 }}>
<ProCard bordered={true}>
<Flex vertical={false} align={"center"} justify={"space-between"}>
<Button
shape="circle"
icon={<LeftOutlined />}
onClick={() => {
const circleId = store.getCircleId();
navigate("/main/share/list/" + circleId);
}}
/>
<Flex vertical={false} align={"center"}>
<h3>{detail.title as string}</h3>
</Flex>
<Flex
vertical={false}
align={"center"}
justify={"space-between"}
style={{ width: "20%" }}>
<Flex vertical={false} align={"center"}>
<Avatar src={detail.avatar as any} size={"small"} />
<span
style={{
fontSize: 12,
color: "gray",
overflow: "hidden",
}}>
{detail.nickname || "unknown"}
</span>
</Flex>
<Flex vertical={false} align={"center"}>
<HeartOutlined />
<span
style={{
fontSize: 12,
color: "gray",
}}>
{detail.likesCount || 0}
</span>
</Flex>
<Flex vertical={false} align={"center"}>
<CommentOutlined />
<span
style={{
fontSize: 12,
color: "gray",
}}>
{detail.commentCount || 0}
</span>
</Flex>
<Flex vertical={false} align={"center"}>
<EyeOutlined style={{ color: "gray" }} />{" "}
<span
style={{
fontSize: 12,
color: "gray",
}}>
{detail.views || 0}
</span>
</Flex>
</Flex>
</Flex>
</ProCard>
<div className={styles.share_detail_container}>
<ProCard bordered={true}>
<div
style={{ height: 500 }}
dangerouslySetInnerHTML={{ __html: detail.content }}></div>
<Card style={{ borderRadius: "10px", borderColor: "#1677FF" }}>
<Flex vertical={false} align={"center"} justify={"space-between"}>
<span
style={{
fontSize: 18,
color: "#1677FF",
fontWeight: "bolder",
}}>
</span>
<Button icon={<WarningOutlined />} type={"primary"}>
</Button>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ marginTop: 10 }}
justify={"space-between"}>
<span style={{ fontSize: 16 }}>{detail.title}</span>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ marginTop: 10 }}
justify={"space-between"}>
<span
style={{
fontSize: 18,
color: "#1677FF",
fontWeight: "bolder",
}}>
</span>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ marginTop: 10 }}
justify={"flex-start"}>
{detail.urls &&
Array.from(detail.urls).map((url: any, index: number) => {
return (
<div key={index}>
<Card
hoverable={true}
style={{
width: 280,
height: 140,
marginLeft: 10,
}}>
<Flex vertical={true}>
<Flex
vertical={false}
justify={"space-between"}
align={"center"}>
<div>
<Avatar
src={
StorageIcon[url.type] as any
}></Avatar>
<span
style={{
marginLeft: 10,
color: "#1677FF",
fontSize: 16,
}}>
{url.typeName}
</span>
</div>
<ExportOutlined
className={styles.link_btn}
onClick={() => {
window.open(url.url, "_blank");
}}
/>
</Flex>
<Divider></Divider>
<Flex vertical={false}>
<Tooltip
title={url.description}
placement={"bottom"}>
<span
style={{
width: 150,
overflowX: "hidden",
}}>
{url.description}
</span>
</Tooltip>
<span
style={{
width: 130,
marginLeft: 10,
display: "flex",
flexDirection: "row",
}}>
<span style={{ color: "#1677FF" }}>
</span>{" "}
<Paragraph copyable>
{url.password}
</Paragraph>
</span>
</Flex>
</Flex>
</Card>
</div>
);
})}
</Flex>
<Flex vertical={false} style={{ marginTop: 10 }}>
<span style={{ color: "grey" }}>
<InfoCircleOutlined />
使24
</span>
</Flex>
</Card>
<Flex vertical={false} align={"center"} style={{ marginTop: 20 }}>
<TagsOutlined style={{ fontSize: 30, color: "#1677FF" }} />
<Flex vertical={false} align={"center"} style={{ marginLeft: 10 }}>
{detail.tags &&
Array.from(detail.tags).map((tag: any, index: number) => {
return (
<div key={index}>
<Tag bordered={false} color={"#" + detail.color}>
{tag.tagName}
</Tag>
</div>
);
})}
</Flex>
</Flex>
<Flex
vertical={false}
align={"center"}
justify={"center"}
style={{ height: 50 }}>
{detail.isLike === true ? (
<>
<Tooltip title={"取消点赞"} placement={"bottom"}>
<Avatar
className={styles.like_icon}
src={like as any}
onClick={() => {
delLike().then();
}}
size={"large"}></Avatar>
</Tooltip>
</>
) : (
<>
<Tooltip title={"点赞"} placement={"bottom"}>
<LikeOutlined
className={styles.detail_link_btn}
onClick={() => {
addLike().then();
}}></LikeOutlined>
</Tooltip>
</>
)}
{detail.isFavor === true ? (
<>
<Tooltip title={"取消收藏"} placement={"bottom"}>
<Avatar
className={styles.favtorie_icon}
src={favorite as any}
onClick={() => {
cancelFavorites().then();
}}
size={"large"}></Avatar>
</Tooltip>
</>
) : (
<>
<Tooltip title={"收藏"} placement={"bottom"}>
<StarOutlined
onClick={() => {
setFavorites().then();
}}
className={styles.detail_link_btn}
/>
</Tooltip>
</>
)}
</Flex>
</ProCard>
</div>
<Comment auth={detail} />
</Skeleton>
</>
);
};
export default observer(ShareDetail);

View File

@@ -0,0 +1,19 @@
.like_icon {
font-size: 13px;
color: grey;
margin-left: 10px;
}
.like_icon:hover{
cursor: pointer;
color: #ce1111;
}
.comment_icon{
font-size: 13px;
color: grey;
margin-left: 10px;
}
.comment_icon:hover{
cursor: pointer;
color: #08a327;
}

View File

@@ -0,0 +1,939 @@
/** @format */
import { ProCard } from "@ant-design/pro-components";
import { Avatar, Button, Empty, Flex, Input, message, Segmented, Skeleton, Tag } from "antd";
import logo from "@/assets/icons/gitee.svg";
import {
BarsOutlined,
CloseOutlined,
CommentOutlined,
CrownOutlined,
FireOutlined,
LikeFilled,
LikeOutlined,
PictureOutlined,
SendOutlined,
SmileOutlined,
} from "@ant-design/icons";
import { useEffect, useState } from "react";
import styles from "./index.module.less";
import { useParams } from "react-router-dom";
import {
addComment,
addLikeComment,
addReply,
deletedLikeComment,
listComment,
listCommentHot,
listReply,
returnAllCommentAndReplyCount,
} from "@/api/share";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
const Comment = observer((props: any) => {
const params = useParams();
const [isReply, setIsReply] = useState<any>(null);
const [isReplyReply, setIsReplyReply] = useState<any>(null);
const [loading, setLoading] = useState<boolean>(true);
const [isReplyComment, setIsReplyComment] = useState<any>(null);
const [comment, setComment] = useState<any[]>([]);
const [reply, setReply] = useState<any[]>([]);
const [commentData, setCommentData] = useState<any>("");
const [replyData, setReplyData] = useState<any>("");
const [replyReplyData, setReplyReplyData] = useState<any>("");
const [count, setCount] = useState<any>(0);
const userStore = useStore("user");
const userId: any = userStore.getUserId();
async function listComments() {
setComment([]);
listComment(params.id, userId).then((res: any) => {
if (res && res.success && res.data) {
setComment(res.data);
setLoading(false);
}
});
}
async function addLike(commentId: any) {
setComment([]);
const data: any = {
detailId: params.id,
userId: userId,
commentId: commentId,
};
addLikeComment(data).then();
listComments().then();
}
async function delLike(commentId: any) {
setComment([]);
const data: any = {
detailId: params.id,
userId: userId,
commentId: commentId,
};
deletedLikeComment(data).then();
listComments().then();
}
async function getCommentHot() {
setComment([]);
listCommentHot(params.id, userId).then((res: any) => {
if (res && res.success && res.data) {
setComment(res.data);
setLoading(false);
}
});
}
async function getAllCommentAndReply(detailId: any) {
returnAllCommentAndReplyCount(detailId).then((res: any) => {
if (res && res.success && res.data) {
setCount(res.data);
}
});
}
async function addComments(data: any) {
addComment(data).then((res: any) => {
if (res && res.success) {
message.open({
content: "评论成功",
type: "success",
});
listComments().then();
} else {
message.open({
content: "评论失败",
type: "error",
});
}
});
}
async function replyComment(commentId: any) {
listReply(commentId, userId).then((res: any) => {
if (res && res.success && res.data) {
setReply(res.data);
}
});
}
async function addReplies(data: any) {
addReply(data).then((res: any) => {
if (res && res.success) {
message.open({
content: "回复成功",
type: "success",
});
listComments().then();
} else {
message.open({
content: "回复失败",
type: "error",
});
}
});
}
const handleExpandClick = (index: any) => {
setIsReply(isReply === index ? null : index);
};
const handleExpandReplyReplyClick = (index: any) => {
setIsReplyReply(isReplyReply === index ? null : index);
};
const handleExpandReplyCommentClick = (index: any) => {
setIsReplyComment(isReplyComment === index ? null : index);
};
useEffect(() => {
getCommentHot().then();
getAllCommentAndReply(params.id).then();
}, []);
return (
<>
<div>
<ProCard title={"评论 " + count}>
<Skeleton active={true} loading={loading} paragraph={{ rows: 2 }}>
<Flex vertical={false}>
<Flex vertical={true} justify={"flex-start"}>
<Avatar src={logo as any} size={"large"} />
</Flex>
<Flex vertical={true} style={{ width: "100%" }}>
<Input.TextArea
style={{ marginLeft: 10 }}
rows={5}
maxLength={500}
onChange={(e: any) => {
setCommentData(e.target.value);
}}
showCount
placeholder={"平等表达,友善交流"}></Input.TextArea>
<Flex
vertical={false}
align={"center"}
style={{ marginTop: 10, marginLeft: 10 }}>
<SmileOutlined style={{ fontSize: 20, color: "grey" }} />
<PictureOutlined
style={{ marginLeft: 20, fontSize: 20, color: "grey" }}
/>
</Flex>
<Flex vertical={false} align={"center"} justify={"flex-end"}>
<Button
icon={<SendOutlined />}
type={"primary"}
onClick={() => {
const data: any = {
userId: userId,
detailId: params.id,
content: commentData,
};
addComments(data).then(() => {
listComments().then();
});
}}>
</Button>
</Flex>
</Flex>
</Flex>
<Flex vertical={true}>
<Segmented
block={false}
style={{ width: 145 }}
size={"middle"}
defaultValue={"hot"}
onChange={(value: any) => {
if (value === "hot") {
getCommentHot().then();
}
if (value === "new") {
listComments().then();
}
}}
options={[
{
label: "最热",
value: "hot",
icon: <FireOutlined />,
},
{
label: "最新",
value: "new",
icon: <BarsOutlined />,
},
]}
/>
{comment.length === 0 ? (
<Empty description={"暂无评论!"} />
) : (
<>
{comment &&
Array.from(comment).map((item: any, index: number) => {
return (
<Flex
key={index}
vertical={true}
style={{ marginTop: 20, width: "100%" }}>
<Flex vertical={false}>
<Flex
vertical={true}
justify={"flex-start"}>
<Avatar
src={item.avatar as any}
size={"large"}></Avatar>
</Flex>
<Flex
vertical={true}
style={{
marginLeft: 15,
width: "100%",
}}>
<Flex vertical={false} align={"center"}>
<span
style={{
fontSize: 16,
fontWeight: 500,
}}>
{item.nick}
</span>
{props.auth.userId ==
item.userId ? (
<Tag
bordered={false}
icon={<CrownOutlined />}
color={"cyan"}
style={{ marginLeft: 5 }}>
</Tag>
) : null}
</Flex>
<ProCard
bordered={true}
boxShadow={false}
extra={<></>}
style={{ width: "100%" }}>
<span>{item.content}</span>
<Flex
vertical={false}
align={"center"}
justify={"space-between"}>
<Flex
vertical={false}
align={"center"}
style={{
marginTop: 10,
width: "100%",
}}>
<span
style={{
fontSize: 13,
color: "grey",
}}>
{item.createdTime}
</span>
<Flex
vertical={false}
align={"center"}>
{item.isLike ===
true ? (
<LikeFilled
onClick={() => {
delLike(
item.id,
).then();
}}
style={{
color: "red",
}}
/>
) : (
<LikeOutlined
className={
styles.like_icon
}
onClick={() => {
addLike(
item.id,
).then();
}}
/>
)}
<span
style={{
fontSize: 13,
color: "grey",
}}>
{item.likes}
</span>
</Flex>
<Flex
vertical={false}
align={"center"}>
<CommentOutlined
onClick={() => {
setReply([]);
if (item.id) {
replyComment(
item.id,
).then(
() => {
handleExpandReplyCommentClick(
index,
);
},
);
}
}}
className={
styles.comment_icon
}
/>
<span
style={{
fontSize: 13,
color: "grey",
}}>
{item.replyCount}
</span>
</Flex>
<Flex
vertical={false}
align={"center"}>
<Button
type="text"
size={"small"}
onClick={() => {
handleExpandClick(
index,
);
}}
style={{
fontSize: 13,
color: "grey",
}}>
</Button>
</Flex>
</Flex>
<Flex
vertical={false}
align={"center"}>
<span
style={{
textWrap: "nowrap",
fontSize: 12,
color: "grey",
textAlign: "end",
}}>
{item.location ||
"unknown"}
</span>
<span
style={{
marginLeft: 10,
fontSize: 13,
color: "grey",
}}>
{item.browser ||
"unknown"}
</span>
<span
style={{
marginLeft: 10,
fontSize: 13,
color: "grey",
}}>
{item.browserVersion ||
"unknown"}
</span>
</Flex>
</Flex>
</ProCard>
{isReply === index && (
<Flex vertical={true}>
<Flex
vertical={false}
align={"center"}>
<span
style={{
fontSize: 13,
}}>
</span>
<span
style={{
fontSize: 13,
}}>
{item.nick}
</span>
<Button
icon={<CloseOutlined />}
style={{
fontSize: 13,
marginLeft: 5,
}}
type={"dashed"}
onClick={() => {
setIsReply(null);
}}
size={"small"}>
</Button>
</Flex>
<Flex
vertical={false}
style={{ marginTop: 5 }}>
<Flex
vertical={true}
justify={"flex-start"}>
<Avatar
src={logo as any}
size={"default"}
/>
</Flex>
<Flex
vertical={true}
style={{
width: "100%",
}}>
<Input.TextArea
style={{
marginLeft: 10,
width: "100%",
}}
rows={3}
maxLength={500}
showCount
onChange={(e) => {
setReplyData(
e.target
.value,
);
}}
placeholder={
"平等表达,友善交流"
}></Input.TextArea>
<Flex
vertical={false}
align={"center"}
style={{
marginTop: 10,
marginLeft: 10,
}}>
<SmileOutlined
style={{
fontSize: 20,
color: "grey",
}}
/>
<PictureOutlined
style={{
marginLeft: 20,
fontSize: 20,
color: "grey",
}}
/>
</Flex>
<Flex
vertical={false}
align={"center"}
justify={
"flex-end"
}>
<Button
onClick={() => {
const data: any =
{
userId: userId,
detailId:
params.id,
content:
replyData,
toId: item.id,
replyId:
item.id,
};
addReplies(
data,
).then();
}}
icon={
<SendOutlined />
}
type={
"primary"
}>
</Button>
</Flex>
</Flex>
</Flex>
</Flex>
)}
{isReplyComment === index &&
reply &&
Array.from(reply).map(
(
replyItem: any,
replyIndex: number,
) => {
return (
<Flex
key={replyIndex}
vertical={false}>
<Flex
vertical={true}
justify={
"flex-start"
}>
<Avatar
src={
replyItem.avatar as any
}
size={
"default"
}></Avatar>
</Flex>
<Flex
vertical={true}
style={{
marginLeft: 15,
width: "100%",
}}>
<Flex
vertical={
false
}
align={
"center"
}>
<span
style={{
fontSize: 14,
fontWeight: 500,
}}>
{
replyItem.nick
}{" "}
{
replyItem.nickto
}
</span>
{props.auth
.userId ==
replyItem.userId ? (
<Tag
bordered={
false
}
icon={
<CrownOutlined />
}
color={
"cyan"
}
style={{
marginLeft: 5,
}}>
</Tag>
) : null}
</Flex>
<ProCard
bordered={
true
}
boxShadow={
false
}
extra={
<></>
}
style={{
width: "100%",
}}>
<span>
{
replyItem.content
}
</span>
<Flex
vertical={
false
}
align={
"center"
}
justify={
"space-between"
}>
<Flex
vertical={
false
}
style={{
marginTop: 10,
width: "100%",
}}>
<span
style={{
fontSize: 13,
color: "grey",
}}>
{
replyItem.createdTime
}
</span>
<Flex
vertical={
false
}
align={
"center"
}>
{replyItem.isLike ===
false ? (
<LikeOutlined
onClick={() => {
addLike(
replyItem.id,
).then();
}}
className={
styles.like_icon
}
/>
) : (
<LikeFilled
className={
styles.like_icon
}
style={{
color: "red",
}}
onClick={() => {
delLike(
replyItem.id,
).then();
}}
/>
)}
<span
style={{
fontSize: 13,
color: "grey",
}}>
{
replyItem.likes
}
</span>
</Flex>
<Flex
vertical={
false
}
align={
"center"
}>
<Button
type="text"
size={
"small"
}
onClick={() => {
handleExpandReplyReplyClick(
replyItem.id,
);
}}
style={{
fontSize: 13,
color: "grey",
}}>
</Button>
</Flex>
</Flex>
<Flex
vertical={
false
}
align={
"center"
}>
<span
style={{
textWrap:
"nowrap",
fontSize: 12,
color: "grey",
textAlign:
"end",
}}>
{replyItem.location ||
"unknown"}
</span>
<span
style={{
marginLeft: 10,
fontSize: 13,
color: "grey",
}}>
{replyItem.browser ||
"unknown"}
</span>
<span
style={{
marginLeft: 10,
fontSize: 13,
color: "grey",
}}>
{replyItem.browserVersion ||
"unknown"}
</span>
</Flex>
</Flex>
</ProCard>
{isReplyReply ===
replyItem.id && (
<>
<Flex
vertical={
true
}>
<Flex
vertical={
false
}
align={
"center"
}>
<span
style={{
fontSize: 13,
}}>
</span>
<span
style={{
fontSize: 13,
}}>
{
replyItem.nick
}
</span>
<Button
icon={
<CloseOutlined />
}
style={{
fontSize: 13,
marginLeft: 5,
}}
type={
"dashed"
}
onClick={() => {
setIsReplyReply(
null,
);
}}
size={
"small"
}>
</Button>
</Flex>
<Flex
vertical={
false
}
style={{
marginTop: 5,
}}>
<Flex
vertical={
true
}
justify={
"flex-start"
}>
<Avatar
src={
logo as any
}
size={
"default"
}
/>
</Flex>
<Flex
vertical={
true
}
style={{
width: "100%",
}}>
<Input.TextArea
style={{
marginLeft: 10,
width: "100%",
}}
rows={
3
}
onChange={(
e: any,
) => {
setReplyReplyData(
e
.target
.value,
);
}}
maxLength={
500
}
showCount
placeholder={
"平等表达,友善交流"
}></Input.TextArea>
<Flex
vertical={
false
}
align={
"center"
}
style={{
marginTop: 10,
marginLeft: 10,
}}>
<SmileOutlined
style={{
fontSize: 20,
color: "grey",
}}
/>
<PictureOutlined
style={{
marginLeft: 20,
fontSize: 20,
color: "grey",
}}
/>
</Flex>
<Flex
vertical={
false
}
align={
"center"
}
justify={
"flex-end"
}>
<Button
onClick={() => {
const data: any =
{
userId: userId,
detailId:
params.id,
content:
replyReplyData,
toId: item.id,
replyId:
replyItem.id,
};
addReplies(
data,
).then();
}}
icon={
<SendOutlined />
}
type={
"primary"
}>
</Button>
</Flex>
</Flex>
</Flex>
</Flex>
</>
)}
</Flex>
</Flex>
);
},
)}
</Flex>
</Flex>
</Flex>
);
})}
</>
)}
</Flex>
</Skeleton>
</ProCard>
</div>
</>
);
});
export default Comment;

View File

@@ -0,0 +1,30 @@
.share_detail_container{
margin-top: 10px;
}
.link_btn{
font-size: 20px;
color: grey;
}
.link_btn:hover{
color: #1890ff;
}
.like_icon:hover{
cursor: pointer;
width: 50px;
height: auto;
}
.favtorie_icon{
margin-left: 20px;
}
.favtorie_icon:hover{
cursor: pointer;
width: 50px;
height: auto;
}
.detail_link_btn{
font-size: 30px;
}
.detail_link_btn:hover{
font-size: 35px;
color: red;
}

View File

@@ -1,86 +0,0 @@
/** @format */
import { LikeOutlined, MessageOutlined, StarOutlined } from "@ant-design/icons";
import { ProList } from "@ant-design/pro-components";
import { Button, Tag } from "antd";
import React from "react";
const IconText = ({ icon, text }: { icon: any; text: string }) => (
<span>
{React.createElement(icon, { style: { marginInlineEnd: 8 } })}
{text}
</span>
);
const dataSource = [
{
title: "语雀的天空",
},
{
title: "Ant Design",
},
{
title: "蚂蚁金服体验科技",
},
{
title: "TechUI",
},
];
const ShareList = () => {
return (
<ProList<{ title: string }>
toolBarRender={() => {
return [
<Button key="3" type="primary">
</Button>,
];
}}
itemLayout="vertical"
rowKey="id"
// headerTitle="竖排样式"
dataSource={dataSource}
metas={{
title: {},
description: {
render: () => (
<>
<Tag></Tag>
<Tag></Tag>
<Tag></Tag>
</>
),
},
actions: {
render: () => [
<IconText icon={StarOutlined} text="156" key="list-vertical-star-o" />,
<IconText icon={LikeOutlined} text="156" key="list-vertical-like-o" />,
<IconText icon={MessageOutlined} text="2" key="list-vertical-message" />,
],
},
extra: {
render: () => (
<img
width={272}
alt="logo"
src="https://gw.alipayobjects.com/zos/rmsportal/mqaQswcyDLcXyDKnZfES.png"
/>
),
},
content: {
render: () => {
return (
<div>
design.alipay.com
design.alipay.com
</div>
);
},
},
}}
/>
);
};
export default ShareList;

View File

@@ -0,0 +1,192 @@
/** @format */
import { ProCard } from "@ant-design/pro-components";
import { Avatar, Button, Flex, Input, List, Skeleton, Tag } from "antd";
import { useEffect, useState } from "react";
import styles from "./index.module.less";
import { Link, useNavigate, useParams } from "react-router-dom";
import {
CommentOutlined,
EyeOutlined,
HeartOutlined,
LeftOutlined,
ShareAltOutlined,
} from "@ant-design/icons";
import { shareDetailList } from "@/api/share";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
interface DataType {
gender: string;
name: {
title: string;
first: string;
last: string;
};
email: string;
picture: {
large: string;
medium: string;
thumbnail: string;
};
nat: string;
}
export default observer(() => {
const navigate = useNavigate();
const params = useParams();
const [loading, setLoading] = useState(true);
const [data, setData] = useState<DataType[]>([]);
const store = useStore("share");
async function getShareDetailList() {
store.setCircleId(params.id as string);
shareDetailList(params.id).then((res: any) => {
console.log(res);
if (res && res.data && res.data) {
setData(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getShareDetailList().then();
}, []);
return (
<>
<div className={styles.share_list_main}>
<ProCard bordered={false} boxShadow={false}>
<div className={styles.share_list_header}>
<div>
<Button
shape="circle"
icon={<LeftOutlined />}
onClick={() => {
navigate("/main/share");
}}
/>
<Input
placeholder="搜索"
style={{ borderRadius: 20, width: 500, marginLeft: 20 }}
/>
</div>
<Button
icon={<ShareAltOutlined />}
type={"primary"}
onClick={() => {
navigate("/main/share/add");
}}>
</Button>
</div>
</ProCard>
<ProCard bordered={false} boxShadow={false}>
<Skeleton loading={loading} active={true} paragraph={{ rows: 14 }}>
<List
dataSource={data}
header={
<>
<h4></h4>
</>
}
renderItem={(item: any) => (
<List.Item key={item.id}>
<List.Item.Meta
avatar={<Avatar src={item.icon} />}
title={
<Flex vertical={false} align={"center"}>
<Link to={"/main/share/detail/" + item.id}>
{item.title}
</Link>
{item.tags &&
Array.from(item.tags).map(
(tag: any, index: number) => {
return (
<Flex
vertical={false}
align={"center"}
key={index}>
<Tag
bordered={false}
color={"#" + tag.color}
style={{ marginLeft: 10 }}>
{tag.tagName}
</Tag>
</Flex>
);
},
)}
</Flex>
}
description={
<>
<Flex
vertical={false}
justify={"space-between"}
align={"center"}>
{item.description}
<Flex
vertical={false}
align={"center"}
justify={"space-between"}
style={{ width: "300px" }}>
<Flex vertical={false} align={"center"}>
<Avatar
src={item.avatar as any}
size={"small"}
/>
<span
style={{
fontSize: 12,
color: "gray",
overflow: "hidden",
}}>
{item.nickname}
</span>
</Flex>
<Flex vertical={false} align={"center"}>
<HeartOutlined />
<span
style={{
fontSize: 12,
color: "gray",
}}>
{item.likesCount}
</span>
</Flex>
<Flex vertical={false} align={"center"}>
<CommentOutlined />
<span
style={{
fontSize: 12,
color: "gray",
}}>
{item.commentCount}
</span>
</Flex>
<Flex vertical={false} align={"center"}>
<EyeOutlined
style={{ color: "gray" }}
/>{" "}
<span
style={{
fontSize: 12,
color: "gray",
}}>
{item.views}
</span>
</Flex>
</Flex>
</Flex>
</>
}
/>
</List.Item>
)}
/>
</Skeleton>
</ProCard>
</div>
</>
);
});

View File

@@ -0,0 +1,10 @@
.share_list_main{
display: flex;
flex-direction: column;
min-height: 83vh;
.share_list_header{
display: flex;
flex-direction: row;
justify-content: space-between;
}
}

View File

@@ -1,10 +1,11 @@
.share_main{
display: flex;
flex-direction: column;
.share_header{
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
}
}
.share_main{
min-height: 83vh;
display: flex;
flex-direction: column;
.share_header{
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
}

View File

@@ -1,39 +1,257 @@
/** @format */
import { FunctionComponent } from "react";
import { ProCard } from "@ant-design/pro-components";
import styles from "./index.module.less";
import { Avatar, Button, Card } from "antd";
import setting from "@/assets/icons/setting.svg";
import Search from "antd/es/input/Search";
import Meta from "antd/es/card/Meta";
import { useNavigate } from "react-router-dom";
const MainShare: FunctionComponent = () => {
const navigate = useNavigate();
return (
<>
<div className={styles.share_main}>
<ProCard bordered={true} boxShadow={true}>
<div className={styles.share_header}>
<Search placeholder="搜索圈子" style={{ width: 500 }} />
<Button></Button>
</div>
</ProCard>
<ProCard bordered={true} boxShadow={true} style={{ marginTop: 20 }}>
<Card
style={{ width: 250, marginTop: 16 }}
hoverable
onClick={() => {
navigate("/main/share/list/1");
}}>
<Meta
avatar={<Avatar src={setting} />}
title="Card title"
description="This is the description"
/>
</Card>
</ProCard>
</div>
</>
);
};
export default MainShare;
/** @format */
import { FunctionComponent, useEffect, useState } from "react";
import { ProCard } from "@ant-design/pro-components";
import styles from "./index.module.less";
import {
Avatar,
Button,
Card,
Drawer,
Flex,
FloatButton,
Form,
Image,
Input,
message,
Skeleton,
Tooltip,
} from "antd";
import { useNavigate } from "react-router-dom";
import TextArea from "antd/es/input/TextArea";
import { EyeOutlined, PlusOutlined, UnorderedListOutlined } from "@ant-design/icons";
import Meta from "antd/es/card/Meta";
import { addShareCircle, getShareCircleList } from "@/api/share";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
const MainShare: FunctionComponent = observer(() => {
const store = useStore("user");
const userId: any = store.getUserId();
const navigate = useNavigate();
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(true);
const [circleList, setCircleList] = useState<any[]>([]);
const [form] = Form.useForm();
const onClose = () => {
setOpen(false);
};
async function getShareCircles() {
getShareCircleList().then((res: any) => {
if (res && res.success && res.data) {
setCircleList(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getShareCircles().then();
}, []);
return (
<>
<div className={styles.share_main}>
<ProCard bordered={false} boxShadow={false}>
<div className={styles.share_header}>
<Input
size={"large"}
placeholder="搜索圈子"
style={{ width: 500, borderRadius: 20 }}
/>
</div>
</ProCard>
<ProCard title={<h3></h3>} bordered={false} boxShadow={false}>
<Flex vertical={false} align={"center"} wrap={true} justify={"flex-start"}>
<Skeleton active={true} loading={loading} paragraph={{ rows: 10 }}>
{circleList &&
circleList.map((item: any, index: number) => {
return (
<div key={index}>
<Card
hoverable
style={{
width: "250px",
boxShadow: " 0 0 10px rgba(0, 0, 0, 0.1)",
borderRadius: 20,
marginLeft: 30,
marginTop: 20,
// backgroundColor: "rgba(79,68,68,0.11)",
}}
onClick={() => {
navigate("/main/share/list/" + item.id);
}}
cover={
<Image
alt="example"
src={item.icon}
style={{
height: 180,
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
backgroundSize: "cover",
}}
preview={false}
width={"100%"}
height={"100%"}
fallback="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="
/>
}>
<Meta
title={item.name}
description={
<>
<Tooltip title={item.description}>
<span>{item.description}</span>
</Tooltip>
</>
}
/>
<Flex
vertical={false}
style={{ marginTop: 10 }}
align={"center"}
justify={"space-between"}>
<Flex vertical={false} align={"center"}>
<Avatar
src={item.avatar as any}
size={"small"}
/>{" "}
<span
style={{
fontSize: 12,
color: "gray",
marginLeft: 5,
}}>
{item.nickName}
</span>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ width: 100 }}
justify={"space-between"}>
<Flex vertical={false} align={"center"}>
<EyeOutlined
style={{ color: "gray" }}
/>{" "}
<span
style={{
fontSize: 12,
color: "gray",
marginLeft: 5,
}}>
{item.views}
</span>
</Flex>
<Flex vertical={false} align={"center"}>
<UnorderedListOutlined
style={{ color: "gray" }}
/>{" "}
<span
style={{
fontSize: 12,
color: "gray",
marginLeft: 5,
}}>
{item.count}
</span>
</Flex>
</Flex>
</Flex>
</Card>
</div>
);
})}
</Skeleton>
</Flex>
</ProCard>
</div>
<Drawer
title="创建圈子"
width={"40%"}
onClose={onClose}
open={open}
styles={{
body: {
paddingBottom: 80,
},
}}
// extra={
// <Space>
// <Button onClick={onClose}>取消</Button>
// <Button onClick={onClose} type="primary">
// 提交
// </Button>
// </Space>
// }
>
<Form
layout="vertical"
form={form}
onFinish={(values: any) => {
const formData: any = {
userId: userId,
...values,
};
addShareCircle(formData).then((res: any) => {
if (res && res.success && res.data) {
message
.open({
content: "创建成功",
type: "success",
})
.then();
setOpen(false);
getShareCircles().then();
form.resetFields();
} else {
message
.open({
content: res.data,
type: "error",
})
.then();
}
});
}}>
<Form.Item
name="name"
label="名称"
rules={[{ required: true, message: "请输入圈子名称!" }]}>
<Input maxLength={30} showCount placeholder="请输入圈子名称!" />
</Form.Item>
<Form.Item
name="icon"
label="图标"
rules={[{ required: true, message: "请输入图标!" }]}>
<Input placeholder="请输入图标!" />
</Form.Item>
<Form.Item
name="description"
label="描述"
rules={[{ required: true, message: "请输入描述!" }]}>
<TextArea rows={4} maxLength={50} showCount placeholder="请输入描述!" />
</Form.Item>
<Form.Item
style={{
display: "flex",
flexDirection: "row",
justifyContent: "flex-end",
}}>
<Button type="primary" htmlType="submit">
</Button>
</Form.Item>
</Form>
</Drawer>
<FloatButton
type={"primary"}
style={{ right: "5%", width: 50, height: 50 }}
icon={<PlusOutlined />}
onClick={() => setOpen(true)}
/>
</>
);
});
export default MainShare;

View File

@@ -0,0 +1,10 @@
.share_list_main{
display: flex;
flex-direction: column;
min-height: 83vh;
.share_list_header{
display: flex;
flex-direction: row;
justify-content: space-between;
}
}

View File

@@ -0,0 +1,187 @@
/** @format */
import { ProCard } from "@ant-design/pro-components";
import { Avatar, Button, Empty, Flex, Input, List, Skeleton, Tag } from "antd";
import { useEffect, useState } from "react";
import styles from "./index.module.less";
import { Link, useNavigate } from "react-router-dom";
import { CommentOutlined, EyeOutlined, HeartOutlined } from "@ant-design/icons";
import { getMyFavor } from "@/api/share";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
export default observer(() => {
const navigate = useNavigate();
const [loading, setLoading] = useState(true);
const [data, setData] = useState<[]>([]);
const store = useStore("user");
const userId: any = store.getUserId();
async function getMyShare() {
getMyFavor(userId).then((res: any) => {
if (res && res.success && res.data) {
setData(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getMyShare().then();
}, []);
return (
<>
<div className={styles.share_list_main}>
<ProCard bordered={false} boxShadow={false}>
<div className={styles.share_list_header}>
<Flex
vertical={false}
align={"center"}
justify={"space-between"}
style={{ width: "100%" }}>
<div>
<Input
placeholder="搜索"
style={{ borderRadius: 20, width: 500, marginLeft: 20 }}
/>
</div>
<div>
<Button
type={"primary"}
onClick={() => {
navigate("/main/share/add");
}}>
</Button>
</div>
</Flex>
</div>
</ProCard>
<ProCard bordered={false} boxShadow={false}>
{data.length === 0 ? (
<Empty description={"暂无数据"}></Empty>
) : (
<>
<Skeleton loading={loading} active={true} paragraph={{ rows: 14 }}>
<List
dataSource={data}
header={
<>
<h4></h4>
</>
}
renderItem={(item: any) => (
<List.Item key={item.id}>
<List.Item.Meta
avatar={<Avatar src={item.icon} />}
title={
<Flex vertical={false} align={"center"}>
<Link to={"/main/share/detail/" + item.id}>
{item.title}
</Link>
{item.tags &&
Array.from(item.tags).map(
(tag: any, index: number) => {
return (
<Flex
vertical={false}
align={"center"}
key={index}>
<Tag
bordered={false}
color={
"#" + tag.color
}
style={{
marginLeft: 10,
}}>
{tag.tagName}
</Tag>
</Flex>
);
},
)}
</Flex>
}
description={
<>
<Flex
vertical={false}
justify={"space-between"}
align={"center"}>
{item.description}
<Flex
vertical={false}
align={"center"}
justify={"space-between"}
style={{ width: "300px" }}>
<Flex
vertical={false}
align={"center"}>
<Avatar
src={item.avatar as any}
size={"small"}
/>
<span
style={{
fontSize: 12,
color: "gray",
overflow: "hidden",
}}>
{item.nickname}
</span>
</Flex>
<Flex
vertical={false}
align={"center"}>
<HeartOutlined />
<span
style={{
fontSize: 12,
color: "gray",
}}>
{item.likesCount}
</span>
</Flex>
<Flex
vertical={false}
align={"center"}>
<CommentOutlined />
<span
style={{
fontSize: 12,
color: "gray",
}}>
{item.commentCount}
</span>
</Flex>
<Flex
vertical={false}
align={"center"}>
<EyeOutlined
style={{ color: "gray" }}
/>{" "}
<span
style={{
fontSize: 12,
color: "gray",
}}>
{item.views}
</span>
</Flex>
</Flex>
</Flex>
</>
}
/>
</List.Item>
)}
/>
</Skeleton>
</>
)}
</ProCard>
</div>
</>
);
});

View File

@@ -0,0 +1,10 @@
.share_list_main{
display: flex;
flex-direction: column;
min-height: 83vh;
.share_list_header{
display: flex;
flex-direction: row;
justify-content: space-between;
}
}

View File

@@ -0,0 +1,187 @@
/** @format */
import { ProCard } from "@ant-design/pro-components";
import { Avatar, Button, Empty, Flex, Input, List, Skeleton, Tag } from "antd";
import { useEffect, useState } from "react";
import styles from "./index.module.less";
import { Link, useNavigate } from "react-router-dom";
import { CommentOutlined, EyeOutlined, HeartOutlined } from "@ant-design/icons";
import { getMyShareList } from "@/api/share";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
export default observer(() => {
const navigate = useNavigate();
const [loading, setLoading] = useState(true);
const [data, setData] = useState<[]>([]);
const store = useStore("user");
const userId: any = store.getUserId();
async function getMyShare() {
getMyShareList(userId).then((res: any) => {
if (res && res.success && res.data) {
setData(res.data);
setLoading(false);
}
});
}
useEffect(() => {
getMyShare().then();
}, []);
return (
<>
<div className={styles.share_list_main}>
<ProCard bordered={false} boxShadow={false}>
<div className={styles.share_list_header}>
<Flex
vertical={false}
align={"center"}
justify={"space-between"}
style={{ width: "100%" }}>
<div>
<Input
placeholder="搜索"
style={{ borderRadius: 20, width: 500, marginLeft: 20 }}
/>
</div>
<div>
<Button
type={"primary"}
onClick={() => {
navigate("/main/share/add");
}}>
</Button>
</div>
</Flex>
</div>
</ProCard>
<ProCard bordered={false} boxShadow={false}>
{data.length === 0 ? (
<Empty description={"暂无数据"}></Empty>
) : (
<>
<Skeleton loading={loading} active={true} paragraph={{ rows: 14 }}>
<List
dataSource={data}
header={
<>
<h4></h4>
</>
}
renderItem={(item: any) => (
<List.Item key={item.id}>
<List.Item.Meta
avatar={<Avatar src={item.icon} />}
title={
<Flex vertical={false} align={"center"}>
<Link to={"/main/share/detail/" + item.id}>
{item.title}
</Link>
{item.tags &&
Array.from(item.tags).map(
(tag: any, index: number) => {
return (
<Flex
vertical={false}
align={"center"}
key={index}>
<Tag
bordered={false}
color={
"#" + tag.color
}
style={{
marginLeft: 10,
}}>
{tag.tagName}
</Tag>
</Flex>
);
},
)}
</Flex>
}
description={
<>
<Flex
vertical={false}
justify={"space-between"}
align={"center"}>
{item.description}
<Flex
vertical={false}
align={"center"}
justify={"space-between"}
style={{ width: "300px" }}>
<Flex
vertical={false}
align={"center"}>
<Avatar
src={item.avatar as any}
size={"small"}
/>
<span
style={{
fontSize: 12,
color: "gray",
overflow: "hidden",
}}>
{item.nickname}
</span>
</Flex>
<Flex
vertical={false}
align={"center"}>
<HeartOutlined />
<span
style={{
fontSize: 12,
color: "gray",
}}>
{item.likesCount}
</span>
</Flex>
<Flex
vertical={false}
align={"center"}>
<CommentOutlined />
<span
style={{
fontSize: 12,
color: "gray",
}}>
{item.commentCount}
</span>
</Flex>
<Flex
vertical={false}
align={"center"}>
<EyeOutlined
style={{ color: "gray" }}
/>{" "}
<span
style={{
fontSize: 12,
color: "gray",
}}>
{item.views}
</span>
</Flex>
</Flex>
</Flex>
</>
}
/>
</List.Item>
)}
/>
</Skeleton>
</>
)}
</ProCard>
</div>
</>
);
});

View File

@@ -1,125 +1,168 @@
/** @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 { 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 { Link, useNavigate } from "react-router-dom";
import { getAllStorage } from "@/api/oss";
import StorageIcon from "@/constant/stroage-icon.ts";
import { getRecentShare, getUserInfoApi } from "@/api/user";
import useStore from "@/utils/store/useStore.tsx";
import { observer } from "mobx-react";
const UserInfo: FunctionComponent = observer(() => {
const navigate = useNavigate();
const [loading, setLoading] = useState(true);
const [loadingStorage, setLoadingStorage] = useState(true);
const [userStorage, setUserStorage] = useState([]);
const [recentShare, setRecentShare] = useState([]);
const [userInfo, setUserInfo] = useState<any>({} as any);
const store = useStore("user");
const userId: any = store.getUserId();
async function getUserStorage() {
const res: any = await getAllStorage(userId);
if (res && res.success && res.data) {
setUserStorage(res.data);
setLoadingStorage(false);
}
}
async function getUserRecentShare() {
const res: any = await getRecentShare(userId);
if (res && res.success && res.data) {
setRecentShare(res.data);
setLoading(false);
}
}
const getUserInfo = async () => {
const res = await getUserInfoApi(userId);
if (res && res.success && res.data) {
setUserInfo(res.data);
}
};
useEffect(() => {
getUserInfo().then();
getUserStorage().then();
getUserRecentShare().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 }}
src={userInfo.avatar}
/>
<span className={styles.user_info_header_name}>{userInfo.nickName}</span>
<div className={styles.user_info_header_desc}>
<div>
<BulbOutlined /> {userInfo.introduce || "-------"}
</div>
<div>
<EnvironmentOutlined /> {userInfo.location || "-------"}
</div>
<div>
<BankOutlined /> {userInfo.company || "-------"}
</div>
</div>
</div>
</div>
<div className={styles.user_info_center_content}>
<ProCard
bordered
style={{ maxWidth: "100%" }}
title="我的存储商"
boxShadow
extra={<Link to={"/main/setting"}></Link>}>
<Flex vertical={false} align={"center"} justify={"space-between"} wrap={true}>
{userStorage && userStorage.length === 0 ? (
<Empty description={"暂无数据"}></Empty>
) : (
<>
<Skeleton loading={loadingStorage} active>
{userStorage.map((item: any, index: number) => {
return (
<div key={index}>
<Card
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>
</div>
);
})}
</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>
{recentShare && recentShare.length === 0 ? (
<Empty description={"暂无数据"}></Empty>
) : (
<Skeleton loading={loading} active avatar>
<List
itemLayout="horizontal"
dataSource={recentShare}
renderItem={(item: any) => (
<List.Item>
<List.Item.Meta
avatar={<Avatar src={userInfo.avatar} />}
title={item.title}
description={item.date}
/>
</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

@@ -1,253 +1,382 @@
/** @format */
import { FunctionComponent, useEffect, useState } from "react";
import { ProCard, ProForm, ProFormCascader } from "@ant-design/pro-components";
import { AntDesignOutlined } from "@ant-design/icons";
import {
Avatar,
Button,
Descriptions,
DescriptionsProps,
Form,
FormProps,
Input,
Select,
Skeleton,
Space,
Tabs,
} from "antd";
import styles from "./index.module.less";
import TextArea from "antd/es/input/TextArea";
import { city } from "@/context/five-level-address.ts";
const UserSetting: FunctionComponent = () => {
const [disable, setDisable] = useState(true);
const [loading, setLoading] = useState(true);
const items: DescriptionsProps["items"] = [
{
key: "1",
label: "用户名",
children: "Zhou Maomao",
},
{
key: "2",
label: "账号ID",
children: "1810000000",
},
{
key: "3",
label: "注册时间",
children: "Hangzhou, Zhejiang",
},
{
key: "4",
label: "邮箱",
children: "landaiqing@126.com",
},
{
key: "5",
label: "手机号",
children: "13333333333333",
},
];
type FieldType = {
email?: string;
nickname?: string;
location?: string;
introduce?: string;
gender?: string;
company?: string;
blog?: string;
};
const onFinish: FormProps<FieldType>["onFinish"] = (values) => {
console.log("Success:", values);
};
const onFinishFailed: FormProps<FieldType>["onFinishFailed"] = (errorInfo) => {
console.log("Failed:", errorInfo);
};
const prefixSelector = (
<Form.Item name="prefix" noStyle>
<Select style={{ width: 90 }}>
<Select.Option value="https://">https://</Select.Option>
<Select.Option value="http://">http://</Select.Option>
</Select>
</Form.Item>
);
const ProFormText = (props: any) => {
return (
<ProForm.Item {...props} style={{ height: "10px" }}>
<ProFormCascader
request={async () => city}
width="md"
name="location"
disabled={disable}></ProFormCascader>
</ProForm.Item>
);
};
useEffect(() => {
setTimeout(() => {
setLoading(false);
}, 2000);
}, []);
const TabItems = [
{
label: <span></span>,
key: "baseInfo",
children: (
<>
<Skeleton loading={loading} active>
<div>
<Form
name="basic"
labelCol={{ span: 3 }}
wrapperCol={{ span: 16 }}
style={{ maxWidth: 600 }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
initialValues={{ prefix: "https://" }}
autoComplete="off">
<Form.Item<FieldType>
label="邮箱"
name="email"
rules={[
{
type: "email",
message: "请输入正确的邮箱!",
},
{ required: true, message: "请输入邮箱!" },
]}>
<Input allowClear disabled={disable} />
</Form.Item>
<Form.Item<FieldType>
label="昵称"
name="nickname"
rules={[
{
type: "string",
message:
"用户名只能是3到16位字母数字下划线减号",
pattern: /^[a-zA-Z0-9_-]{3,16}$/,
},
{
required: true,
message: "请输入昵称!",
},
]}>
<Input allowClear disabled={disable} />
</Form.Item>
<Form.Item<FieldType>
label="性别"
name="gender"
rules={[{ required: true, message: "请输入性别!" }]}>
<Select disabled={disable}>
<Select.Option value="男"></Select.Option>
<Select.Option value="女"></Select.Option>
<Select.Option value="UNKNOWN"></Select.Option>
</Select>
</Form.Item>
<Form.Item<FieldType>
label="地区"
name="location"
rules={[{ required: true, message: "请输入地区!" }]}>
<ProFormText />
</Form.Item>
<Form.Item<FieldType> label="公司" name="company">
<Input allowClear disabled={disable} />
</Form.Item>
<Form.Item<FieldType> label="博客" name="blog">
<Input
addonBefore={prefixSelector}
allowClear
disabled={disable}
/>
</Form.Item>
<Form.Item<FieldType> label="个人简介" name="introduce">
<TextArea
rows={4}
allowClear
maxLength={200}
showCount
placeholder="请输入您的个人简介最多不超过200字。"
disabled={disable}
/>
</Form.Item>
<Form.Item wrapperCol={{ offset: 3, span: 16 }}>
<Space
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
width: "400px",
}}>
<Button
htmlType="button"
onClick={() => {
setDisable(!disable);
}}>
</Button>
<Button type="primary" htmlType="submit" disabled={disable}>
</Button>
</Space>
</Form.Item>
</Form>
</div>
</Skeleton>
</>
),
},
{
label: <span></span>,
key: "security",
children: (
<>
<Skeleton loading={loading} active>
<Space direction={"vertical"} style={{ width: "100%" }}>
<ProCard hoverable bordered>
</ProCard>
<ProCard hoverable bordered>
</ProCard>
<ProCard hoverable bordered>
</ProCard>
</Space>
</Skeleton>
</>
),
},
];
return (
<>
<div className={styles.user_setting_main}>
<ProCard boxShadow>
<Skeleton loading={loading} active avatar>
<div className={styles.user_setting_header}>
<Avatar
size={{ xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 }}
icon={<AntDesignOutlined />}
/>
<Descriptions
style={{ width: "80%", marginLeft: "50px" }}
items={items}
column={3}
size={"small"}></Descriptions>
</div>
</Skeleton>
</ProCard>
<div className={styles.user_setting_content}>
<ProCard boxShadow>
<Tabs type="card" items={TabItems}></Tabs>
</ProCard>
</div>
</div>
</>
);
};
export default UserSetting;
/** @format */
import { FunctionComponent, useEffect, useState } from "react";
import { ProCard } from "@ant-design/pro-components";
import {
Avatar,
Button,
Flex,
Form,
FormProps,
Input,
message,
Select,
Skeleton,
Space,
Tabs,
Tag,
} from "antd";
import styles from "./index.module.less";
import TextArea from "antd/es/input/TextArea";
import { getUserInfoApi, updateUserInfo } from "@/api/user";
import { observer } from "mobx-react";
import useStore from "@/utils/store/useStore.tsx";
const UserSetting: FunctionComponent = observer(() => {
const [disable, setDisable] = useState<boolean>(true);
const [loading, setLoading] = useState<boolean>(true);
const [userInfo, setUserInfo] = useState<any>({} as any);
const [password, setPassword] = useState<string>("");
const [phone, setPhone] = useState<string>("");
const [email, setEmail] = useState<string>("");
const store = useStore("user");
const userId: any = store.getUserId();
async function getUserInfo() {
getUserInfoApi(userId).then((res: any) => {
console.log(res);
if (res && res.success && res.data) {
setUserInfo(res.data);
setLoading(false);
}
});
}
type FieldType = {
nickName?: string;
// location?: string;
introduce?: string;
gender?: string;
company?: string;
blog?: string;
};
async function updateUser(data: any) {
updateUserInfo(data).then((res: any) => {
if (res && res.success) {
message.open({
type: "success",
content: "修改成功",
});
} else {
message.open({
type: "error",
content: "修改失败",
});
}
});
}
const onFinish: FormProps<FieldType>["onFinish"] = (values) => {
const data: any = {
id: userId,
...values,
};
updateUserInfo(data).then((res: any) => {
if (res && res.success) {
message.open({
type: "success",
content: "修改成功",
});
} else {
message.open({
type: "error",
content: "修改失败",
});
}
});
};
const onFinishFailed: FormProps<FieldType>["onFinishFailed"] = (errorInfo: any) => {
message.open({
type: "error",
content: errorInfo,
});
};
useEffect(() => {
getUserInfo().then();
}, []);
const prefixSelector = (
<Select style={{ width: 90 }}>
<Select.Option value="https://">https://</Select.Option>
<Select.Option value="http://">http://</Select.Option>
</Select>
);
// const ProFormText = (props: any) => {
// return (
// <ProForm.Item {...props} style={{ height: "10px" }}>
// <ProFormCascader
// request={async () => city}
// width="md"
// name="location"
// disabled={disable}></ProFormCascader>
// </ProForm.Item>
// );
// };
useEffect(() => {}, []);
const TabItems = [
{
label: <span></span>,
key: "baseInfo",
children: (
<>
<Skeleton loading={loading} active>
<div>
<Form
name="basic"
labelCol={{ span: 3 }}
wrapperCol={{ span: 16 }}
style={{ maxWidth: 600 }}
onFinish={onFinish}
onFinishFailed={onFinishFailed}
initialValues={{ prefix: "https://" }}
autoComplete="off">
{/*<Form.Item<FieldType>*/}
{/* label="邮箱"*/}
{/* name="email"*/}
{/* rules={[*/}
{/* {*/}
{/* type: "email",*/}
{/* message: "请输入正确的邮箱!",*/}
{/* },*/}
{/* { required: true, message: "请输入邮箱!" },*/}
{/* ]}>*/}
{/* <Input allowClear disabled={disable} />*/}
{/*</Form.Item>*/}
<Form.Item<FieldType>
label="昵称"
name="nickName"
rules={[
{
type: "string",
message:
"用户名只能是3到16位字母数字下划线减号",
pattern: /^[a-zA-Z0-9_-]{3,16}$/,
},
{
required: true,
message: "请输入昵称!",
},
]}>
<Input allowClear disabled={disable} />
</Form.Item>
<Form.Item<FieldType>
label="性别"
name="gender"
rules={[{ required: true, message: "请输入性别!" }]}>
<Select disabled={disable}>
<Select.Option value="男"></Select.Option>
<Select.Option value="女"></Select.Option>
<Select.Option value="UNKNOWN"></Select.Option>
</Select>
</Form.Item>
{/*<Form.Item<FieldType>*/}
{/* label="地区"*/}
{/* name="location"*/}
{/* rules={[{ required: true, message: "请输入地区!" }]}>*/}
{/* <ProFormText />*/}
{/*</Form.Item>*/}
<Form.Item<FieldType> label="公司" name="company">
<Input allowClear disabled={disable} />
</Form.Item>
<Form.Item<FieldType> label="博客" name="blog">
<Input
addonBefore={prefixSelector}
allowClear
disabled={disable}
/>
</Form.Item>
<Form.Item<FieldType> label="个人简介" name="introduce">
<TextArea
rows={4}
allowClear
maxLength={200}
showCount
placeholder="请输入您的个人简介最多不超过200字。"
disabled={disable}
/>
</Form.Item>
<Form.Item wrapperCol={{ offset: 3, span: 16 }}>
<Space
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
width: "400px",
}}>
<Button
htmlType="button"
onClick={() => {
setDisable(!disable);
}}>
</Button>
<Button type="primary" htmlType="submit" disabled={disable}>
</Button>
</Space>
</Form.Item>
</Form>
</div>
</Skeleton>
</>
),
},
{
label: <span></span>,
key: "security",
children: (
<>
<Skeleton loading={loading} active>
<Space direction={"vertical"} style={{ width: "100%" }}>
<ProCard hoverable bordered>
<Flex vertical={false} align={"center"}>
<span style={{ width: 100 }}></span>
<Space.Compact style={{ width: "100%" }}>
<Input.Password
onChange={(e: any) => {
setPassword(e.target.value);
}}
variant="borderless"
/>
<Button
type="text"
onClick={async () => {
const data: any = {
id: userId,
password: password,
};
await updateUser(data);
}}>
</Button>
</Space.Compact>
</Flex>
</ProCard>
<ProCard hoverable bordered>
<Flex vertical={false} align={"center"}>
<span style={{ width: 100 }}></span>
<Space.Compact style={{ width: "100%" }}>
<Input.Password
onChange={(e: any) => {
setPhone(e.target.value);
}}
variant="borderless"
/>
<Button
type="text"
onClick={async () => {
const data: any = {
id: userId,
phone: phone,
};
await updateUser(data);
}}>
</Button>
</Space.Compact>
</Flex>
</ProCard>
<ProCard hoverable bordered>
<Flex vertical={false} align={"center"}>
<span style={{ width: 100 }}></span>
<Space.Compact style={{ width: "100%" }}>
<Input.Password
onChange={(e: any) => {
setEmail(e.target.value);
}}
variant="borderless"
/>
<Button
type="text"
onClick={async () => {
const data: any = {
id: userId,
email: email,
};
await updateUser(data);
}}>
</Button>
</Space.Compact>
</Flex>
</ProCard>
</Space>
</Skeleton>
</>
),
},
];
return (
<>
<div className={styles.user_setting_main}>
<ProCard boxShadow>
<Skeleton loading={loading} active avatar>
<div className={styles.user_setting_header}>
<Avatar
size={{ xs: 24, sm: 32, md: 40, lg: 64, xl: 80, xxl: 100 }}
src={userInfo.avatar}
/>
<Flex
vertical={false}
align={"center"}
style={{ height: "100px", marginLeft: 40 }}>
<Flex vertical={true} justify={"flex-start"}>
<Flex vertical={false} align={"center"}>
<span style={{ color: "grey" }}></span>
<span style={{ width: 200 }}>{userInfo.userName}</span>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ marginTop: 20 }}>
<span style={{ color: "grey" }}>ID</span>
<span style={{ width: 200 }}>{userInfo.id}</span>
</Flex>
</Flex>
<Flex vertical={true} style={{ marginLeft: 50 }}>
<Flex vertical={false} align={"center"}>
<span style={{ color: "grey" }}> </span>
<span style={{ width: 130 }}>
{userInfo.email || "---------"}
</span>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ marginTop: 20 }}>
<span style={{ color: "grey" }}></span>
<span style={{ width: 130 }}>
{userInfo.phone || "---------"}
</span>
</Flex>
</Flex>
<Flex vertical={true} style={{ marginLeft: 50 }}>
<Flex vertical={false} align={"center"}>
<span style={{ color: "grey" }}></span>
<span style={{ width: 130 }}>{userInfo.createdTime}</span>
</Flex>
<Flex
vertical={false}
align={"center"}
style={{ marginTop: 20 }}>
<span style={{ color: "grey" }}> </span>
{userInfo.status === 0 ? (
<Tag color={"success"}></Tag>
) : (
<Tag color={"red"}></Tag>
)}
</Flex>
</Flex>
</Flex>
</div>
</Skeleton>
</ProCard>
<div className={styles.user_setting_content}>
<ProCard boxShadow>
<Tabs type="card" items={TabItems}></Tabs>
</ProCard>
</div>
</div>
</>
);
});
export default UserSetting;

View File

@@ -1,74 +1,74 @@
/** @format */
import jpg from "@/assets/icons/files/jpg.svg";
import png from "@/assets/icons/files/png.svg";
import pdf from "@/assets/icons/files/pdf.svg";
import java from "@/assets/icons/files/java.svg";
import ai from "@/assets/icons/files/ai.svg";
import avi from "@/assets/icons/files/avi.svg";
import css from "@/assets/icons/files/css.svg";
import csv from "@/assets/icons/files/csv.svg";
import dbf from "@/assets/icons/files/dbf.svg";
import doc from "@/assets/icons/files/doc.svg";
import dwg from "@/assets/icons/files/dwg.svg";
import exe from "@/assets/icons/files/exe.svg";
import fla from "@/assets/icons/files/fla.svg";
import flash from "@/assets/icons/files/flash.svg";
import gif from "@/assets/icons/files/gif.svg";
import html from "@/assets/icons/files/html.svg";
import iso from "@/assets/icons/files/iso.svg";
import javascript from "@/assets/icons/files/javascript.svg";
import json from "@/assets/icons/files/json-file.svg";
import mp3 from "@/assets/icons/files/mp3.svg";
import mp4 from "@/assets/icons/files/mp4.svg";
import ppt from "@/assets/icons/files/ppt.svg";
import psd from "@/assets/icons/files/psd.svg";
import rtf from "@/assets/icons/files/rtf.svg";
import search from "@/assets/icons/files/search.svg";
import svg from "@/assets/icons/files/svg.svg";
import trash from "@/assets/icons/files/trash.svg";
import trashbox from "@/assets/icons/files/trashbox.svg";
import txt from "@/assets/icons/files/txt.svg";
import xls from "@/assets/icons/files/xls.svg";
import xml from "@/assets/icons/files/xml.svg";
import zip from "@/assets/icons/files/zip.svg";
import rar from "@/assets/icons/files/rar.svg";
import gz from "@/assets/icons/files/gz.svg";
const FileIcon: any = {
jpg: jpg,
png: png,
pdf: pdf,
java: java,
ai: ai,
avi: avi,
css: css,
csv: csv,
dbf: dbf,
doc: doc,
docx: doc,
dwg: dwg,
exe: exe,
fla: fla,
flash: flash,
gif: gif,
html: html,
iso: iso,
javascript: javascript,
json: json,
mp3: mp3,
mp4: mp4,
ppt: ppt,
psd: psd,
rtf: rtf,
search: search,
svg: svg,
trash: trash,
trashbox: trashbox,
txt: txt,
xls: xls,
xml: xml,
zip: zip,
rar: rar,
gz: gz,
};
export default FileIcon;
/** @format */
import jpg from "@/assets/icons/files/jpg.svg";
import png from "@/assets/icons/files/png.svg";
import pdf from "@/assets/icons/files/pdf.svg";
import java from "@/assets/icons/files/java.svg";
import ai from "@/assets/icons/files/ai.svg";
import avi from "@/assets/icons/files/avi.svg";
import css from "@/assets/icons/files/css.svg";
import csv from "@/assets/icons/files/csv.svg";
import dbf from "@/assets/icons/files/dbf.svg";
import doc from "@/assets/icons/files/doc.svg";
import dwg from "@/assets/icons/files/dwg.svg";
import exe from "@/assets/icons/files/exe.svg";
import fla from "@/assets/icons/files/fla.svg";
import flash from "@/assets/icons/files/flash.svg";
import gif from "@/assets/icons/files/gif.svg";
import html from "@/assets/icons/files/html.svg";
import iso from "@/assets/icons/files/iso.svg";
import javascript from "@/assets/icons/files/javascript.svg";
import json from "@/assets/icons/files/json-file.svg";
import mp3 from "@/assets/icons/files/mp3.svg";
import mp4 from "@/assets/icons/files/mp4.svg";
import ppt from "@/assets/icons/files/ppt.svg";
import psd from "@/assets/icons/files/psd.svg";
import rtf from "@/assets/icons/files/rtf.svg";
import search from "@/assets/icons/files/search.svg";
import svg from "@/assets/icons/files/svg.svg";
import trash from "@/assets/icons/files/trash.svg";
import trashbox from "@/assets/icons/files/trashbox.svg";
import txt from "@/assets/icons/files/txt.svg";
import xls from "@/assets/icons/files/xls.svg";
import xml from "@/assets/icons/files/xml.svg";
import zip from "@/assets/icons/files/zip.svg";
import rar from "@/assets/icons/files/rar.svg";
import gz from "@/assets/icons/files/gz.svg";
const FileIcon: any = {
jpg: jpg,
png: png,
pdf: pdf,
java: java,
ai: ai,
avi: avi,
css: css,
csv: csv,
dbf: dbf,
doc: doc,
docx: doc,
dwg: dwg,
exe: exe,
fla: fla,
flash: flash,
gif: gif,
html: html,
iso: iso,
javascript: javascript,
json: json,
mp3: mp3,
mp4: mp4,
ppt: ppt,
psd: psd,
rtf: rtf,
search: search,
svg: svg,
trash: trash,
trashbox: trashbox,
txt: txt,
xls: xls,
xml: xml,
zip: zip,
rar: rar,
gz: gz,
};
export default FileIcon;

View File

@@ -0,0 +1,24 @@
/** @format */
const RandomColor: any = [
"processing",
"success",
"error",
"warning",
"magenta",
"blue",
"geekblue",
"purple",
"#f50",
"#2db7f5",
"#87d068",
"#108ee9",
"red",
"volcano",
"orange",
"gold",
"lime",
"green",
];
const getRandomColor = () => RandomColor[Math.floor(Math.random() * RandomColor.length)];
export default getRandomColor;

View File

@@ -1,34 +1,36 @@
/** @format */
import aliyun from "@/assets/icons/aliyun.svg";
import tencent from "@/assets/icons/tencent.svg";
import huawei from "@/assets/icons/huawei.svg";
import baiduyun from "@/assets/icons/baiduyun.svg";
import minio from "@/assets/icons/minio.svg";
import jdyun from "@/assets/icons/jdyun.svg";
import aws from "@/assets/icons/aws.svg";
import wangyi from "@/assets/icons/wangyi.svg";
import qiniu from "@/assets/icons/qiniu.svg";
import upyun from "@/assets/icons/upyun.svg";
import pinanyun from "@/assets/icons/pinanyun.svg";
import qingyun from "@/assets/icons/qingyun.svg";
import ucloud from "@/assets/icons/ucloud.svg";
import jinshan from "@/assets/icons/jinshan.svg";
const StorageIcon: any = {
ali: aliyun,
tencent: tencent,
huawei: huawei,
baidu: baiduyun,
minio: minio,
jd: jdyun,
aws: aws,
wangyi: wangyi,
qiniu: qiniu,
up: upyun,
pinan: pinanyun,
qingyun: qingyun,
ucloud: ucloud,
jinshan: jinshan,
};
export default StorageIcon;
/** @format */
import aliyun from "@/assets/icons/aliyun.svg";
import tencent from "@/assets/icons/tencent.svg";
import huawei from "@/assets/icons/huawei.svg";
import baiduyun from "@/assets/icons/baiduyun.svg";
import minio from "@/assets/icons/minio.svg";
import jdyun from "@/assets/icons/jdyun.svg";
import aws from "@/assets/icons/aws.svg";
import wangyi from "@/assets/icons/wangyi.svg";
import qiniu from "@/assets/icons/qiniu.svg";
import upyun from "@/assets/icons/upyun.svg";
import pinanyun from "@/assets/icons/pinanyun.svg";
import qingyun from "@/assets/icons/qingyun.svg";
import ucloud from "@/assets/icons/ucloud.svg";
import jinshan from "@/assets/icons/jinshan.svg";
import bucket from "@/assets/icons/bucket.svg";
const StorageIcon: any = {
ali: aliyun,
tencent: tencent,
huawei: huawei,
baidu: baiduyun,
minio: minio,
jd: jdyun,
aws: aws,
wangyi: wangyi,
qiniu: qiniu,
up: upyun,
pinan: pinanyun,
qingyun: qingyun,
ucloud: ucloud,
jinshan: jinshan,
bucket:bucket,
};
export default StorageIcon;

View File

@@ -0,0 +1,11 @@
/** @format */
import { lazy } from "react";
const ShareAdd = lazy(
() =>
new Promise((resolve: any) => {
resolve(import("@/components/Main/Share/components/ShareAdd/ShareAdd.tsx"));
}),
);
export default ShareAdd;

View File

@@ -0,0 +1,11 @@
/** @format */
import { lazy } from "react";
const ShareDetail = lazy(
() =>
new Promise((resolve: any) => {
resolve(import("@/components/Main/Share/components/ShareDetail/ShareDetail.tsx"));
}),
);
export default ShareDetail;

View File

@@ -5,7 +5,7 @@ import { lazy } from "react";
const ShareList = lazy(
() =>
new Promise((resolve: any) => {
resolve(import("@/components/Main/Share/components/ShareList"));
resolve(import("@/components/Main/Share/components/ShareList/ShareList.tsx"));
}),
);
export default ShareList;

View File

@@ -0,0 +1,11 @@
/** @format */
import { lazy } from "react";
const MyFavorites = lazy(
() =>
new Promise((resolve: any) => {
resolve(import("@/components/Main/User/MyFavorites/index.tsx"));
}),
);
export default MyFavorites;

View File

@@ -0,0 +1,11 @@
/** @format */
import { lazy } from "react";
const MyShare = lazy(
() =>
new Promise((resolve: any) => {
resolve(import("@/components/Main/User/MyShare/index.tsx"));
}),
);
export default MyShare;

View File

@@ -1,11 +1,11 @@
/** @format */
import { lazy } from "react";
const MainUserInfo = lazy(
() =>
new Promise((resolve: any) => {
resolve(import("@/components/Main/User/UserInfo"));
}),
);
export default MainUserInfo;
/** @format */
import { lazy } from "react";
const MainUserInfo = lazy(
() =>
new Promise((resolve: any) => {
resolve(import("@/components/Main/User/UserInfo"));
}),
);
export default MainUserInfo;

View File

@@ -1,11 +1,11 @@
/** @format */
import { lazy } from "react";
const MainUserSetting = lazy(
() =>
new Promise((resolve: any) => {
resolve(import("@/components/Main/User/UserSetting"));
}),
);
export default MainUserSetting;
/** @format */
import { lazy } from "react";
const MainUserSetting = lazy(
() =>
new Promise((resolve: any) => {
resolve(import("@/components/Main/User/UserSetting"));
}),
);
export default MainUserSetting;

View File

@@ -13,8 +13,8 @@ import Home from "@/router/modules/home";
import MainHome from "@/router/modules/main/home";
import MainBucket from "@/router/modules/main/bucket";
import MainFile from "@/router/modules/main/file";
import MainUserInfo from "@/router/modules/main/userInfo";
import MainUserSetting from "@/router/modules/main/userSetting";
import MainUserInfo from "@/router/modules/main/user/userInfo";
import MainUserSetting from "@/router/modules/main/user/userSetting";
import MainShare from "@/router/modules/main/share";
import MainSetting from "@/router/modules/main/settings";
import Ali from "@/router/modules/main/settings/ali/ali.ts";
@@ -32,6 +32,7 @@ import Wangyi from "@/router/modules/main/settings/wangyi/wangyi.ts";
import Jinshan from "@/router/modules/main/settings/jinshan/jinshan.ts";
import Qiniu from "@/router/modules/main/settings/qiniu/qiniu.ts";
import ShareList from "@/router/modules/main/share/modules/shareList.tsx";
import ShareDetail from "@/router/modules/main/share/modules/shareDetail.tsx";
import minioBucket from "@/router/modules/main/bucket/createBuckets/minio.ts";
import tencentBucket from "@/router/modules/main/bucket/createBuckets/tencent.ts";
import aliBucket from "@/router/modules/main/bucket/createBuckets/ali.ts";
@@ -45,11 +46,14 @@ import qiniuBucket from "@/router/modules/main/bucket/createBuckets/qiniu.ts";
import ucloudBucket from "@/router/modules/main/bucket/createBuckets/ucloud.ts";
import upBucket from "@/router/modules/main/bucket/createBuckets/up.ts";
import wangyiBucket from "@/router/modules/main/bucket/createBuckets/wangyi.ts";
import ShareAdd from "@/router/modules/main/share/modules/shareAdd.tsx";
import MyShare from "@/router/modules/main/user/myShare";
import MyFavorites from "@/router/modules/main/user/myFavorites";
const routes: RouteObject[] = [
{
path: "/",
Component: (props) => ComponentLoading(Home, props),
element: <Navigate to={"/home"} />,
},
{
path: "/register",
@@ -142,6 +146,10 @@ const routes: RouteObject[] = [
path: "/main/file",
Component: MainFile,
},
{
path: "/main/file/:bucket",
Component: MainFile,
},
{
path: "/main/user/info",
Component: MainUserInfo,
@@ -150,6 +158,15 @@ const routes: RouteObject[] = [
path: "/main/user/setting",
Component: MainUserSetting,
},
{
path: "/main/user/myshare",
Component: MyShare,
},
{
path: "/main/user/favorites",
Component: MyFavorites,
},
{
path: "/main/share",
Component: MainShare,
@@ -158,6 +175,14 @@ const routes: RouteObject[] = [
path: "/main/share/list/:id",
Component: ShareList,
},
{
path: "/main/share/detail/:id",
Component: ShareDetail,
},
{
path: "/main/share/add",
Component: ShareAdd,
},
{
path: "/main/setting",
Component: MainSetting,

View File

@@ -1,9 +1,9 @@
/** @format */
import matchAuth from "./matchRouter.ts";
import { Navigate, useLocation } from "react-router-dom";
import { message } from "antd";
import { getStorageFromKey } from "@/utils/localStorage/config.ts";
import React from "react";
import { message } from "antd";
export default function AuthRoute(props: { children: React.ReactNode }) {
const location: any = useLocation();
const isLogin = getStorageFromKey("token");
@@ -12,13 +12,15 @@ export default function AuthRoute(props: { children: React.ReactNode }) {
const condition: boolean =
(currentPath === "/login" && !isLogin) ||
currentPath === "/404" ||
(currentPath === "register" && !isLogin) ||
(currentPath === "forget" && !isLogin);
(currentPath === "/register" && !isLogin) ||
(currentPath === "/forget" && !isLogin) ||
(currentPath === "/" && !isLogin) ||
(currentPath === "/home" && !isLogin);
// 登录后访问login
const conditionWithLogin: boolean =
(currentPath === "/login" && isLogin) ||
(currentPath === "register" && isLogin) ||
(currentPath === "forget" && isLogin);
(currentPath === "/register" && isLogin) ||
(currentPath === "/forget" && isLogin);
const findPath: any = matchAuth(currentPath);
if (condition) {
@@ -32,14 +34,14 @@ export default function AuthRoute(props: { children: React.ReactNode }) {
return <Navigate to="/404" />;
}
// if (!isLogin) {
// message
// .open({
// content: "请先登录!",
// type: "warning",
// })
// .then();
// return <Navigate to="/login" />;
// }
if (!isLogin) {
message
.open({
content: "请先登录!",
type: "warning",
})
.then();
return <Navigate to="/login" />;
}
return props.children;
}

View File

@@ -1,12 +1,12 @@
/** @format */
import { useUserStore } from "./modules/user.ts";
import { useFileStore } from "@/store/modules/file.ts";
import { UseStorageSettingStore } from "@/store/modules/storage_setting.ts";
/** 将每个Store实例化 */
export const RootStore = {
user: new useUserStore(),
file: new useFileStore(),
storage: new UseStorageSettingStore(),
};
/** @format */
import { useUserStore } from "./modules/user.ts";
import { useFileStore } from "@/store/modules/file.ts";
import { useShareStore } from "@/store/modules/share.ts";
/** 将每个Store实例化 */
export const RootStore = {
user: new useUserStore(),
file: new useFileStore(),
share: new useShareStore(),
};

View File

@@ -1,69 +1,199 @@
/** @format */
import { action, makeObservable, observable } from "mobx";
import { isHydrated, makePersistable } from "mobx-persist-store";
import { handleLocalforage } from "@/utils/localforage";
export class useFileStore {
filePath: [any] = [
{
title: "/ root",
},
];
constructor() {
makeObservable(this, {
filePath: observable,
setFilePath: action,
getFilePath: action,
clearFilePath: action,
getFilePathSecondLast: action,
isHydrated: action,
});
makePersistable(
this,
{
// 在构造函数内使用 makePersistable
name: "file", // 保存的name用于在storage中的名称标识只要不和storage中其他名称重复就可以
properties: ["filePath"], // 要保存的字段这些字段会被保存在name对应的storage中注意不写在这里面的字段将不会被保存刷新页面也将丢失get字段例外。get数据会在数据返回后再自动计算
storage: handleLocalforage, // 保存的位置可以是localStoragesessionstorage
removeOnExpiration: true, //如果 expireIn 具有值且已过期,则在调用 getItem 时将自动删除存储中的数据。默认值为 true。
stringify: false, //如果为 true则数据在传递给 setItem 之前将是 JSON.stringify。默认值为 true。
expireIn: 2592000000, // 一个以毫秒为单位的值,用于确定 getItem 何时不应检索存储中的数据。默认情况下永不过期。
debugMode: false, // 如果为 true将为多个 mobx-persist-store 项调用 console.info。默认值为 false。
},
{
delay: 0, // 允许您设置一个 delay 选项来限制 write 函数的调用次数。默认情况下没有延迟。
fireImmediately: false, // 确定是应立即保留存储数据,还是等到存储中的属性发生更改。 false 默认情况下。
},
).then(
action(() => {
// persist 完成的回调在这里可以执行一些拿到数据后需要执行的操作如果在页面上要判断是否完成persist使用 isHydrated
// console.log(persistStore)
}),
);
}
// 获取文件路径
getFilePath() {
return this.filePath ? this.filePath : [];
}
// 设置文件路径
setFilePath(path: any) {
this.filePath.push(path);
}
// 删除文件路径最后一个
clearFilePath() {
if (this.filePath.length === 1) {
return;
}
this.filePath.pop();
}
// 获取文件路径倒数第二个
getFilePathSecondLast() {
return this.filePath.slice(0, -1).pop();
}
isHydrated() {
return isHydrated(this);
}
}
/** @format */
import { action, makeObservable, observable } from "mobx";
import { isHydrated, makePersistable } from "mobx-persist-store";
import { handleLocalforage } from "@/utils/localforage";
export class useFileStore {
filePath: any[] = []; // 文件路径
currentStorage: string = ""; // 当前存储商
currentBucket: string = ""; // 当前存储桶
currentFile: string = ""; // 当前文件
copyFile: string = ""; // 复制的文件地址
pasteFile: string = ""; //粘贴的地址
copyFileName: string = ""; // 复制的文件名
uploadFileStorage: string = ""; // 上传文件的存储商
uploadFileBucket: string = ""; // 上传文件的存储桶
uploadFilePath: string = ""; // 上传文件的路径
constructor() {
makeObservable(this, {
filePath: observable,
currentStorage: observable,
currentFile: observable,
currentBucket: observable,
copyFile: observable,
pasteFile: observable,
copyFileName: observable,
uploadFileStorage: observable,
uploadFileBucket: observable,
uploadFilePath: observable,
setFilePath: action,
getFilePath: action,
clearFilePath: action,
getFilePathSecondLast: action,
getMiddlePath: action,
clearAllFilePath: action,
getFilePathExceptFirst: action,
setCurrentBucket: action,
setCurrentStorage: action,
getCurrentBucket: action,
getCurrentStorage: action,
getCurrentFile: action,
setCurrentFile: action,
isHydrated: action,
setCopyFile: action,
getCopyFile: action,
setPasteFile: action,
getPasteFile: action,
getCopyFileName: action,
setCopyFileName: action,
setUploadFileStorage: action,
getUploadFileStorage: action,
setUploadFileBucket: action,
getUploadFileBucket: action,
setUploadFilePath: action,
getUploadFilePath: action,
});
makePersistable(
this,
{
// 在构造函数内使用 makePersistable
name: "file", // 保存的name用于在storage中的名称标识只要不和storage中其他名称重复就可以
properties: [
"filePath",
"currentStorage",
"currentBucket",
"currentFile",
"copyFile",
"pasteFile",
"copyFileName",
], // 要保存的字段这些字段会被保存在name对应的storage中注意不写在这里面的字段将不会被保存刷新页面也将丢失get字段例外。get数据会在数据返回后再自动计算
storage: handleLocalforage, // 保存的位置可以是localStoragesessionstorage
// removeOnExpiration: true, //如果 expireIn 具有值且已过期,则在调用 getItem 时将自动删除存储中的数据。默认值为 true。
// stringify: false, //如果为 true则数据在传递给 setItem 之前将是 JSON.stringify。默认值为 true。
// expireIn: 2592000000, // 一个以毫秒为单位的值,用于确定 getItem 何时不应检索存储中的数据。默认情况下永不过期。
// debugMode: false, // 如果为 true将为多个 mobx-persist-store 项调用 console.info。默认值为 false。
},
{
// delay: 0, // 允许您设置一个 delay 选项来限制 write 函数的调用次数。默认情况下没有延迟。
// fireImmediately: false, // 确定是应立即保留存储数据,还是等到存储中的属性发生更改。 false 默认情况下。
},
).then(
action(() => {
// persist 完成的回调在这里可以执行一些拿到数据后需要执行的操作如果在页面上要判断是否完成persist使用 isHydrated
// console.log(persistStore)
}),
);
}
// 获取文件路径
getFilePath() {
return this.filePath ? this.filePath : [];
}
// 设置文件路径
setFilePath(path: any) {
this.filePath.push(path);
}
// 删除文件路径最后一个
clearFilePath() {
if (this.filePath.length === 1) {
return;
}
this.filePath.pop();
}
// 清空所有文件路径
clearAllFilePath() {
this.filePath.splice(0);
}
// 获取文件路径倒数第二个
getFilePathSecondLast() {
return this.filePath.slice(0, -1).pop();
}
// 获取文件路径除了第一个
getFilePathExceptFirst() {
if (this.filePath.length === 1) {
return "";
} else {
return this.filePath.slice(1).join("/");
}
}
// 获取文件路径中间路径
getMiddlePath() {
if (this.filePath.length <= 2) {
return " ";
}
return this.filePath.slice(1, this.filePath.length - 1).join("/");
}
isHydrated() {
return isHydrated(this);
}
// 设置当前存储桶
setCurrentBucket(currentBucket: string) {
this.currentBucket = currentBucket;
}
// 设置当前存储商
setCurrentStorage(currentStorage: string) {
this.currentStorage = currentStorage;
}
// 获取当前存储商
getCurrentStorage() {
return this.currentStorage ? this.currentStorage : null;
}
// 获取当前存储桶
getCurrentBucket() {
return this.currentBucket ? this.currentBucket : null;
}
// 获取当前文件
getCurrentFile() {
return this.currentFile ? this.currentFile : null;
}
// 设置当前文件
setCurrentFile(currentFile: string) {
return (this.currentFile = currentFile);
}
//设置复制文件
setCopyFile(copyFile: string) {
this.copyFile = copyFile;
}
// 设置粘贴文件
setPasteFile(pasteFile: string) {
this.pasteFile = pasteFile;
}
// 获取复制文件
getCopyFile() {
return this.copyFile ? this.copyFile : null;
}
// 获取粘贴文件
getPasteFile() {
return this.pasteFile ? this.pasteFile : null;
}
// 设置文件名称
setCopyFileName(copyFileName: string) {
this.copyFileName = copyFileName;
}
// 获取文件名称
getCopyFileName() {
return this.copyFileName ? this.copyFileName : null;
}
setUploadFileStorage(uploadFileStorage: string) {
this.uploadFileStorage = uploadFileStorage;
}
getUploadFileStorage() {
return this.uploadFileStorage ? this.uploadFileStorage : null;
}
setUploadFileBucket(uploadFileBucket: string) {
this.uploadFileBucket = uploadFileBucket;
}
getUploadFileBucket() {
return this.uploadFileBucket ? this.uploadFileBucket : null;
}
setUploadFilePath(uploadFilePath: string) {
this.uploadFilePath = uploadFilePath;
}
getUploadFilePath() {
return this.uploadFilePath ? this.uploadFilePath : null;
}
}

View File

@@ -0,0 +1,52 @@
/** @format */
import { action, makeObservable, observable } from "mobx";
import { isHydrated, makePersistable } from "mobx-persist-store";
import { handleLocalforage } from "@/utils/localforage";
export class useShareStore {
circleId: string = "";
constructor() {
makeObservable(this, {
circleId: observable,
setCircleId: action,
getCircleId: action,
isHydrated: action,
});
makePersistable(
this,
{
// 在构造函数内使用 makePersistable
name: "shareInfo", // 保存的name用于在storage中的名称标识只要不和storage中其他名称重复就可以
properties: ["circleId"], // 要保存的字段这些字段会被保存在name对应的storage中注意不写在这里面的字段将不会被保存刷新页面也将丢失get字段例外。get数据会在数据返回后再自动计算
storage: handleLocalforage, // 保存的位置可以是localStoragesessionstorage
// removeOnExpiration: true, //如果 expireIn 具有值且已过期,则在调用 getItem 时将自动删除存储中的数据。默认值为 true。
// stringify: false, //如果为 true则数据在传递给 setItem 之前将是 JSON.stringify。默认值为 true。
// expireIn: 2592000000, // 一个以毫秒为单位的值,用于确定 getItem 何时不应检索存储中的数据。默认情况下永不过期。
// debugMode: false, // 如果为 true将为多个 mobx-persist-store 项调用 console.info。默认值为 false。
} as any,
{
// delay: 0, // 允许您设置一个 delay 选项来限制 write 函数的调用次数。默认情况下没有延迟。
// fireImmediately: false, // 确定是应立即保留存储数据,还是等到存储中的属性发生更改。 false 默认情况下。
},
).then(
action(() => {
// persist 完成的回调在这里可以执行一些拿到数据后需要执行的操作如果在页面上要判断是否完成persist使用 isHydrated
// console.log(persistStore)
}),
);
}
getCircleId() {
return this.circleId ? this.circleId : null;
}
isHydrated() {
return isHydrated(this);
}
setCircleId(circleId: string) {
this.circleId = circleId;
}
}

View File

@@ -1,50 +0,0 @@
/** @format */
import { action, makeObservable, observable } from "mobx";
import { isHydrated, makePersistable } from "mobx-persist-store";
import { handleLocalforage } from "@/utils/localforage";
export class UseStorageSettingStore {
selectValue: string = "";
constructor() {
makeObservable(this, {
selectValue: observable,
setSelectValue: action,
getSelectValue: action,
isHydrated: action,
});
makePersistable(
this,
{
// 在构造函数内使用 makePersistable
name: "storage_setting", // 保存的name用于在storage中的名称标识只要不和storage中其他名称重复就可以
properties: ["selectValue"], // 要保存的字段这些字段会被保存在name对应的storage中注意不写在这里面的字段将不会被保存刷新页面也将丢失get字段例外。get数据会在数据返回后再自动计算
storage: handleLocalforage, // 保存的位置可以是localStoragesessionstorage
removeOnExpiration: true, //如果 expireIn 具有值且已过期,则在调用 getItem 时将自动删除存储中的数据。默认值为 true。
stringify: false, //如果为 true则数据在传递给 setItem 之前将是 JSON.stringify。默认值为 true。
expireIn: 2592000000, // 一个以毫秒为单位的值,用于确定 getItem 何时不应检索存储中的数据。默认情况下永不过期。
debugMode: false, // 如果为 true将为多个 mobx-persist-store 项调用 console.info。默认值为 false。
},
{
delay: 0, // 允许您设置一个 delay 选项来限制 write 函数的调用次数。默认情况下没有延迟。
fireImmediately: false, // 确定是应立即保留存储数据,还是等到存储中的属性发生更改。 false 默认情况下。
},
).then(
action(() => {
// persist 完成的回调在这里可以执行一些拿到数据后需要执行的操作如果在页面上要判断是否完成persist使用 isHydrated
// console.log(persistStore)
}),
);
}
getSelectValue() {
return this.selectValue ? this.selectValue : null;
}
setSelectValue(value: any) {
this.selectValue = value;
}
isHydrated() {
return isHydrated(this);
}
}

View File

@@ -1,64 +1,93 @@
/** @format */
import { action, makeObservable, observable } from "mobx";
import { isHydrated, makePersistable } from "mobx-persist-store";
import { handleLocalforage } from "@/utils/localforage";
export class useUserStore {
token: string = "";
userId: string = "";
constructor() {
makeObservable(this, {
token: observable,
userId: observable,
setToken: action,
setUserId: action,
getToken: action,
getUserId: action,
isHydrated: action,
});
makePersistable(
this,
{
// 在构造函数内使用 makePersistable
name: "userInfo", // 保存的name用于在storage中的名称标识只要不和storage中其他名称重复就可以
properties: ["token", "userId"], // 要保存的字段这些字段会被保存在name对应的storage中注意不写在这里面的字段将不会被保存刷新页面也将丢失get字段例外。get数据会在数据返回后再自动计算
storage: handleLocalforage, // 保存的位置可以是localStoragesessionstorage
removeOnExpiration: true, //如果 expireIn 具有值且已过期,则在调用 getItem 时将自动删除存储中的数据。默认值为 true。
stringify: false, //如果为 true则数据在传递给 setItem 之前将是 JSON.stringify。默认值为 true。
expireIn: 2592000000, // 一个以毫秒为单位的值,用于确定 getItem 何时不应检索存储中的数据。默认情况下永不过期。
debugMode: false, // 如果为 true将为多个 mobx-persist-store 项调用 console.info。默认值为 false。
},
{
delay: 0, // 允许您设置一个 delay 选项来限制 write 函数的调用次数。默认情况下没有延迟。
fireImmediately: false, // 确定是应立即保留存储数据,还是等到存储中的属性发生更改。 false 默认情况下。
},
).then(
action(() => {
// persist 完成的回调在这里可以执行一些拿到数据后需要执行的操作如果在页面上要判断是否完成persist使用 isHydrated
// console.log(persistStore)
}),
);
}
getToken() {
return this.token ? this.token : null;
}
getUserId() {
return this.userId ? this.userId : null;
}
isHydrated() {
return isHydrated(this);
}
setToken(token: string) {
this.token = token;
}
setUserId(userId: string) {
this.userId = userId;
}
}
/** @format */
import { action, makeObservable, observable } from "mobx";
import { isHydrated, makePersistable } from "mobx-persist-store";
import { handleLocalforage } from "@/utils/localforage";
export class useUserStore {
token: string = "";
userId: string = "";
name: string = "";
avatar: string = "";
nickname: string = "";
constructor() {
makeObservable(this, {
token: observable,
userId: observable,
name: observable,
avatar: observable,
setToken: action,
setUserId: action,
getToken: action,
getUserId: action,
isHydrated: action,
setName: action,
getName: action,
setAvatar: action,
getAvatar: action,
setNickName: action,
getNickName: action,
});
makePersistable(
this,
{
// 在构造函数内使用 makePersistable
name: "userInfo", // 保存的name用于在storage中的名称标识只要不和storage中其他名称重复就可以
properties: ["token", "userId", "name", "avatar", "nickname"], // 要保存的字段这些字段会被保存在name对应的storage中注意不写在这里面的字段将不会被保存刷新页面也将丢失get字段例外。get数据会在数据返回后再自动计算
storage: handleLocalforage, // 保存的位置可以是localStoragesessionstorage
// removeOnExpiration: true, //如果 expireIn 具有值且已过期,则在调用 getItem 时将自动删除存储中的数据。默认值为 true。
// stringify: false, //如果为 true则数据在传递给 setItem 之前将是 JSON.stringify。默认值为 true。
// expireIn: 2592000000, // 一个以毫秒为单位的值,用于确定 getItem 何时不应检索存储中的数据。默认情况下永不过期。
// debugMode: false, // 如果为 true将为多个 mobx-persist-store 项调用 console.info。默认值为 false。
},
{
// delay: 0, // 允许您设置一个 delay 选项来限制 write 函数的调用次数。默认情况下没有延迟。
// fireImmediately: false, // 确定是应立即保留存储数据,还是等到存储中的属性发生更改。 false 默认情况下。
},
).then(
action(() => {
// persist 完成的回调在这里可以执行一些拿到数据后需要执行的操作如果在页面上要判断是否完成persist使用 isHydrated
// console.log(persistStore)
}),
);
}
getToken() {
return this.token ? this.token : null;
}
getUserId() {
return this.userId ? this.userId : null;
}
isHydrated() {
return isHydrated(this);
}
setToken(token: string) {
this.token = token;
}
setUserId(userId: string) {
this.userId = userId;
}
setName(name: string) {
this.name = name;
}
setNickName(name: string) {
this.nickname = name;
}
getNickName() {
return this.nickname ? this.nickname : null;
}
setAvatar(avatar: string) {
this.avatar = avatar;
}
getName() {
return this.name ? this.name : null;
}
getAvatar() {
return this.avatar ? this.avatar : null;
}
}

57
src/types/user.d.ts vendored Normal file
View File

@@ -0,0 +1,57 @@
/** @format */
/* eslint-disable */
declare namespace API {
type PhoneRegisterRequest = {
phone?: string;
userName?: string;
password?: string;
confirmPassword?: string;
activeCode?: string;
};
type LoginRequest = {
userName?: string;
password?: string;
token: string;
deg: number;
};
type LoginByPhoneRequest = {
phone?: string;
activeCode?: string;
token: string;
deg: number;
};
type findPasswordRequest = {
phone?: string;
password?: string;
confirmPassword?: string;
activeCode?: string;
token: string;
deg: number;
};
type AliOSSConfigRequest = {
userId?:number;
endpoint?:string;
accessKeyId?:string;
accessKeySecret?:string;
}
type MinioOSSConfigRequest = {
userId?:number;
endpoint?:string;
accessKey?:string;
secretKey?:string;
}
type QiniuOSSConfigRequest = {
userId?:number;
endpoint?:string;
accessKey?:string;
secretKey?:string;
region?:string;
}
type TencentOSSConfigRequest = {
userId?:number;
appId?:string;
secretKey?:string;
region?:string;
}
}

View File

@@ -1,261 +0,0 @@
/** @format */
/* eslint-disable */
declare namespace API {
type PhoneRegisterRequest = {
phone?: string;
userName?: string;
password?: string;
confirmPassword?: string;
activeCode?: string;
};
type LoginRequest = {
userName?: string;
password?: string;
token: string;
deg: number;
};
type LoginByPhoneRequest = {
phone?: string;
activeCode?: string;
token: string;
deg: number;
};
type findPasswordRequest = {
phone?: string;
password?: string;
confirmPassword?: string;
activeCode?: string;
token: string;
deg: number;
};
// type ApiResponse<T> = {
// success?: boolean;
// code?: number;
// codeMessage?: string;
// errorMessage?: Map<string, string>;
// showType?: ErrorShowType;
// data: T
// }
// type CurrentUser = {
// name?: string;
// avatar?: string;
// userid?: string;
// email?: string;
// signature?: string;
// title?: string;
// group?: string;
// tags?: { key?: string; label?: string }[];
// notifyCount?: number;
// unreadCount?: number;
// country?: string;
// access?: string;
// geographic?: {
// province?: { label?: string; key?: string };
// city?: { label?: string; key?: string };
// };
// address?: string;
// phone?: string;
// };
//
// type LoginResult = ResponseStructure & {
// data?: {
// token?: string;
// expireDateTime?: number;
// expire?: number;
// timeUnit?: any;
// }
// };
//
// type PageParams = {
// pageNum?: number;
// pageSize?: number;
// };
// type RuleListItem = {
// key?: number;
// disabled?: boolean;
// href?: string;
// avatar?: string;
// name?: string;
// owner?: string;
// desc?: string;
// callNo?: number;
// status?: number;
// updatedAt?: string;
// createdAt?: string;
// progress?: number;
// };
// type RuleList = {
// data?: RuleListItem[];
// /** 列表的内容总数 */
// total?: number;
// success?: boolean;
// };
// interface ResponseStructure {
// success?: boolean;
// code?: number;
// codeMessage?: string;
// errorMessage?: Map<string, string>;
// showType?: ErrorShowType;
// }
// type
// FakeCaptcha = ResponseStructure & {
// data?: boolean,
// };
//
// type PhonePasswordLoginParams = {
// clientId?: string;
// phone?: string;
// password?: string;
// code?: string;
// autoLogin?: boolean;
// };
//
// type PhoneSmsCodeLoginParams = {
// clientId?: string;
// phone?: string;
// smsCode?: string;
// autoLogin?: boolean;
// };
//
// type ErrorResponse = {
// /** 业务约定的错误码 */
// errorCode: string;
// /** 业务上的错误信息 */
// errorMessage?: Map<string, string>;
// /** 业务上的请求是否成功 */
// success?: boolean;
// };
//
// type NoticeIconList = {
// data?: NoticeIconItem[];
// /** 列表的内容总数 */
// total?: number;
// success?: boolean;
// };
// type NoticeIconItemType = 'notification' | 'message' | 'event';
// type NoticeIconItem = {
// id?: string;
// extra?: string;
// key?: string;
// read?: boolean;
// avatar?: string;
// title?: string;
// status?: string;
// datetime?: string;
// description?: string;
// type?: NoticeIconItemType;
// };
// type GenerateMpRegCode = {
// data?: {
// regCode?: string;
// qrCodeUrl?: string;
// expireSeconds?: number;
// ticket?: string;
// url?: string;
// };
// }
// type GetClientId = {
// data?: string;
// }
// type GenerateBase64Code = {
// data?: string;
// }
// type GetClientToken = {
// data?: {
// token?: string;
// expireDateTime?: number;
// expire?: number;
// };
// }
// type PhoneRegisterResponse = ResponseStructure & {
// data?: number;
// }
//
// type CustomValidate = {
// validateStatus?: boolean;
// msg?: string;
// formValue?: any;
// code?: number;
// codeMessage?: string;
// errors?: Map<string, string>;
// validateFields: ValidateFields<Values>;
// }
//
// type ListAccountBookVo = ResponseStructure & {
// data?: {
// total?: number;
// list?: ListAccountBookVoItem[]
// }
// }
// type ListAccountBookVoItem = {
// id: number;
// companyName?: string;
// valueAddedTaxCate?: string;
// accountingStandard?: string;
// startTime?: Date;
// createTime?: Date;
// enableVoucherVerify?: boolean;
// disable?: boolean;
// }
// type GetAccountBookVo = {
// id?: number;
// companyName?: string;
// unifiedSocialCreditCode?: string;
// industryId?: number;
// valueAddedTaxCate?: number;
// enableVoucherVerify?: boolean;
// startTime?: Date;
// accountingStandard?: number;
// enableFixedAssets?: boolean;
// enableCapital?: boolean;
// enablePsi?: boolean;
// }
// type DataDictionaryVo = {
// dataCode?: string;
// dataValue?: string;
// }
//
// type ListTreeMenuVo = {
// id?: number;
// key?: string;
// title?: any;
// icon?: string;
// checked?: boolean;
// children?: ListTreeMenuVo[];
// level?: number;
// };
//
// type ListTreeSelectMenuVo = {
// id?: number;
// value?: string;
// title?: any;
// children?: ListTreeMenuVo[];
// }
//
// type ListRoleVo = {
// id: number;
// roleName?: string;
// disable?: boolean;
// }
//
// type ListSubject = {
// id: number;
// pid?: number;
// valueAddedTaxCate?: string;
// accountingStandard?: string;
// startTime?: Date;
// createTime?: Date;
// enableVoucherVerify?: boolean;
// disable?: boolean;
// }
}

View File

@@ -1,174 +1,163 @@
/** @format */
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import { message } from "antd";
import { getStorageFromKey } from "@/utils/localStorage/config.ts";
class Request {
private instance: AxiosInstance | undefined;
constructor(config: AxiosRequestConfig) {
this.instance = axios.create(config);
// 全局请求拦截
this.instance.interceptors.request.use(
(config) => {
const token: string | null = getStorageFromKey("token");
if (token) {
config.headers.Authorization = `${import.meta.env.VITE_APP_TOKEN_KEY} ${token}`;
}
// if (config.method == "post") {
// config.data = EncryptData(JSON.stringify(config.data));
// }
return config;
},
(error) => {
return Promise.reject(error);
},
);
// 全局响应拦截
this.instance.interceptors.response.use(
(response) => {
// 后端返回字符串表示需要解密操作
// if (typeof response.data == "string") {
// response.data = DecryptData(response.data);
// if (response.status !== 200) {
// message.error(response.statusText).then();
// return Promise.reject(response.data);
// }
// }
return response.data;
},
(error) => {
const { response } = error;
if (response) {
this.handleCode(response.status);
}
if (!window.navigator.onLine) {
message.error("网络连接失败");
// return router.push({
// path: '/404',
// })
return Promise.reject(error);
}
},
);
}
handleCode(code: number): void {
switch (code) {
case 400:
message
.open({
content: "请求错误(400)",
type: "error",
})
.then();
break;
case 401:
message
.open({
content: "未授权,请重新登录(401)",
type: "error",
})
.then();
break;
case 403:
message
.open({
content: "拒绝访问(403)",
type: "error",
})
.then();
break;
case 404:
message
.open({
content: "请求出错(404)",
type: "error",
})
.then();
break;
case 408:
message
.open({
content: "请求超时(408)",
type: "error",
})
.then();
break;
case 500:
message
.open({
content: "服务器错误(500)",
type: "error",
})
.then();
break;
case 501:
message
.open({
content: "服务未实现(501)",
type: "error",
})
.then();
break;
case 502:
message
.open({
content: "网络错误(502)",
type: "error",
})
.then();
break;
case 503:
message
.open({
content: "服务不可用(503)",
type: "error",
})
.then();
break;
case 504:
message
.open({
content: "网络超时(504)",
type: "error",
})
.then();
break;
case 505:
message
.open({
content: "HTTP版本不受支持(505)",
type: "error",
})
.then();
break;
default:
message
.open({
content: `连接出错(${code})!`,
type: "error",
})
.then();
break;
}
}
request<T>(config: AxiosRequestConfig<T>): Promise<T> {
return new Promise<T>((resolve, reject) => {
this.instance
?.request<any, T>(config)
.then((res) => {
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
}
export default Request;
/** @format */
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import { message } from "antd";
import { getStorageFromKey } from "@/utils/localStorage/config.ts";
class Request {
private instance: AxiosInstance | undefined;
constructor(config: AxiosRequestConfig) {
this.instance = axios.create(config);
// 全局请求拦截
this.instance.interceptors.request.use(
(config) => {
const token: string | null = getStorageFromKey("token");
if (token) {
config.headers.Authorization = `${import.meta.env.VITE_APP_TOKEN_KEY} ${token}`;
}
return config;
},
(error) => {
return Promise.reject(error);
},
);
// 全局响应拦截
this.instance.interceptors.response.use(
(response) => {
if (response.data instanceof Blob) {
return response;
} else {
return response.data;
}
},
(error) => {
const { response } = error;
if (response) {
this.handleCode(response.status);
}
if (!window.navigator.onLine) {
message.error("网络连接失败");
return Promise.reject(error);
}
},
);
}
handleCode(code: number): void {
switch (code) {
case 400:
message
.open({
content: "请求错误(400)",
type: "error",
})
.then();
break;
case 401:
message
.open({
content: "未授权,请重新登录(401)",
type: "error",
})
.then();
break;
case 403:
message
.open({
content: "拒绝访问(403)",
type: "error",
})
.then();
break;
case 404:
message
.open({
content: "请求出错(404)",
type: "error",
})
.then();
break;
case 408:
message
.open({
content: "请求超时(408)",
type: "error",
})
.then();
break;
case 500:
message
.open({
content: "服务器错误(500)",
type: "error",
})
.then();
break;
case 501:
message
.open({
content: "服务未实现(501)",
type: "error",
})
.then();
break;
case 502:
message
.open({
content: "网络错误(502)",
type: "error",
})
.then();
break;
case 503:
message
.open({
content: "服务不可用(503)",
type: "error",
})
.then();
break;
case 504:
message
.open({
content: "网络超时(504)",
type: "error",
})
.then();
break;
case 505:
message
.open({
content: "HTTP版本不受支持(505)",
type: "error",
})
.then();
break;
default:
message
.open({
content: `连接出错(${code})!`,
type: "error",
})
.then();
break;
}
}
request<T>(config: AxiosRequestConfig<T>): Promise<T> {
return new Promise<T>((resolve, reject) => {
this.instance
?.request<any, T>(config)
.then((res) => {
resolve(res);
})
.catch((err) => {
reject(err);
});
});
}
}
export default Request;

View File

@@ -1,10 +1,10 @@
/** @format */
import Request from "./request";
const web: Request = new Request({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 5000,
});
export default web;
/** @format */
import Request from "./request";
const web: Request = new Request({
baseURL: import.meta.env.VITE_APP_BASE_API,
// timeout: 10000,
});
export default web;

View File

@@ -1,117 +1,143 @@
/** @format */
import {
GithubFilled,
InfoCircleFilled,
LogoutOutlined,
QuestionCircleFilled,
} from "@ant-design/icons";
import { DefaultFooter, PageContainer, ProCard, ProLayout } from "@ant-design/pro-components";
import settings from "./settings.tsx";
import { Link, Outlet, useLocation } from "react-router-dom";
import logo from "@/assets/images/logo.png";
import { Suspense } from "react";
import { Dropdown } from "antd";
// import { getUserMenuPermission } from "@/api/user";
export default function Layout() {
const location = useLocation();
return (
<div
id="test-pro-layout"
style={{
height: "100vh",
}}>
<ProLayout
logo={logo}
layout={"mix"}
pure={false}
loading={false}
contentWidth={"Fluid"}
title={"五味子云存储"}
siderWidth={216}
menuItemRender={(menuItemProps, defaultDom) => {
if (menuItemProps.isUrl || !menuItemProps.path) {
return defaultDom;
}
return <Link to={menuItemProps.path}>{defaultDom}</Link>;
}}
{...settings}
menu={{
// request: async () => {
// const res: any = await getUserMenuPermission("17");
// return res.data.routes;
// },
type: "group",
defaultOpenAll: false,
hideMenuWhenCollapsed: false,
collapsedShowTitle: false,
}}
disableMobile={false}
location={{
pathname: location.pathname,
}}
avatarProps={{
src: "https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg",
title: "七妮妮",
size: "large",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (props, dom) => {
return (
<Dropdown
menu={{
items: [
{
key: "logout",
icon: <LogoutOutlined />,
label: "退出登录",
},
],
}}>
{dom}
</Dropdown>
);
},
}}
actionsRender={(props: any) => {
// eslint-disable-next-line react/prop-types
if (props.isMobile) return [];
return [
<InfoCircleFilled key="InfoCircleFilled" />,
<QuestionCircleFilled key="QuestionCircleFilled" />,
<GithubFilled key="GithubFilled" />,
];
}}
breadcrumbRender={(routers = []) => [
{
path: "/main/home",
title: "主页",
},
...routers,
]}
footerRender={() => (
<DefaultFooter
links={[
{
key: "schisandra",
title: "schisandra",
href: "https://landaiqing.cn",
},
]}
copyright="2024"
/>
)}>
<PageContainer title={false}>
<ProCard>
<div>
<Suspense>
<Outlet />
</Suspense>
</div>
</ProCard>
</PageContainer>
</ProLayout>
</div>
);
}
/** @format */
import {
GithubFilled,
InfoCircleFilled,
LogoutOutlined,
QuestionCircleFilled,
} from "@ant-design/icons";
import { DefaultFooter, PageContainer, ProCard, ProLayout } from "@ant-design/pro-components";
import { Link, Outlet, useLocation, useNavigate } from "react-router-dom";
import logo from "@/assets/images/logo.png";
import { Suspense } from "react";
import { Dropdown } from "antd";
import settings from "@/views/Main/settings.tsx";
import { logout } from "@/api/user";
import { observer } from "mobx-react";
import useStore from "@/utils/store/useStore.tsx";
import { getUserMenuPermission } from "@/api/user";
import { clearStorage } from "@/utils/localStorage/config.ts";
const Layout = () => {
const location = useLocation();
const store = useStore("user");
const navigate = useNavigate();
return (
<div
id="pro-layout"
style={{
height: "100vh",
}}>
<ProLayout
logo={logo as any}
layout={"mix"}
splitMenus={false}
pure={false}
loading={false}
contentWidth={"Fluid"}
title={"五味子云存储"}
siderWidth={216}
menuItemRender={(menuItemProps, defaultDom) => {
if (menuItemProps.isUrl || !menuItemProps.path) {
return defaultDom;
}
return <Link to={menuItemProps.path}>{defaultDom}</Link>;
}}
{...settings}
menu={{
request: async () => {
const res: any = await getUserMenuPermission(store.getUserId() as any);
return res.data.routes;
},
type: "group",
defaultOpenAll: false,
hideMenuWhenCollapsed: false,
collapsedShowTitle: false,
}}
disableMobile={false}
location={{
pathname: location.pathname,
}}
avatarProps={
{
src: store.getAvatar() || logo,
title: store.getNickName() || store.getName() || "unknown",
size: "large",
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
render: (props, dom) => {
return (
<Dropdown
menu={{
items: [
{
key: "logout",
icon: <LogoutOutlined />,
label: "退出登录",
onClick: () => {
logout(store.getUserId());
clearStorage();
store.setToken("");
store.setUserId("");
store.setAvatar("");
store.setNickName("");
setTimeout(() => {
navigate("/login");
}, 1000);
},
},
],
}}>
{dom}
</Dropdown>
);
},
} as any
}
actionsRender={(props: any) => {
// eslint-disable-next-line react/prop-types
if (props.isMobile) return [];
return [
<InfoCircleFilled key="InfoCircleFilled" />,
<QuestionCircleFilled key="QuestionCircleFilled" />,
<GithubFilled key="GithubFilled" />,
];
}}
breadcrumbRender={(routers = []) => [
{
path: "/main/home",
title: "主页",
},
...routers,
]}
footerRender={() => (
<DefaultFooter
links={[
{
key: "schisandra-1",
title: "五味子云存储",
href: "https://landaiqing.cn",
},
{
key: "schisandra-2",
title: "schisandra cloud storage",
href: "https://landaiqing.cn",
},
]}
copyright="2024 by schisandra"
/>
)}>
<PageContainer title={false} breadcrumb={false as any} ghost={true}>
<ProCard>
<div>
<Suspense>
<Outlet />
</Suspense>
</div>
</ProCard>
</PageContainer>
</ProLayout>
</div>
);
};
export default observer(Layout);

View File

@@ -1,179 +1,189 @@
/** @format */
// import dashboard from "@/assets/images/dashboard.png";
// import bucket from "@/assets/images/bucket.png";
// import file_icon from "@/assets/images/file.png";
// import share_icon from "@/assets/images/share.png";
// import user from "@/assets/images/user.png";
// import user_info_icon from "@/assets/images/userInfo.png";
// import setting from "@/assets/images/setting.png";
// import storage_setting from "@/assets/images/storage_setting.png";
import aliyun from "@/assets/icons/aliyun.svg";
import tencent from "@/assets/icons/tencent.svg";
import huawei from "@/assets/icons/huawei.svg";
import baiduyun from "@/assets/icons/baiduyun.svg";
import minio from "@/assets/icons/minio.svg";
import jdyun from "@/assets/icons/jdyun.svg";
import aws from "@/assets/icons/aws.svg";
import wangyi from "@/assets/icons/wangyi.svg";
import qiniu from "@/assets/icons/qiniu.svg";
import upyun from "@/assets/icons/upyun.svg";
import pinanyun from "@/assets/icons/pinanyun.svg";
import qingyun from "@/assets/icons/qingyun.svg";
import ucloud from "@/assets/icons/ucloud.svg";
import jinshan from "@/assets/icons/jinshan.svg";
export default {
route: {
path: "/",
routes: [
{
index: true,
path: "main/home",
name: "仪表盘",
icon: "https://pic.imgdb.cn/item/668b9176d9c307b7e99e51b9.png",
},
{
path: "main/setting",
name: "存储商",
icon: "https://pic.imgdb.cn/item/668b918cd9c307b7e99e7fbc.png",
},
{
path: "main/bucket",
name: "存储桶",
icon: "https://pic.imgdb.cn/item/668b91a5d9c307b7e99ea40d.png",
},
{
path: "main/file",
name: "文件",
icon: "https://pic.imgdb.cn/item/668b91b7d9c307b7e99eb9fb.png",
},
{
path: "main/share",
name: "分享圈",
icon: "https://pic.imgdb.cn/item/668b91d1d9c307b7e99edb1c.png",
},
{
path: "/",
name: "个人中心",
icon: "https://pic.imgdb.cn/item/668b91e1d9c307b7e99eed3a.png",
routes: [
{
index: true,
path: "main/user/info",
name: "用户信息",
icon: "https://pic.imgdb.cn/item/668b91fbd9c307b7e99f0f90.png",
},
{
path: "main/user/setting",
name: "用户设置",
icon: "https://pic.imgdb.cn/item/668b921ad9c307b7e99f35b2.png",
},
],
},
],
},
location: {
pathname: "/main/home",
},
appList: [
{
icon: aliyun,
title: "阿里云OSS",
desc: "一款海量、安全、低成本、高可靠的云存储服务",
url: "https://www.aliyun.com/product/oss",
target: "_blank",
},
{
icon: tencent,
title: "腾讯云COS",
desc: "由腾讯云推出的分布式存储服务。",
url: "https://cloud.tencent.com/product/cos",
target: "_blank",
},
{
icon: huawei,
title: "华为云OBS",
desc: "安全稳定、性能领先、无限弹性扩展的存储能力",
url: "https://www.huaweicloud.com/intl/zh-cn/product/obs.html",
target: "_blank",
},
{
icon: baiduyun,
title: "百度云BOS",
desc: "一款稳定、安全、高效、高可拓展的云存储服务",
url: "https://cloud.baidu.com/product/bos.html",
target: "_blank",
},
{
icon: minio,
title: "MinIO",
desc: "MinIO 是一款高性能、兼容 S3 的对象存储。",
url: "https://min.io/",
target: "_blank",
},
{
icon: jdyun,
title: "京东云OSS",
desc: "京东云自研的存储海量数据的分布式存储服务",
url: "https://www.jdcloud.com/cn/products/object-storage-service",
target: "_blank",
},
{
icon: aws,
title: "亚马逊S3 ",
desc: "专为任意位置检索任意数量数据的对象存储",
url: "https://aws.amazon.com/cn/s3/?nc2=h_ql_prod_st_s3",
target: "_blank",
},
{
icon: wangyi,
title: "网易数帆NOS",
desc: "高可用、高可靠、高性能的云端存储服务",
url: "https://sf.163.com/product/nos",
target: "_blank",
},
{
icon: qiniu,
title: "七牛云 Kodo",
desc: "非结构化数据存储管理平台,支持中心和边缘存储",
url: "https://www.qiniu.com/products/kodo",
target: "_blank",
},
{
icon: upyun,
title: "又拍云 USS",
desc: "面向非结构化数据的对象存储服务",
url: "https://www.upyun.com/products/file-storage",
target: "_blank",
},
{
icon: pinanyun,
title: "平安云OBS",
desc: "基于大规模分布式高并发存储框架的云存储服务",
url: "https://yun.pingan.com/ssr/products/OBS",
target: "_blank",
},
{
icon: qingyun,
title: "青云",
desc: "安全可靠、低成本的云端存储服务",
url: "https://www.qingcloud.com/products/objectstorage/",
target: "_blank",
},
{
icon: ucloud,
title: "优刻得US3",
desc: "为互联网应用提供非结构化文件云存储的服务",
url: "https://www.ucloud.cn/site/product/ufile.html",
target: "_blank",
},
{
icon: jinshan,
title: "金山云OBS",
desc: "金山云分布式对象存储 KingStorage-OBS",
url: "https://www.ksyun.com/nv/product/ES10000.html",
target: "_blank",
},
],
};
/** @format */
// import dashboard from "@/assets/images/dashboard.png";
// import bucket from "@/assets/images/bucket.png";
// import file_icon from "@/assets/images/file.png";
// import share_icon from "@/assets/images/share.png";
// import user from "@/assets/images/user.png";
// import user_info_icon from "@/assets/images/userInfo.png";
// import setting from "@/assets/images/setting.png";
// import storage_setting from "@/assets/images/storage_setting.png";
import aliyun from "@/assets/icons/aliyun.svg";
import tencent from "@/assets/icons/tencent.svg";
import huawei from "@/assets/icons/huawei.svg";
import baiduyun from "@/assets/icons/baiduyun.svg";
import minio from "@/assets/icons/minio.svg";
import jdyun from "@/assets/icons/jdyun.svg";
import aws from "@/assets/icons/aws.svg";
import wangyi from "@/assets/icons/wangyi.svg";
import qiniu from "@/assets/icons/qiniu.svg";
import upyun from "@/assets/icons/upyun.svg";
import pinanyun from "@/assets/icons/pinanyun.svg";
import qingyun from "@/assets/icons/qingyun.svg";
import ucloud from "@/assets/icons/ucloud.svg";
import jinshan from "@/assets/icons/jinshan.svg";
export default {
// route: {
// path: "/",
// routes: [
// {
// index: true,
// path: "main/home",
// name: "仪表盘",
// icon: "https://pic.imgdb.cn/item/668b9176d9c307b7e99e51b9.png",
// },
// {
// path: "main/setting",
// name: "存储商",
// icon: "https://pic.imgdb.cn/item/668b918cd9c307b7e99e7fbc.png",
// },
// {
// path: "main/bucket",
// name: "存储桶",
// icon: "https://pic.imgdb.cn/item/668b91a5d9c307b7e99ea40d.png",
// },
// {
// path: "main/file",
// name: "文件",
// icon: "https://pic.imgdb.cn/item/668b91b7d9c307b7e99eb9fb.png",
// },
// {
// path: "main/share",
// name: "分享圈",
// icon: "https://pic.imgdb.cn/item/668b91d1d9c307b7e99edb1c.png",
// },
// {
// path: "/",
// name: "个人中心",
// icon: "https://pic.imgdb.cn/item/668b91e1d9c307b7e99eed3a.png",
// routes: [
// {
// index: true,
// path: "main/user/info",
// name: "用户信息",
// icon: "https://pic.imgdb.cn/item/668b91fbd9c307b7e99f0f90.png",
// },
// {
// path: "main/user/setting",
// name: "用户设置",
// icon: "https://pic.imgdb.cn/item/668b921ad9c307b7e99f35b2.png",
// },
// {
// path: "main/user/myshare",
// name: "我的分享",
// icon: "https://pic.imgdb.cn/item/668f8e5fd9c307b7e9f079bf.png",
// },
// {
// path: "main/user/favorites",
// name: "我的收藏",
// icon: "https://pic.imgdb.cn/item/6690e7c0d9c307b7e9738f02.png",
// },
// ],
// },
// ],
// },
location: {
pathname: "/main/home",
},
appList: [
{
icon: aliyun,
title: "阿里云OSS",
desc: "一款海量、安全、低成本、高可靠的云存储服务",
url: "https://www.aliyun.com/product/oss",
target: "_blank",
},
{
icon: tencent,
title: "腾讯云COS",
desc: "由腾讯云推出的分布式存储服务。",
url: "https://cloud.tencent.com/product/cos",
target: "_blank",
},
{
icon: huawei,
title: "华为云OBS",
desc: "安全稳定、性能领先、无限弹性扩展的存储能力",
url: "https://www.huaweicloud.com/intl/zh-cn/product/obs.html",
target: "_blank",
},
{
icon: baiduyun,
title: "百度云BOS",
desc: "一款稳定、安全、高效、高可拓展的云存储服务",
url: "https://cloud.baidu.com/product/bos.html",
target: "_blank",
},
{
icon: minio,
title: "MinIO",
desc: "MinIO 是一款高性能、兼容 S3 的对象存储。",
url: "https://min.io/",
target: "_blank",
},
{
icon: jdyun,
title: "京东云OSS",
desc: "京东云自研的存储海量数据的分布式存储服务",
url: "https://www.jdcloud.com/cn/products/object-storage-service",
target: "_blank",
},
{
icon: aws,
title: "亚马逊S3 ",
desc: "专为任意位置检索任意数量数据的对象存储",
url: "https://aws.amazon.com/cn/s3/?nc2=h_ql_prod_st_s3",
target: "_blank",
},
{
icon: wangyi,
title: "网易数帆NOS",
desc: "高可用、高可靠、高性能的云端存储服务",
url: "https://sf.163.com/product/nos",
target: "_blank",
},
{
icon: qiniu,
title: "七牛云 Kodo",
desc: "非结构化数据存储管理平台,支持中心和边缘存储",
url: "https://www.qiniu.com/products/kodo",
target: "_blank",
},
{
icon: upyun,
title: "又拍云 USS",
desc: "面向非结构化数据的对象存储服务",
url: "https://www.upyun.com/products/file-storage",
target: "_blank",
},
{
icon: pinanyun,
title: "平安云OBS",
desc: "基于大规模分布式高并发存储框架的云存储服务",
url: "https://yun.pingan.com/ssr/products/OBS",
target: "_blank",
},
{
icon: qingyun,
title: "青云",
desc: "安全可靠、低成本的云端存储服务",
url: "https://www.qingcloud.com/products/objectstorage/",
target: "_blank",
},
{
icon: ucloud,
title: "优刻得US3",
desc: "为互联网应用提供非结构化文件云存储的服务",
url: "https://www.ucloud.cn/site/product/ufile.html",
target: "_blank",
},
{
icon: jinshan,
title: "金山云OBS",
desc: "金山云分布式对象存储 KingStorage-OBS",
url: "https://www.ksyun.com/nv/product/ES10000.html",
target: "_blank",
},
],
};

View File

@@ -1,375 +1,373 @@
/** @format */
import { LockOutlined, MobileOutlined, SafetyOutlined, WechatOutlined } from "@ant-design/icons";
import { CaptFieldRef, ProFormCaptcha, ProFormText } from "@ant-design/pro-components";
import { Alert, Button, ConfigProvider, Form, Image, message, Space, Spin, Tabs } from "antd";
import { useEffect, useRef, useState } from "react";
import { TinyColor } from "@ctrl/tinycolor";
import logo from "@/assets/images/logo.png";
import styles from "./index.module.less";
import { observer } from "mobx-react";
import FooterComponent from "@/components/Footer";
import { createClientId, findPassword, generateQRCode, getClientToken, getSms } from "@/api/user";
import RotateCaptcha, { CaptchaInstance, type TicketInfoType } from "react-rotate-captcha";
import { get, load } from "@/api/captcha";
import { useNavigate } from "react-router-dom";
import useStore from "@/utils/store/useStore.tsx";
import { setStorage } from "@/utils/localStorage/config.ts";
import { TimerManager } from "timer-manager-lib";
type LoginType = "phone";
export default observer(() => {
const [form] = Form.useForm();
const captchaRef = useRef<CaptFieldRef | null | undefined>();
const smsCaptcha = useRef<CaptchaInstance>(null);
const findPasswordCaptcha = useRef<CaptchaInstance>(null);
const [loginType, setLoginType] = useState<LoginType>("phone");
const colors = ["#fc6076", "#ff9a44", "#ef9d43", "#e75516"];
const [QRCode, setQRCode] = useState<string>("");
const navigate = useNavigate();
const store = useStore("user");
const timerManager = new TimerManager();
const [loading, setLoading] = useState<boolean>(true);
const getHoverColors = (colors: string[]) =>
colors.map((color) => new TinyColor(color).lighten(5).toString());
const getActiveColors = (colors: string[]) =>
colors.map((color) => new TinyColor(color).darken(5).toString());
async function smsVerify(token: string, deg: number): Promise<TicketInfoType> {
const phone = form.getFieldValue("phone");
const data: any = {
token: token,
deg: deg,
phone: phone,
};
const res: any = await getSms(data);
if (res && res.code === 0) {
message.open({
content: res.data,
type: "success",
duration: 5,
});
} else {
message.open({
content: res.data,
type: "warning",
duration: 5,
});
}
return res;
}
async function findPasswordVerify(token: string, deg: number): Promise<TicketInfoType> {
const mobile = form.getFieldValue("phone");
const captcha = form.getFieldValue("activeCode");
const password = form.getFieldValue("password");
const confirmPassword = form.getFieldValue("confirmPassword");
const data: API.findPasswordRequest = {
token: token,
deg: deg,
phone: mobile,
activeCode: captcha,
password: password,
confirmPassword: confirmPassword,
};
const res: any = await findPassword(data);
if (res && res.success && res.code === 0) {
message.open({
content: res.data,
type: "success",
duration: 5,
});
} else if (res.code === 0 && !res.success) {
message.open({
content: res.data,
type: "error",
duration: 5,
});
}
return res;
}
async function openSmsCaptcha() {
smsCaptcha.current!.open();
}
async function fopenFindPasswordCaptcha() {
findPasswordCaptcha.current!.open();
}
const items = [
{
key: "phone",
label: (
<span>
<SafetyOutlined />
</span>
),
},
];
async function wechatLogin() {
createClientId().then((res: any) => {
generateQRCode(res.data).then((response: any) => {
if (response.success) {
setQRCode(response.data.qrCodeUrl);
setLoading(false);
timerManager.add(() => {
getClientToken(res.data).then((result: any) => {
if (result.success) {
timerManager.clear();
store.setToken(result.data.tokenValue);
store.setUserId(result.data.loginId);
setStorage("token", result.data.tokenValue, 24 * 60 * 30);
setStorage("userId", result.data.loginId, 24 * 60 * 30);
message
.open({
content: "登录成功!",
type: "success",
})
.then();
if (store.getToken() !== null || store.getUserId() !== null) {
setTimeout(() => {
navigate("/main");
}, 2000);
}
}
});
}, 3000);
} else {
message
.open({
content: response.data,
type: "error",
})
.then();
}
});
});
}
useEffect(() => {
wechatLogin().then();
}, []);
return (
<div className={styles.container}>
<RotateCaptcha get={get} load={load} verify={smsVerify} limit={2} ref={smsCaptcha} />
<RotateCaptcha
get={get}
load={load}
verify={findPasswordVerify}
limit={2}
ref={findPasswordCaptcha}
/>
<div className={styles.content}>
<Space>
<Space className={styles.login_content}>
<Space align="center" className={styles.mp_code}>
<Space direction="vertical" align="center">
<span className={styles.mp_code_title}></span>
<Spin tip="Loading" size="large" spinning={loading}>
<Image
preview={false}
height={200}
width={200}
className={styles.mp_code_img}
// src={generateMpRegCodeData.data?.qrCodeUrl}
src={QRCode}
fallback="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMIAAADDCAYAAADQvc6UAAABRWlDQ1BJQ0MgUHJvZmlsZQAAKJFjYGASSSwoyGFhYGDIzSspCnJ3UoiIjFJgf8LAwSDCIMogwMCcmFxc4BgQ4ANUwgCjUcG3awyMIPqyLsis7PPOq3QdDFcvjV3jOD1boQVTPQrgSkktTgbSf4A4LbmgqISBgTEFyFYuLykAsTuAbJEioKOA7DkgdjqEvQHEToKwj4DVhAQ5A9k3gGyB5IxEoBmML4BsnSQk8XQkNtReEOBxcfXxUQg1Mjc0dyHgXNJBSWpFCYh2zi+oLMpMzyhRcASGUqqCZ16yno6CkYGRAQMDKMwhqj/fAIcloxgHQqxAjIHBEugw5sUIsSQpBobtQPdLciLEVJYzMPBHMDBsayhILEqEO4DxG0txmrERhM29nYGBddr//5/DGRjYNRkY/l7////39v///y4Dmn+LgeHANwDrkl1AuO+pmgAAADhlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAqACAAQAAAABAAAAwqADAAQAAAABAAAAwwAAAAD9b/HnAAAHlklEQVR4Ae3dP3PTWBSGcbGzM6GCKqlIBRV0dHRJFarQ0eUT8LH4BnRU0NHR0UEFVdIlFRV7TzRksomPY8uykTk/zewQfKw/9znv4yvJynLv4uLiV2dBoDiBf4qP3/ARuCRABEFAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghggQAQZQKAnYEaQBAQaASKIAQJEkAEEegJmBElAoBEgghgg0Aj8i0JO4OzsrPv69Wv+hi2qPHr0qNvf39+iI97soRIh4f3z58/u7du3SXX7Xt7Z2enevHmzfQe+oSN2apSAPj09TSrb+XKI/f379+08+A0cNRE2ANkupk+ACNPvkSPcAAEibACyXUyfABGm3yNHuAECRNgAZLuYPgEirKlHu7u7XdyytGwHAd8jjNyng4OD7vnz51dbPT8/7z58+NB9+/bt6jU/TI+AGWHEnrx48eJ/EsSmHzx40L18+fLyzxF3ZVMjEyDCiEDjMYZZS5wiPXnyZFbJaxMhQIQRGzHvWR7XCyOCXsOmiDAi1HmPMMQjDpbpEiDCiL358eNHurW/5SnWdIBbXiDCiA38/Pnzrce2YyZ4//59F3ePLNMl4PbpiL2J0L979+7yDtHDhw8vtzzvdGnEXdvUigSIsCLAWavHp/+qM0BcXMd/q25n1vF57TYBp0a3mUzilePj4+7k5KSLb6gt6ydAhPUzXnoPR0dHl79WGTNCfBnn1uvSCJdegQhLI1vvCk+fPu2ePXt2tZOYEV6/fn31dz+shwAR1sP1cqvLntbEN9MxA9xcYjsxS1jWR4AIa2Ibzx0tc44fYX/16lV6NDFLXH+YL32jwiACRBiEbf5KcXoTIsQSpzXx4N28Ja4BQoK7rgXiydbHjx/P25TaQAJEGAguWy0+2Q8PD6/Ki4R8EVl+bzBOnZY95fq9rj9zAkTI2SxdidBHqG9+skdw43borCXO/ZcJdraPWdv22uIEiLA4q7nvvCug8WTqzQveOH26fodo7g6uFe/a17W3+nFBAkRYENRdb1vkkz1CH9cPsVy/jrhr27PqMYvENYNlHAIesRiBYwRy0V+8iXP8+/fvX11Mr7L7ECueb/r48eMqm7FuI2BGWDEG8cm+7G3NEOfmdcTQw4h9/55lhm7DekRYKQPZF2ArbXTAyu4kDYB2YxUzwg0gi/41ztHnfQG26HbGel/crVrm7tNY+/1btkOEAZ2M05r4FB7r9GbAIdxaZYrHdOsgJ/wCEQY0J74TmOKnbxxT9n3FgGGWWsVdowHtjt9Nnvf7yQM2aZU/TIAIAxrw6dOnAWtZZcoEnBpNuTuObWMEiLAx1HY0ZQJEmHJ3HNvGCBBhY6jtaMoEiJB0Z29vL6ls58vxPcO8/zfrdo5qvKO+d3Fx8Wu8zf1dW4p/cPzLly/dtv9Ts/EbcvGAHhHyfBIhZ6NSiIBTo0LNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiECRCjUbEPNCRAhZ6NSiAARCjXbUHMCRMjZqBQiQIRCzTbUnAARcjYqhQgQoVCzDTUnQIScjUohAkQo1GxDzQkQIWejUogAEQo121BzAkTI2agUIkCEQs021JwAEXI2KoUIEKFQsw01J0CEnI1KIQJEKNRsQ80JECFno1KIABEKNdtQcwJEyNmoFCJAhELNNtScABFyNiqFCBChULMNNSdAhJyNSiEC/wGgKKC4YMA4TAAAAABJRU5ErkJggg=="
/>
</Spin>
<Alert
// message={(<span>微信扫码<span>关注公众号</span></span>)}
description={
<div>
<span>
<span className={styles.mp_tips}></span>
</span>
<br />
</div>
}
// type="success"
showIcon={true}
className={styles.alert}
icon={<WechatOutlined />}
/>
</Space>
</Space>
<Form
form={form}
className={styles.login_form}
initialValues={{
autoLogin: true,
}}>
<Space direction="vertical" align="center">
<Space className={styles.logo}>
<img
alt="logo"
src={logo}
style={{ width: "44px", height: "44px" }}
/>
<span></span>
</Space>
<div className={styles.subTitle}></div>
</Space>
<Tabs
centered={true}
items={items}
activeKey={loginType}
onChange={(activeKey) =>
setLoginType(activeKey as LoginType)
}></Tabs>
<>
<ProFormText
fieldProps={{
size: "large",
prefix: <MobileOutlined className={"prefixIcon"} />,
autoComplete: "off",
}}
name="phone"
placeholder="请输入手机号"
rules={[
{
required: true,
message: "请输入手机号!",
},
{
pattern: /^1\d{10}$/,
message: "手机号格式错误!",
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: "large",
prefix: <SafetyOutlined className={"prefixIcon"} />,
}}
captchaProps={{
size: "large",
}}
placeholder={"请输入验证码"}
captchaTextRender={(timing: boolean, count: number) => {
if (timing) {
return `${count} ${"获取验证码"}`;
// return `${"获取验证码"}`;
}
return "获取验证码";
}}
name="activeCode"
phoneName={"phone"}
countDown={60}
rules={[
{
required: true,
message: "请输入验证码!",
},
]}
fieldRef={captchaRef}
onGetCaptcha={async () => {
await openSmsCaptcha();
}}
/>
<ProFormText.Password
name="password"
fieldProps={{
size: "large",
prefix: <LockOutlined className={"prefixIcon"} />,
}}
placeholder="请输入新密码"
rules={[
{
required: true,
message: "请输入新密码!",
},
{
pattern:
/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z\\W]{6,18}$/,
message:
"密码长度需在6~18位字符且必须包含字母和数字",
},
]}
/>
<ProFormText.Password
name="confirmPassword"
dependencies={["password"]}
fieldProps={{
size: "large",
prefix: <LockOutlined className={"prefixIcon"} />,
}}
placeholder="请再次确认密码"
rules={[
{
required: true,
message: "请再次确认密码!",
},
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue("password") === value) {
return Promise.resolve();
}
return Promise.reject(
new Error("两次输入的密码不一致!"),
);
},
}),
]}
/>
</>
<ConfigProvider
theme={{
components: {
Button: {
colorPrimary: `linear-gradient(135deg, ${colors.join(", ")})`,
colorPrimaryHover: `linear-gradient(135deg, ${getHoverColors(colors).join(", ")})`,
colorPrimaryActive: `linear-gradient(135deg, ${getActiveColors(colors).join(", ")})`,
lineWidth: 0,
},
},
}}>
<Button
type="primary"
block
size="large"
onClick={async () => {
const validateFields = [
"phone",
"password",
"activeCode",
"confirmPassword",
];
await form
.validateFields(validateFields)
.then(async () => {
await fopenFindPasswordCaptcha();
})
.catch((error) => {
console.error(error);
});
}}>
</Button>
</ConfigProvider>
</Form>
<a href="/login" className={styles.go_to_register}>
<span></span>
</a>
</Space>
</Space>
</div>
<FooterComponent />
</div>
);
});
/** @format */
import { LockOutlined, MobileOutlined, SafetyOutlined, WechatOutlined } from "@ant-design/icons";
import { CaptFieldRef, ProFormCaptcha, ProFormText } from "@ant-design/pro-components";
import { Alert, Button, ConfigProvider, Form, Image, message, Space, Spin, Tabs } from "antd";
import { useEffect, useRef, useState } from "react";
import { TinyColor } from "@ctrl/tinycolor";
import logo from "@/assets/images/logo.png";
import styles from "./index.module.less";
import { observer } from "mobx-react";
import FooterComponent from "@/components/Footer";
import { createClientId, findPassword, generateQRCode, getClientToken, getSms } from "@/api/user";
import RotateCaptcha, { CaptchaInstance, type TicketInfoType } from "react-rotate-captcha";
import { get, load } from "@/api/captcha";
import { useNavigate } from "react-router-dom";
import useStore from "@/utils/store/useStore.tsx";
import { setStorage } from "@/utils/localStorage/config.ts";
import { TimerManager } from "timer-manager-lib";
type LoginType = "phone";
export default observer(() => {
const [form] = Form.useForm();
const captchaRef = useRef<CaptFieldRef | null | undefined>();
const smsCaptcha = useRef<CaptchaInstance>(null);
const findPasswordCaptcha = useRef<CaptchaInstance>(null);
const [loginType, setLoginType] = useState<LoginType>("phone");
const colors = ["#fc6076", "#ff9a44", "#ef9d43", "#e75516"];
const [QRCode, setQRCode] = useState<string>("");
const navigate = useNavigate();
const store = useStore("user");
const timerManager = new TimerManager();
const [loading, setLoading] = useState<boolean>(true);
const getHoverColors = (colors: string[]) =>
colors.map((color) => new TinyColor(color).lighten(5).toString());
const getActiveColors = (colors: string[]) =>
colors.map((color) => new TinyColor(color).darken(5).toString());
async function smsVerify(token: string, deg: number): Promise<TicketInfoType> {
const phone = form.getFieldValue("phone");
const data: any = {
token: token,
deg: deg,
phone: phone,
};
const res: any = await getSms(data);
if (res && res.code === 0) {
message.open({
content: res.data,
type: "success",
duration: 5,
});
} else {
message.open({
content: res.data,
type: "warning",
duration: 5,
});
}
return res;
}
async function findPasswordVerify(token: string, deg: number): Promise<TicketInfoType> {
const mobile = form.getFieldValue("phone");
const captcha = form.getFieldValue("activeCode");
const password = form.getFieldValue("password");
const confirmPassword = form.getFieldValue("confirmPassword");
const data: API.findPasswordRequest = {
token: token,
deg: deg,
phone: mobile,
activeCode: captcha,
password: password,
confirmPassword: confirmPassword,
};
const res: any = await findPassword(data);
if (res && res.success && res.code === 0) {
message.open({
content: res.data,
type: "success",
duration: 5,
});
} else if (res.code === 0 && !res.success) {
message.open({
content: res.data,
type: "error",
duration: 5,
});
}
return res;
}
async function openSmsCaptcha() {
smsCaptcha.current!.open();
}
async function fopenFindPasswordCaptcha() {
findPasswordCaptcha.current!.open();
}
const items = [
{
key: "phone",
label: (
<span>
<SafetyOutlined />
</span>
),
},
];
async function wechatLogin() {
createClientId().then((res: any) => {
generateQRCode(res.data).then((response: any) => {
if (res && response.success && res.data) {
setQRCode(response.data.qrCodeUrl);
setLoading(false);
timerManager.add(() => {
getClientToken(res.data).then((result: any) => {
if (result.success) {
timerManager.clear();
store.setToken(result.data.tokenValue);
store.setUserId(result.data.loginId);
setStorage("token", result.data.tokenValue, 24 * 60 * 30);
setStorage("userId", result.data.loginId, 24 * 60 * 30);
message
.open({
content: "登录成功!",
type: "success",
})
.then();
if (store.getToken() !== null || store.getUserId() !== null) {
setTimeout(() => {
navigate("/main");
}, 2000);
}
}
});
}, 3000);
} else {
message
.open({
content: response.data,
type: "error",
})
.then();
}
});
});
}
useEffect(() => {
wechatLogin().then();
}, []);
return (
<div className={styles.container}>
<RotateCaptcha get={get} load={load} verify={smsVerify} limit={2} ref={smsCaptcha} />
<RotateCaptcha
get={get}
load={load}
verify={findPasswordVerify}
limit={2}
ref={findPasswordCaptcha}
/>
<div className={styles.content}>
<Space>
<Space className={styles.login_content}>
<Space align="center" className={styles.mp_code}>
<Space direction="vertical" align="center">
<span className={styles.mp_code_title}></span>
<Spin tip="Loading" size="large" spinning={loading}>
<Image
preview={false}
height={200}
width={200}
className={styles.mp_code_img}
// src={generateMpRegCodeData.data?.qrCodeUrl}
src={QRCode}
/>
</Spin>
<Alert
// message={(<span>微信扫码<span>关注公众号</span></span>)}
description={
<div>
<span>
<span className={styles.mp_tips}></span>
</span>
<br />
</div>
}
// type="success"
showIcon={true}
className={styles.alert}
icon={<WechatOutlined />}
/>
</Space>
</Space>
<Form
form={form}
className={styles.login_form}
initialValues={{
autoLogin: true,
}}>
<Space direction="vertical" align="center">
<Space className={styles.logo}>
<img
alt="logo"
src={logo}
style={{ width: "44px", height: "44px" }}
/>
<span></span>
</Space>
<div className={styles.subTitle}></div>
</Space>
<Tabs
centered={true}
items={items}
activeKey={loginType}
onChange={(activeKey) =>
setLoginType(activeKey as LoginType)
}></Tabs>
<>
<ProFormText
fieldProps={{
size: "large",
prefix: <MobileOutlined className={"prefixIcon"} />,
autoComplete: "off",
}}
name="phone"
placeholder="请输入手机号"
rules={[
{
required: true,
message: "请输入手机号!",
},
{
pattern: /^1\d{10}$/,
message: "手机号格式错误!",
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: "large",
prefix: <SafetyOutlined className={"prefixIcon"} />,
}}
captchaProps={{
size: "large",
}}
placeholder={"请输入验证码"}
captchaTextRender={(timing: boolean, count: number) => {
if (timing) {
return `${count} ${"获取验证码"}`;
// return `${"获取验证码"}`;
}
return "获取验证码";
}}
name="activeCode"
phoneName={"phone"}
countDown={60}
rules={[
{
required: true,
message: "请输入验证码!",
},
]}
fieldRef={captchaRef}
onGetCaptcha={async () => {
await openSmsCaptcha();
}}
/>
<ProFormText.Password
name="password"
fieldProps={{
size: "large",
prefix: <LockOutlined className={"prefixIcon"} />,
}}
placeholder="请输入新密码"
rules={[
{
required: true,
message: "请输入新密码!",
},
{
pattern:
/^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z\\W]{6,18}$/,
message:
"密码长度需在6~18位字符且必须包含字母和数字",
},
]}
/>
<ProFormText.Password
name="confirmPassword"
dependencies={["password"]}
fieldProps={{
size: "large",
prefix: <LockOutlined className={"prefixIcon"} />,
}}
placeholder="请再次确认密码"
rules={[
{
required: true,
message: "请再次确认密码!",
},
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue("password") === value) {
return Promise.resolve();
}
return Promise.reject(
new Error("两次输入的密码不一致!"),
);
},
}),
]}
/>
</>
<ConfigProvider
theme={{
components: {
Button: {
colorPrimary: `linear-gradient(135deg, ${colors.join(", ")})`,
colorPrimaryHover: `linear-gradient(135deg, ${getHoverColors(colors).join(", ")})`,
colorPrimaryActive: `linear-gradient(135deg, ${getActiveColors(colors).join(", ")})`,
lineWidth: 0,
},
},
}}>
<Button
type="primary"
block
size="large"
onClick={async () => {
const validateFields = [
"phone",
"password",
"activeCode",
"confirmPassword",
];
await form
.validateFields(validateFields)
.then(async () => {
await fopenFindPasswordCaptcha();
})
.catch((error) => {
console.error(error);
});
}}>
</Button>
</ConfigProvider>
</Form>
<a href="/login" className={styles.go_to_register}>
<span></span>
</a>
</Space>
</Space>
</div>
<FooterComponent />
</div>
);
});

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More