Browse Source

feat: oss上传

lihao
nili 5 months ago
parent
commit
cc84ea1953
  1. 7
      package.json
  2. 124
      src/pages/OSSUpload.tsx
  3. 7
      src/pages/SuperAdmin.tsx
  4. 8
      src/services/matrix/admin.ts
  5. 2
      src/services/matrix/index.ts
  6. 45
      src/services/matrix/registerController.ts
  7. 44
      src/services/matrix/typings.d.ts
  8. 21
      src/utils/encryptUtil.ts

7
package.json

@ -4,7 +4,6 @@
"private": true, "private": true,
"description": "An out-of-box UI solution for enterprise applications", "description": "An out-of-box UI solution for enterprise applications",
"scripts": { "scripts": {
"openapi": "max openapi",
"analyze": "cross-env ANALYZE=1 max build", "analyze": "cross-env ANALYZE=1 max build",
"build": "max build", "build": "max build",
"deploy": "npm run build && npm run gh-pages", "deploy": "npm run build && npm run gh-pages",
@ -19,6 +18,7 @@
"lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src ", "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src ",
"lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src", "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
"lint:prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\" --end-of-line auto", "lint:prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\" --end-of-line auto",
"openapi": "max openapi",
"prepare": "husky install", "prepare": "husky install",
"prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\"", "prettier": "prettier -c --write \"**/**.{js,jsx,tsx,ts,less,md,json}\"",
"preview": "npm run build && max preview --port 8000", "preview": "npm run build && max preview --port 8000",
@ -50,6 +50,7 @@
"@ant-design/icons": "^4.8.1", "@ant-design/icons": "^4.8.1",
"@ant-design/pro-components": "^2.6.48", "@ant-design/pro-components": "^2.6.48",
"@umijs/route-utils": "^2.2.2", "@umijs/route-utils": "^2.2.2",
"ali-oss": "^6.20.0",
"antd": "^5.13.2", "antd": "^5.13.2",
"antd-style": "^3.6.1", "antd-style": "^3.6.1",
"classnames": "^2.5.1", "classnames": "^2.5.1",
@ -61,7 +62,8 @@
"rc-util": "^5.38.1", "rc-util": "^5.38.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-helmet-async": "^1.3.0" "react-helmet-async": "^1.3.0",
"spark-md5": "^3.0.2"
}, },
"devDependencies": { "devDependencies": {
"@ant-design/pro-cli": "^3.3.0", "@ant-design/pro-cli": "^3.3.0",
@ -74,6 +76,7 @@
"@types/react": "^18.2.48", "@types/react": "^18.2.48",
"@types/react-dom": "^18.2.18", "@types/react-dom": "^18.2.18",
"@types/react-helmet": "^6.1.11", "@types/react-helmet": "^6.1.11",
"@types/spark-md5": "^3.0.2",
"@umijs/fabric": "^2.14.1", "@umijs/fabric": "^2.14.1",
"@umijs/lint": "^4.1.1", "@umijs/lint": "^4.1.1",
"@umijs/max": "^4.1.1", "@umijs/max": "^4.1.1",

124
src/pages/OSSUpload.tsx

@ -0,0 +1,124 @@
import { toMD5 } from '@/utils/encryptUtil';
import OSS from 'ali-oss';
import { message, Upload, UploadFile, UploadProps } from 'antd';
import React, { useEffect, useState } from 'react';
import { getSts } from '../services/matrix/admin';
interface OSSUploadProps {
onUploadSuccess?: (fileUrl: string) => void;
onUploadError?: (error: any) => void;
}
const OSSUpload: React.FC<OSSUploadProps> = ({ onUploadSuccess, onUploadError }) => {
const [uploading, setUploading] = useState(false);
const [fileList, setFileList] = useState<UploadFile[]>([]);
const [ossClient, setOssClient] = useState<OSS | null>(null);
const { Dragger } = Upload;
useEffect(() => {
async function initOssClient() {
try {
const stsResponse = await getSts(); // 假设你有一个 getSTS 函数可以获取 STS 凭证
if (
!stsResponse.data ||
!stsResponse.data.accessKeySecret ||
!stsResponse.data.accessKeyId
) {
message.error('初始化失败,请稍后再试');
return;
}
const client = new OSS({
region: 'oss-cn-beijing',
accessKeyId: stsResponse.data.accessKeyId,
accessKeySecret: stsResponse.data.accessKeySecret,
stsToken: stsResponse.data.securityToken,
bucket: stsResponse.data.bucket,
});
setOssClient(client);
} catch (error) {
message.error('初始化 OSS 客户端失败');
if (onUploadError) {
onUploadError(error);
}
}
}
initOssClient();
}, [onUploadError]);
const onRemove = (file: UploadFile) => {
const files = (fileList || []).filter((v) => v.url !== file.url);
setFileList(files);
};
const handleUpload: UploadProps['customRequest'] = async (options) => {
const { file } = options;
if (file instanceof File) {
setUploading(true);
try {
const md5 = await toMD5(file);
const fileName = `matrix/${md5}.${file.name.split('.').pop()}`;
await ossClient?.put(fileName, file, {
headers: {
'Content-Type': file.type,
},
});
const fileUrl = `https://apks.bzgames.cn/${fileName}`;
if (onUploadSuccess) {
onUploadSuccess(fileUrl);
}
setUploading(false);
// 将上传成功的文件信息添加到 fileList
setFileList((prevFileList) => [
...prevFileList,
{
uid: file.uid,
name: file.name + ':' + fileUrl,
status: 'done',
url: fileUrl,
},
]);
} catch (error) {
message.error('文件上传失败');
if (onUploadError) {
onUploadError(error);
}
setFileList((prevFileList) => [
...prevFileList,
{
uid: file.uid,
name: file.name,
status: 'error',
},
]);
} finally {
setUploading(false);
}
} else {
message.error('上传文件类型错误');
}
};
return (
<Dragger
fileList={fileList}
multiple
customRequest={handleUpload}
onRemove={onRemove}
disabled={uploading || !ossClient}
onPreview={async (file) => {
await navigator.clipboard.writeText(file.url || '');
message.success('链接复制成功 ' + file.url);
}}
>
<p className="ant-upload-drag-icon">
<i className="anticon anticon-inbox" />
</p>
<p className="ant-upload-text"></p>
<p className="ant-upload-hint">使 MD5 </p>
</Dragger>
);
};
export default OSSUpload;

7
src/pages/SuperAdmin.tsx

@ -26,6 +26,8 @@ import TabPane from 'antd/es/tabs/TabPane';
import moment from 'moment'; import moment from 'moment';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import OSSUpload from './OSSUpload';
// import { RequestOptionsType, ProFieldRequestData } from "@ant-design/pro-utils"; // import { RequestOptionsType, ProFieldRequestData } from "@ant-design/pro-utils";
const SuperAdmin: React.FC = () => { const SuperAdmin: React.FC = () => {
@ -316,7 +318,7 @@ const SuperAdmin: React.FC = () => {
<Form.List name="scheduleTime"> <Form.List name="scheduleTime">
{(fields, { add, remove }) => ( {(fields, { add, remove }) => (
<> <>
{fields.map(({ key, name, ...restField }) => ( {fields.map(({ key, name }) => (
<div key={key}> <div key={key}>
<Form.Item <Form.Item
name={[name, 'time']} name={[name, 'time']}
@ -344,6 +346,9 @@ const SuperAdmin: React.FC = () => {
</Modal> </Modal>
</div> </div>
</TabPane> </TabPane>
<TabPane tab="上传资源" key="3">
<OSSUpload />
</TabPane>
</Tabs> </Tabs>
</PageContainer> </PageContainer>
); );

8
src/services/matrix/admin.ts

@ -80,6 +80,14 @@ export async function deleteWhiteList(
}); });
} }
/** 此处后端没有提供注释 GET /api/admin/getSTS */
export async function getSts(options?: { [key: string]: any }) {
return request<API.RSTSInfo>('/api/admin/getSTS', {
method: 'GET',
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /api/admin/grantApp */ /** 此处后端没有提供注释 POST /api/admin/grantApp */
export async function grantApp( export async function grantApp(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象) // 叠加生成的Param类型 (非body参数swagger默认没有生成对象)

2
src/services/matrix/index.ts

@ -7,9 +7,11 @@ import * as appController from './appController';
import * as device from './device'; import * as device from './device';
import * as loginController from './loginController'; import * as loginController from './loginController';
import * as matrixController from './matrixController'; import * as matrixController from './matrixController';
import * as registerController from './registerController';
export default { export default {
matrixController, matrixController,
loginController, loginController,
registerController,
admin, admin,
device, device,
appController, appController,

45
src/services/matrix/registerController.ts

@ -0,0 +1,45 @@
// @ts-ignore
/* eslint-disable */
import { request } from '@umijs/max';
/** 此处后端没有提供注释 GET /api/citrus/register/getApp */
export async function getApp(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.getAppParams,
options?: { [key: string]: any },
) {
return request<API.RMatrixAppBo>('/api/citrus/register/getApp', {
method: 'GET',
params: {
...params,
},
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /api/citrus/register/sendCode */
export async function sendCode(
// 叠加生成的Param类型 (非body参数swagger默认没有生成对象)
params: API.sendCodeParams,
options?: { [key: string]: any },
) {
return request<API.RVoid>('/api/citrus/register/sendCode', {
method: 'POST',
params: {
...params,
},
...(options || {}),
});
}
/** 此处后端没有提供注释 POST /api/citrus/register/submitRegister */
export async function submitRegister(body: API.RegisterBo, options?: { [key: string]: any }) {
return request<API.RVoid>('/api/citrus/register/submitRegister', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
});
}

44
src/services/matrix/typings.d.ts

@ -78,6 +78,10 @@ declare namespace API {
appId?: string; appId?: string;
}; };
type getAppParams = {
inviteCode: string;
};
type grantAppParams = { type grantAppParams = {
appIds: string; appIds: string;
adminId: number; adminId: number;
@ -207,6 +211,13 @@ declare namespace API {
secret?: string; secret?: string;
}; };
type MatrixAppBo = {
name?: string;
code?: string;
img?: string;
url?: string;
};
type MatrixMockSchedule = { type MatrixMockSchedule = {
id?: number; id?: number;
appId?: number; appId?: number;
@ -278,6 +289,13 @@ declare namespace API {
data?: CurrentUser; data?: CurrentUser;
}; };
type RegisterBo = {
mobile?: string;
code?: string;
pwd?: string;
inviteCode?: string;
};
type RInviteInfo = { type RInviteInfo = {
code?: number; code?: number;
message?: string; message?: string;
@ -338,6 +356,12 @@ declare namespace API {
data?: MatrixAdmin; data?: MatrixAdmin;
}; };
type RMatrixAppBo = {
code?: number;
message?: string;
data?: MatrixAppBo;
};
type ROverviewBo = { type ROverviewBo = {
code?: number; code?: number;
message?: string; message?: string;
@ -362,12 +386,32 @@ declare namespace API {
data?: string; data?: string;
}; };
type RSTSInfo = {
code?: number;
message?: string;
data?: STSInfo;
};
type RVoid = { type RVoid = {
code?: number; code?: number;
message?: string; message?: string;
data?: Record<string, any>; data?: Record<string, any>;
}; };
type sendCodeParams = {
mobile: string;
};
type STSInfo = {
securityToken?: string;
expiration?: string;
accessKeySecret?: string;
accessKeyId?: string;
stsRole?: string;
bucket?: string;
endpoint?: string;
};
type updateScoreParams = { type updateScoreParams = {
score: number; score: number;
}; };

21
src/utils/encryptUtil.ts

@ -0,0 +1,21 @@
import SparkMD5 from 'spark-md5';
async function toMD5(file: File): Promise<string> {
return new Promise((resolve, reject) => {
const spark = new SparkMD5.ArrayBuffer();
const fileReader = new FileReader();
fileReader.onload = (e) => {
spark.append(e.target?.result as ArrayBuffer);
resolve(spark.end());
};
fileReader.onerror = (err) => {
reject(err);
};
fileReader.readAsArrayBuffer(file);
});
}
export { toMD5 };
Loading…
Cancel
Save