feat: 添加banner页面 添加菜单
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
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',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用已有签名上传单个文件到 OSS(Web 版,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 };
|
||||
}
|
||||
Reference in New Issue
Block a user