nili
6 months ago
8 changed files with 255 additions and 3 deletions
@ -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; |
@ -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 || {}), |
||||
|
}); |
||||
|
} |
@ -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…
Reference in new issue