first commit
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
import CryptoJS from 'crypto-js'
|
||||
import {Base64} from 'js-base64'
|
||||
import {i18n} from '@/locale'
|
||||
|
||||
// === 👉 请在这里填写你的 AWS 信息 ===
|
||||
const S3Config = {
|
||||
bucket: 'cheflink', // 你的存储桶名称
|
||||
region: 'us-east-1', // 桶所在区域
|
||||
accessKeyId: 'AKIA3LKQVMAPD3KFPJGS',
|
||||
secretKey: 'tV7yvBESDPemtiHGlFOg/oFxz3L1BNXu8KutKjZS',
|
||||
timeout: 0.1 // 签名有效时间(小时)
|
||||
}
|
||||
|
||||
// === 签名函数 ===
|
||||
function getPolicyBase64(): string {
|
||||
const expiration = new Date(Date.now() + 10 * 60 * 1000).toISOString() // 10分钟有效
|
||||
const policyText = {
|
||||
expiration,
|
||||
conditions: [
|
||||
{bucket: S3Config.bucket},
|
||||
['starts-with', '$key', 'cheflink/'],
|
||||
['starts-with', '$Content-Type', 'image/']
|
||||
]
|
||||
}
|
||||
return Base64.encode(JSON.stringify(policyText))
|
||||
}
|
||||
|
||||
|
||||
function getSignature(policyBase64: string): string {
|
||||
const bytes = CryptoJS.HmacSHA1(policyBase64, S3Config.secretKey)
|
||||
return CryptoJS.enc.Base64.stringify(bytes)
|
||||
}
|
||||
|
||||
// === 图片压缩函数 ===
|
||||
function compressImageIfNeeded(filePath: string, size: number): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef APP-PLUS
|
||||
if (size > 3 * 1024 * 1024) {
|
||||
uni.compressImage({
|
||||
src: filePath,
|
||||
quality: 70,
|
||||
success: res => {
|
||||
uni.getFileInfo({
|
||||
filePath: res.tempFilePath,
|
||||
success: info => resolve(res.tempFilePath),
|
||||
fail: () => resolve(res.tempFilePath),
|
||||
})
|
||||
},
|
||||
fail: err => reject(err),
|
||||
})
|
||||
} else {
|
||||
resolve(filePath)
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
if (size > 3 * 1024 * 1024) {
|
||||
const img = new Image()
|
||||
img.crossOrigin = 'Anonymous'
|
||||
img.onload = function () {
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = img.width
|
||||
canvas.height = img.height
|
||||
const ctx = canvas.getContext('2d')
|
||||
ctx?.drawImage(img, 0, 0, img.width, img.height)
|
||||
canvas.toBlob(
|
||||
blob => {
|
||||
if (blob) {
|
||||
const url = URL.createObjectURL(blob)
|
||||
resolve(url)
|
||||
} else {
|
||||
reject(new Error('图片压缩失败'))
|
||||
}
|
||||
},
|
||||
'image/jpeg',
|
||||
0.7
|
||||
)
|
||||
}
|
||||
img.onerror = () => reject(new Error('图片加载失败'))
|
||||
img.src = filePath
|
||||
} else {
|
||||
resolve(filePath)
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-PLUS || H5
|
||||
resolve(filePath)
|
||||
// #endif
|
||||
})
|
||||
}
|
||||
|
||||
// === S3 上传函数 ===
|
||||
const uploadToS3 = async function (filePath: string, suffix = '.jpg', dir = 'cheflink/'): Promise<string> {
|
||||
if (!filePath) {
|
||||
uni.showToast({icon: 'none', title: i18n.global.t('common.prompt.picture-wrong-please-try-again')})
|
||||
return Promise.reject(new Error('filePath is empty'))
|
||||
}
|
||||
|
||||
// 获取文件信息
|
||||
let fileInfo: UniApp.GetFileInfoSuccessCallbackResult
|
||||
try {
|
||||
fileInfo = await new Promise((resolve, reject) => {
|
||||
uni.getFileInfo({
|
||||
filePath,
|
||||
success: resolve,
|
||||
fail: reject,
|
||||
})
|
||||
})
|
||||
} catch (err) {
|
||||
uni.showToast({icon: 'none', title: i18n.global.t('common.prompt.request-incorrect')})
|
||||
return Promise.reject(err)
|
||||
}
|
||||
|
||||
// 压缩图片(如果大于 3MB)
|
||||
let uploadPath: string
|
||||
try {
|
||||
uploadPath = await compressImageIfNeeded(filePath, fileInfo.size)
|
||||
} catch (err) {
|
||||
uni.showToast({icon: 'none', title: i18n.global.t('common.prompt.request-incorrect')})
|
||||
return Promise.reject(err)
|
||||
}
|
||||
|
||||
// 文件名
|
||||
const filename = Date.now() + Math.floor(Math.random() * 1000) + suffix
|
||||
const key = dir + filename
|
||||
const policyBase64 = getPolicyBase64()
|
||||
const signature = getSignature(policyBase64)
|
||||
const uploadUrl = `https://${S3Config.bucket}.s3.${S3Config.region}.amazonaws.com/`
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: uploadUrl,
|
||||
filePath: uploadPath,
|
||||
name: 'file',
|
||||
formData: {
|
||||
key,
|
||||
AWSAccessKeyId: S3Config.accessKeyId,
|
||||
policy: policyBase64,
|
||||
signature,
|
||||
'Content-Type': 'image/jpeg',
|
||||
},
|
||||
success: res => {
|
||||
if (res.statusCode === 204) {
|
||||
uni.showToast({icon: 'none', title: i18n.global.t('common.operation-success')})
|
||||
resolve(`${uploadUrl}${key}`)
|
||||
} else {
|
||||
uni.showToast({icon: 'none', title: i18n.global.t('common.prompt.up-failed')})
|
||||
reject(new Error(`上传失败,状态码: ${res.statusCode}`))
|
||||
}
|
||||
},
|
||||
fail: err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: i18n.global.t('common.prompt.request-failed-please-try-again-later')
|
||||
})
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export {uploadToS3}
|
||||
|
||||
Reference in New Issue
Block a user