Files
cpms_operation_platform/src/utils/oss.ts
T
2026-07-25 09:39:56 +08:00

122 lines
3.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { OssSignData } from '@/api/upload';
import { fetchOssSign } from '@/api/upload';
/**
* OSS 上传类型
* 1=证件照 2=赛事封面 3=头像 4=富文本 5=Banner
*/
export const OssUploadType = {
IdCard: '1',
EventCover: '2',
Avatar: '3',
RichText: '4',
Banner: '5',
} as const;
export type OssUploadTypeValue = (typeof OssUploadType)[keyof typeof OssUploadType];
/**
* 生成唯一文件名:16 位大小写字母+数字随机串.ext
*/
export function genFileName(filePath: string, fileName?: string): string {
let suffix = '';
if (fileName) {
const dot = fileName.lastIndexOf('.');
suffix = dot >= 0 ? fileName.slice(dot).toLowerCase() : '';
}
if (!suffix && filePath) {
const dot = filePath.lastIndexOf('.');
suffix = dot >= 0 ? filePath.slice(dot).toLowerCase() : '';
}
if (!suffix) suffix = '.jpg';
const random = Array.from({ length: 16 }, () => {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
return chars.charAt(Math.floor(Math.random() * chars.length));
}).join('');
return `${random}${suffix}`;
}
/** 根据签名和文件名构建 OSS 上传 FormData 字段 */
export function buildOssFormData(sign: OssSignData, fileName: string): Record<string, string> {
return {
key: `${sign.dir}${fileName}`,
policy: sign.policy,
'x-oss-signature': sign.signature,
'x-oss-signature-version': 'OSS4-HMAC-SHA256',
'x-oss-credential': sign.x_oss_credential,
'x-oss-date': sign.x_oss_date,
'x-oss-security-token': sign.security_token,
success_action_status: '200',
};
}
/**
* 使用已有签名上传单个文件到 OSSWeb 版,fetch + FormData
*/
export async function uploadFileWithSign(file: File, sign: OssSignData): Promise<string> {
const fileName = genFileName(file.name, file.name);
const key = `${sign.dir}${fileName}`;
const formData = new FormData();
Object.entries(buildOssFormData(sign, fileName)).forEach(([k, v]) => {
formData.append(k, v);
});
formData.append('file', file);
const res = await fetch(sign.host, {
method: 'POST',
body: formData,
});
if (!res.ok) {
throw new Error(`OSS 上传失败:${res.status} ${res.statusText}`);
}
return `${sign.host}/${key}`;
}
/**
* 上传单个文件到 OSS
* @returns 文件访问 URL
*/
export async function uploadFile(file: File, type: OssUploadTypeValue): Promise<{ url: string }> {
const sign = await fetchOssSign(type);
const url = await uploadFileWithSign(file, sign);
return { url };
}
/**
* 逐张上传文件到 OSS(同一批复用同一签名,单张失败不影响后续)
*/
export async function uploadFilesOneByOne(
files: File[],
type: OssUploadTypeValue,
options?: {
onSuccess?: (url: string, index: number) => void | Promise<void>;
onError?: (error: unknown, index: number) => void;
},
): Promise<{ successCount: number; failCount: number }> {
if (files.length === 0) {
return { successCount: 0, failCount: 0 };
}
const sign = await fetchOssSign(type);
let successCount = 0;
let failCount = 0;
for (let i = 0; i < files.length; i++) {
try {
const url = await uploadFileWithSign(files[i], sign);
successCount++;
await options?.onSuccess?.(url, i);
} catch (err) {
failCount++;
options?.onError?.(err, i);
}
}
return { successCount, failCount };
}