feat: 添加 S3 文件上传功能,更新 '@capp/eden' 依赖至 0.0.11,优化实名认证表单逻辑

This commit is contained in:
2026-01-18 22:52:44 +07:00
parent 4cdbb5cac1
commit 40ad132ce7
7 changed files with 134 additions and 36 deletions

77
src/utils/aws/s3.ts Normal file
View File

@@ -0,0 +1,77 @@
import type { TreatyBody } from "@/api/types";
import { client, safeClient } from "@/api";
interface UploadOptions {
fetchOptions: UploadFetchOptions;
onProgress?: (progress: number) => void;
signal?: AbortSignal;
}
export type UploadFetchOptions = TreatyBody<typeof client.api.file_storage.upload_url.post>;
export async function uploadToS3(file: File, options: UploadOptions): Promise<string> {
const { onProgress, signal, fetchOptions } = options;
// 1. 获取预签名 URL
const { data, error } = await safeClient(client.api.file_storage.upload_url.post({
...fetchOptions,
}));
if (error.value || !data.value) {
throw new Error("获取上传 URL 失败");
}
const { fileId, uploadUrl, method, headers } = toRefs(data.value);
// 2. 上传文件到 S3
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
// 监听上传进度
xhr.upload.addEventListener("progress", (e: ProgressEvent) => {
if (e.lengthComputable && onProgress) {
const progress = Math.round((e.loaded / e.total) * 100);
onProgress(progress);
}
});
// 上传成功
xhr.addEventListener("load", () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(fileId.value);
}
else {
reject(new Error(`上传失败: ${xhr.status} ${xhr.statusText}`));
}
});
// 网络错误
xhr.addEventListener("error", () => {
reject(new Error("网络错误,上传失败"));
});
// 上传取消
xhr.addEventListener("abort", () => {
reject(new Error("上传已取消"));
});
// 超时
xhr.addEventListener("timeout", () => {
reject(new Error("上传超时"));
});
// 支持外部取消
if (signal) {
signal.addEventListener("abort", () => {
xhr.abort();
});
}
// 开始上传
xhr.open(method.value, uploadUrl.value, true);
for (const [key, value] of Object.entries(headers.value)) {
xhr.setRequestHeader(key, value);
}
xhr.timeout = 300000; // 5分钟超时
xhr.send(file);
});
}