import config from '@/config' import Crypto from '@/utils/oss-upload/common/crypto/crypto.js.js' import '@/utils/oss-upload/common/crypto/hmac.js' import '@/utils/oss-upload/common/crypto/sha1.js' import { Base64 } from '@/utils/oss-upload/common/crypto/base64.js' /** * 生成随机Key */ function storeKey() { let s = []; let hexDigits = "0123456789abcdef"; for (let i = 0; i < 36; i++) { s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); } s[14] = "4"; s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); s[8] = s[13] = s[18] = s[23] = "-"; return s.join(""); } /** * 生成OSS签名配置 */ function generateOSSConfig() { // 设置1小时后过期 let date = new Date() date = date.setHours(date.getHours() + 1) let extime = "" + new Date(date).toISOString() let policyText = { "expiration": extime, "conditions": [ ["content-length-range", 0, 1024 * 1024 * 100] // 设置上传文件的大小限制100MB ] }; const policyBase64 = Base64.encode(JSON.stringify(policyText)) // 生成签名 let bytes = Crypto.HMAC(Crypto.SHA1, policyBase64, config.aliOSS_secretKey, { asBytes: true }); let signature = Crypto.util.bytesToBase64(bytes); return { accessid: config.aliOSS_accessKey, // host: `https://${config.aliOSS_bucketName}.${config.endpoint}`, host: config.staticDomain, signature: signature, policyBase64: policyBase64, } } /** * OSS上传功能(使用签名认证) * @param {Object} file - 文件对象(uni.chooseImage返回的文件) * @returns {Promise} 返回上传结果 */ const uploadImage = async (file) => { try { // 生成OSS配置和签名 const ossConfig = generateOSSConfig() // 生成唯一文件名 const timestamp = Date.now() const randomStr = Math.random().toString(36).substring(2, 8) const fileExtension = getFileExtension(file.name || file.path || '.jpg') const fileName = `avatars/${timestamp}_${randomStr}${fileExtension}` const result = await uni.uploadFile({ url: ossConfig.host, filePath: file.path || file.tempFilePath, name: 'file', formData: { key: fileName, policy: ossConfig.policyBase64, OSSAccessKeyId: ossConfig.accessid, success_action_status: '200', signature: ossConfig.signature, } }) console.log('OSS上传结果:', result) // 检查上传是否成功 if (result.errMsg && result.errMsg.includes("uploadFile:ok")) { const fileUrl = `${config.staticDomain}${fileName}` return { success: true, url: fileUrl, fileName: fileName } } else { throw new Error(`OSS上传失败,状态码: ${result.statusCode}, 错误信息: ${result.errMsg}`) } } catch (error) { console.error('OSS上传失败:', error) return { success: false, error: error.message || 'OSS上传失败' } } } /** * 获取文件扩展名 */ const getFileExtension = (fileName) => { if (!fileName) return '.jpg' const lastDot = fileName.lastIndexOf('.') return lastDot !== -1 ? fileName.substring(lastDot) : '.jpg' } /** * 选择并上传图片到OSS(一步到位) */ const chooseAndUpload = async () => { try { // 选择图片 const chooseResult = await uni.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album', 'camera'] }) if (chooseResult.tempFilePaths && chooseResult.tempFilePaths.length > 0) { const file = { path: chooseResult.tempFilePaths[0], tempFilePath: chooseResult.tempFilePaths[0] } // 显示加载提示 uni.showLoading({ title: '上传中...' }) // 上传文件到OSS const uploadResult = await uploadImage(file) uni.hideLoading() if (uploadResult.success) { uni.showToast({ title: '上传成功!', icon: 'success' }) return uploadResult } else { uni.showToast({ title: uploadResult.error, icon: 'error' }) return null } } } catch (error) { uni.hideLoading() uni.showToast({ title: 'OSS上传失败', icon: 'error' }) console.error('OSS上传失败:', error) return null } } export { uploadImage, chooseAndUpload, getFileExtension }