Files
xk-doctor-wx/common/js/oss-upload.js
2026-06-18 17:04:50 +08:00

112 lines
3.6 KiB
JavaScript
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.
/**
* 阿里云 OSS PostObject 直传(对齐 xk-admin oss-upload.ts
*
* 运维:微信小程序 uploadFile 合法域名需包含 OSS host
* 例如 https://xiaokang88.oss-cn-hangzhou.aliyuncs.com
*/
import { getBusinessOssSignatureApi, unwrapOssSignature, registerBusinessOssFile } from '@/api/upload.js';
/**
* @param {string} filePath 本地临时文件路径
* @returns {string} xk_upload_YYYYMMDD/uuid_timestamp.ext
*/
export function generateObjectName(filePath) {
const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, '0');
const day = String(today.getDate()).padStart(2, '0');
const dateStr = `${year}${month}${day}`;
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = (Math.random() * 16) | 0;
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
const timestamp = Math.floor(Date.now() / 1000);
const pathStr = String(filePath || '');
const lastDotIndex = pathStr.lastIndexOf('.');
const extension = lastDotIndex > 0 ? pathStr.substring(lastDotIndex + 1).toLowerCase() : 'jpg';
return `xk_upload_${dateStr}/${uuid}_${timestamp}.${extension}`;
}
function basenameFromPath(filePath) {
const pathStr = String(filePath || '');
const parts = pathStr.split(/[/\\]/);
return parts[parts.length - 1] || '';
}
/**
* @returns {Promise<{ accessKeyId, policy, signature, host, bucket, key, expire }>}
*/
export async function getOssSignatureFromBackend() {
const res = await getBusinessOssSignatureApi();
const signature = unwrapOssSignature(res);
if (!signature) {
throw new Error('获取 OSS 签名失败');
}
return signature;
}
/**
* @param {{ filePath: string, onProgress?: (percent: number) => void }} options
* @returns {Promise<{ url: string, objectName: string }>}
*/
export async function uploadToOss(options) {
const { filePath, onProgress, fileSize = 0, fileName = '' } = options || {};
if (!filePath) {
throw new Error('文件路径为空');
}
const signature = await getOssSignatureFromBackend();
const objectName = generateObjectName(filePath);
const formData = {
key: objectName,
policy: signature.policy,
OSSAccessKeyId: signature.accessKeyId,
signature: signature.signature,
success_action_status: '200',
'x-oss-object-acl': 'public-read',
};
return new Promise((resolve, reject) => {
const uploadTask = uni.uploadFile({
url: signature.host,
filePath,
name: 'file',
formData,
success: (uploadRes) => {
const code = uploadRes.statusCode;
if (code >= 200 && code < 300 || code === 204) {
const host = String(signature.host).replace(/\/$/, '');
const url = `${host}/${objectName}`;
const displayName = fileName || basenameFromPath(filePath);
registerBusinessOssFile(url, fileSize, displayName).catch((err) => {
console.warn('OSS 文件登记失败:', err);
});
resolve({
url,
objectName,
});
return;
}
reject(new Error(`OSS 上传失败HTTP ${code}`));
},
fail: (err) => {
reject(err instanceof Error ? err : new Error((err && err.errMsg) || 'OSS 上传失败'));
},
});
if (onProgress && uploadTask && typeof uploadTask.onProgressUpdate === 'function') {
uploadTask.onProgressUpdate((res) => {
if (res.totalBytesExpectedToSend > 0) {
const percent = Math.round((res.totalBytesSent / res.totalBytesExpectedToSend) * 100);
onProgress(percent);
}
});
}
});
}