import request from '@/utils/request'; import Taro from '@tarojs/taro' import dayjs from 'dayjs'; import crypto from 'crypto-js'; import {Base64} from 'js-base64'; import {FileRecord} from "@/api/system/file/model"; import { TenantId } from "@/config/app"; export async function uploadOssByPath(filePath: string) { return new Promise(async (resolve) => { const date = new Date(); date.setMinutes(date.getMinutes() + 1); const policyText = { expiration: date.toISOString(), // 设置policy过期时间。 conditions: [ // 限制上传大小。 ["content-length-range", 0, 1024 * 1024 * 1024], ], }; let sts = Taro.getStorageSync('sts'); let stsExpired = Taro.getStorageSync('stsExpiredAt'); if (!sts || (stsExpired && dayjs().isAfter(dayjs(stsExpired)))) { // @ts-ignore const {data: {data: {credentials}}} = await request.get(`https://gle-server.websoft.top/api/oss/getSTSToken`) Taro.setStorageSync('sts', credentials) Taro.setStorageSync('stsExpiredAt', credentials.expiration) sts = credentials } console.log(sts) const [filename, ext] = filePath.split('.') const key = `headers/${filename + (Math.random() * 100000)}.${ext}` const policy = Base64.encode(JSON.stringify(policyText)) const signature = computeSignature(sts.accessKeySecret, policy) Taro.uploadFile({ url: 'https://oss.wsdns.cn', name: 'file', filePath, formData: { key, policy, OSSAccessKeyId: sts.accessKeyId, signature, 'x-oss-security-token': sts.securityToken }, success: () => { resolve(`https://oss.wsdns.cn/${key}`) } }) }) } const computeSignature = (accessKeySecret: string, canonicalString: string): string => { return crypto.enc.Base64.stringify(crypto.HmacSHA1(canonicalString, accessKeySecret)); } /** * 上传阿里云OSS */ export async function uploadFileByPath(filePath: string) { const parseResponseToRecord = (res: any): FileRecord => { const statusCode = Number(res?.statusCode) if (Number.isFinite(statusCode) && statusCode !== 200) { throw new Error(`上传失败(HTTP ${statusCode})`) } const raw = res?.data if (raw === null || raw === undefined || raw === '') { throw new Error('上传失败:响应为空') } let data: any if (typeof raw === 'string') { const cleaned = raw.replace(/^\uFEFF/, '').trim() try { data = JSON.parse(cleaned) } catch (_e) { throw new Error('上传失败:响应格式错误') } } else { data = raw } if (data?.code === 0) return data.data as FileRecord const codeHint = data?.code !== undefined && data?.code !== null ? `(code=${String(data.code)})` : '' let msg = String(data?.message || data?.msg || data?.error || data?.errMsg || `上传失败${codeHint}`) try { msg = decodeURIComponent(escape(msg)) } catch (_e) { // ignore } throw new Error(msg || '上传失败') } const tenantIdInStorage = Taro.getStorageSync('TenantId') const tenantId = tenantIdInStorage && String(tenantIdInStorage) === String(TenantId) ? tenantIdInStorage : TenantId const header: Record = { 'content-type': 'application/json', TenantId: String(tenantId) } return new Promise((resolve: (result: FileRecord) => void, reject) => { if (!filePath) { reject(new Error('缺少 filePath')) return } Taro.uploadFile({ url: 'https://server.websoft.top/api/oss/upload', filePath, name: 'file', header, success: (res) => { try { resolve(parseResponseToRecord(res)) } catch (e) { reject(e) } }, fail: (err) => { const msg = String((err as any)?.errMsg || (err as any)?.message || '上传请求失败') reject(new Error(msg)) } }) }) } export async function uploadFile() { return new Promise(async (resolve: (result: FileRecord) => void, reject) => { Taro.chooseImage({ count: 1, sizeType: ['compressed'], sourceType: ['album', 'camera'], success: async (res) => { const tempFilePath = res.tempFilePaths[0]; try { const record = await uploadFileByPath(tempFilePath) resolve(record) } catch (e) { reject(e) } }, fail: (err) => { console.log('选择图片失败', err); reject(new Error('选择图片失败')) } }); }) }