fix: 文件上传压缩功能修复。
This commit is contained in:
450
src/pages.json
450
src/pages.json
@@ -62,172 +62,12 @@
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/statistic/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/mine",
|
||||
"style": {
|
||||
"navigationBarTitleText": "",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/doctorRecord/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "就医记录"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/doctorRecord/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "就医记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/doctorRecord/costList",
|
||||
"style": {
|
||||
"navigationBarTitleText": "费用明细"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/doctorRecord/costAddEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "费用明细"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/healthRecord/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康档案"
|
||||
}
|
||||
} ,
|
||||
{
|
||||
"path": "pages/health/healthRecord/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康档案"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/healthRecord/details",
|
||||
"style": {
|
||||
"navigationBarTitleText": "档案统计"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/marRecord/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用药记录"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/marRecord/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用药记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/medicineBasic/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "药品基础信息"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/medicineBasic/details",
|
||||
"style": {
|
||||
"navigationBarTitleText": "药品基础信息详情"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/medicineBasic/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "药品基础信息"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/medicineStockIn/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "药品入库清单"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/medicineStockIn/details",
|
||||
"style": {
|
||||
"navigationBarTitleText": "药品入库清单详情"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/medicineStockIn/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "药品入库清单"
|
||||
}
|
||||
}, {
|
||||
"path": "pages/health/medicineStock/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "药品实时库存"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/temperatureRecord/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "体温记录"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/temperatureRecord/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "体温记录"
|
||||
}
|
||||
} ,
|
||||
{
|
||||
"path": "pages/health/processRecord/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "档案过程记录"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/processRecord/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "过程记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/heightWeightRecord/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "身高体重记录"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/milkPowderRecord/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "吃奶记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/milkPowderRecord/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "吃奶记录"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/heightWeightRecord/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "身高体重记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/person/list",
|
||||
@@ -256,81 +96,42 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/statistic/doctorStatistic/index",
|
||||
"path": "pages/health/temperatureRecord/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "就医统计"
|
||||
"navigationBarTitleText": "体温记录"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/temperatureRecord/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "体温记录"
|
||||
}
|
||||
} ,
|
||||
{
|
||||
"path": "pages/health/statistic/healthStatistic/index",
|
||||
"path": "pages/health/heightWeightRecord/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "档案统计"
|
||||
"navigationBarTitleText": "身高体重记录"
|
||||
}
|
||||
}
|
||||
,
|
||||
{
|
||||
"path": "pages/health/milkPowderRecord/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "吃奶记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/statistic/healthScreen/index",
|
||||
"path": "pages/health/milkPowderRecord/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康总览态势"
|
||||
"navigationBarTitleText": "吃奶记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/statistic/recordScreen/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "健康档案态势"
|
||||
}
|
||||
} ,
|
||||
,
|
||||
{
|
||||
"path": "pages/health/statistic/marStatistic/index",
|
||||
"path": "pages/health/heightWeightRecord/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用药统计"
|
||||
}
|
||||
} ,
|
||||
{
|
||||
"path": "pages/health/statistic/temperatureStatistic/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "体温统计"
|
||||
}
|
||||
} ,
|
||||
{
|
||||
"path": "pages/health/statistic/milkPowderStatistic/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "吃奶量统计"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/medicationPlan/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用药计划"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/medicationPlan/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "用药计划"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/chronicDisease/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "慢性疾病档案"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/chronicDisease/addEdit",
|
||||
"style": {
|
||||
"navigationBarTitleText": "慢性疾病档案"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/chronicDisease/details",
|
||||
"style": {
|
||||
"navigationBarTitleText": "慢性疾病详情"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/health/medicationTask/list",
|
||||
"style": {
|
||||
"navigationBarTitleText": "服药任务"
|
||||
"navigationBarTitleText": "身高体重记录"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -393,9 +194,212 @@
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/statistic",
|
||||
"name": "statistic",
|
||||
"pages": [
|
||||
{
|
||||
"path": "index",
|
||||
"style": { "navigationBarTitleText": "统计分析" }
|
||||
},
|
||||
{
|
||||
"path": "doctorStatistic/index",
|
||||
"style": { "navigationBarTitleText": "就医统计" }
|
||||
},
|
||||
{
|
||||
"path": "healthStatistic/index",
|
||||
"style": { "navigationBarTitleText": "档案统计" }
|
||||
},
|
||||
{
|
||||
"path": "healthScreen/index",
|
||||
"style": { "navigationBarTitleText": "健康总览态势" }
|
||||
},
|
||||
{
|
||||
"path": "recordScreen/index",
|
||||
"style": { "navigationBarTitleText": "健康档案态势" }
|
||||
},
|
||||
{
|
||||
"path": "marStatistic/index",
|
||||
"style": { "navigationBarTitleText": "用药统计" }
|
||||
},
|
||||
{
|
||||
"path": "temperatureStatistic/index",
|
||||
"style": { "navigationBarTitleText": "体温统计" }
|
||||
},
|
||||
{
|
||||
"path": "milkPowderStatistic/index",
|
||||
"style": { "navigationBarTitleText": "吃奶量统计" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/medicineBasic",
|
||||
"name": "medicineBasic",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": { "navigationBarTitleText": "药品基础信息" }
|
||||
},
|
||||
{
|
||||
"path": "details",
|
||||
"style": { "navigationBarTitleText": "药品基础信息详情" }
|
||||
},
|
||||
{
|
||||
"path": "addEdit",
|
||||
"style": { "navigationBarTitleText": "药品基础信息" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/medicineStockIn",
|
||||
"name": "medicineStockIn",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": { "navigationBarTitleText": "药品入库清单" }
|
||||
},
|
||||
{
|
||||
"path": "details",
|
||||
"style": { "navigationBarTitleText": "药品入库清单详情" }
|
||||
},
|
||||
{
|
||||
"path": "addEdit",
|
||||
"style": { "navigationBarTitleText": "药品入库清单" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/medicineStock",
|
||||
"name": "medicineStock",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": { "navigationBarTitleText": "药品实时库存" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/medicationPlan",
|
||||
"name": "medicationPlan",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": { "navigationBarTitleText": "用药计划" }
|
||||
},
|
||||
{
|
||||
"path": "addEdit",
|
||||
"style": { "navigationBarTitleText": "用药计划" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/medicationTask",
|
||||
"name": "medicationTask",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": { "navigationBarTitleText": "服药任务" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/marRecord",
|
||||
"name": "marRecord",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": { "navigationBarTitleText": "用药记录" }
|
||||
},
|
||||
{
|
||||
"path": "addEdit",
|
||||
"style": { "navigationBarTitleText": "用药记录" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/doctorRecord",
|
||||
"name": "doctorRecord",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": { "navigationBarTitleText": "就医记录" }
|
||||
},
|
||||
{
|
||||
"path": "addEdit",
|
||||
"style": { "navigationBarTitleText": "就医记录" }
|
||||
},
|
||||
{
|
||||
"path": "costList",
|
||||
"style": { "navigationBarTitleText": "费用明细" }
|
||||
},
|
||||
{
|
||||
"path": "costAddEdit",
|
||||
"style": { "navigationBarTitleText": "费用明细" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/healthRecord",
|
||||
"name": "healthRecord",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": { "navigationBarTitleText": "健康档案" }
|
||||
},
|
||||
{
|
||||
"path": "addEdit",
|
||||
"style": { "navigationBarTitleText": "健康档案" }
|
||||
},
|
||||
{
|
||||
"path": "details",
|
||||
"style": { "navigationBarTitleText": "档案统计" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/processRecord",
|
||||
"name": "processRecord",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": { "navigationBarTitleText": "档案过程记录" }
|
||||
},
|
||||
{
|
||||
"path": "addEdit",
|
||||
"style": { "navigationBarTitleText": "过程记录" }
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"root": "pages/health/chronicDisease",
|
||||
"name": "chronicDisease",
|
||||
"pages": [
|
||||
{
|
||||
"path": "list",
|
||||
"style": { "navigationBarTitleText": "慢性疾病档案" }
|
||||
},
|
||||
{
|
||||
"path": "addEdit",
|
||||
"style": { "navigationBarTitleText": "慢性疾病档案" }
|
||||
},
|
||||
{
|
||||
"path": "details",
|
||||
"style": { "navigationBarTitleText": "慢性疾病详情" }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
],
|
||||
"preloadRule": {
|
||||
"pages/health/index": {
|
||||
"network": "all",
|
||||
"packages": ["medicineBasic", "medicineStockIn", "medicineStock", "medicationPlan", "medicationTask", "marRecord", "doctorRecord", "healthRecord", "processRecord", "chronicDisease"]
|
||||
},
|
||||
"pages/health/statistic/index": {
|
||||
"network": "all",
|
||||
"packages": ["statistic"]
|
||||
}
|
||||
},
|
||||
"tabBar": {
|
||||
"color": "#000000",
|
||||
"selectedColor": "#000000",
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
<script setup>
|
||||
import { getActivity, addActivity, updateActivity, uploadFile } from '@/api/health/activity'
|
||||
import config from '@/config'
|
||||
import { compressImage } from '@/utils/imageCompress'
|
||||
const { proxy } = getCurrentInstance()
|
||||
import { getDicts } from '@/api/system/dict/data.js'
|
||||
import dayjs from 'dayjs'
|
||||
@@ -400,30 +401,32 @@ function chooseImage() {
|
||||
})
|
||||
}
|
||||
|
||||
function uploadImages(paths, index) {
|
||||
async function uploadImages(paths, index) {
|
||||
if (index >= paths.length) {
|
||||
uploading.value = false
|
||||
return
|
||||
}
|
||||
uploading.value = true
|
||||
// H5 端 mask: true 会让页面无法点击,一旦上传出问题会导致用户被“锁住”
|
||||
// 这里改为 mask: false,允许用户取消(会提示正在上传)
|
||||
uni.showLoading({ title: `处理中 ${index + 1}/${paths.length}`, mask: false })
|
||||
try {
|
||||
// 上传前先压缩(超过 500KB 才压,避免小图多走一道)
|
||||
const compressedPath = await compressImage(paths[index])
|
||||
uni.showLoading({ title: `上传中 ${index + 1}/${paths.length}`, mask: false })
|
||||
uploadFile({
|
||||
filePath: paths[index],
|
||||
const res = await uploadFile({
|
||||
filePath: compressedPath,
|
||||
name: 'file'
|
||||
}).then(res => {
|
||||
})
|
||||
const url = (res.data && res.data.url) || res.fileName || res.url
|
||||
if (url) {
|
||||
attachmentList.value.push(normalizeAttachmentUrl(url))
|
||||
}
|
||||
uni.hideLoading()
|
||||
uploadImages(paths, index + 1)
|
||||
}).catch(() => {
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
uploading.value = false
|
||||
proxy.$refs['uToast'].show({ message: `第 ${index + 1} 张上传失败`, type: 'error' })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function deleteImage(index) {
|
||||
|
||||
@@ -114,6 +114,7 @@
|
||||
<script setup>
|
||||
import { getDoctorRecord, addDoctorRecord, updateDoctorRecord, uploadFile } from '@/api/health/doctorRecord'
|
||||
import config from '@/config'
|
||||
import { compressImage } from '@/utils/imageCompress'
|
||||
import { listPerson } from '@/api/health/person'
|
||||
import { listHealthRecord } from '@/api/health/healthRecord'
|
||||
const { proxy } = getCurrentInstance()
|
||||
@@ -457,30 +458,32 @@ function chooseImage() {
|
||||
}
|
||||
|
||||
// 递归上传图片
|
||||
function uploadImages(paths, index) {
|
||||
async function uploadImages(paths, index) {
|
||||
if (index >= paths.length) {
|
||||
uploading.value = false
|
||||
return
|
||||
}
|
||||
uploading.value = true
|
||||
// H5 端 mask: true 会让页面无法点击,一旦上传出问题会导致用户被“锁住”
|
||||
// 这里改为 mask: false,允许用户取消(会提示正在上传)
|
||||
uni.showLoading({ title: `处理中 ${index + 1}/${paths.length}`, mask: false })
|
||||
try {
|
||||
// 上传前先压缩(超过 500KB 才压,避免小图多走一道)
|
||||
const compressedPath = await compressImage(paths[index])
|
||||
uni.showLoading({ title: `上传中 ${index + 1}/${paths.length}`, mask: false })
|
||||
uploadFile({
|
||||
filePath: paths[index],
|
||||
const res = await uploadFile({
|
||||
filePath: compressedPath,
|
||||
name: 'file'
|
||||
}).then(res => {
|
||||
})
|
||||
const url = (res.data && res.data.url) || res.fileName || res.url
|
||||
if (url) {
|
||||
attachmentList.value.push(normalizeAttachmentUrl(url))
|
||||
}
|
||||
uni.hideLoading()
|
||||
uploadImages(paths, index + 1)
|
||||
}).catch(() => {
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
uploading.value = false
|
||||
proxy.$refs['uToast'].show({ message: `第 ${index + 1} 张上传失败`, type: 'error' })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 删除图片
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
<script setup>
|
||||
import {getMedicineBasic, addMedicineBasic, updateMedicineBasic, uploadFile } from '@/api/health/medicineBasic'
|
||||
import config from '@/config'
|
||||
import { compressImage } from '@/utils/imageCompress'
|
||||
const { proxy } = getCurrentInstance()
|
||||
import { getDicts } from '@/api/system/dict/data.js'
|
||||
import dayjs from 'dayjs'
|
||||
@@ -617,19 +618,21 @@ function chooseImage() {
|
||||
}
|
||||
|
||||
// 递归上传图片
|
||||
function uploadImages(paths, index) {
|
||||
async function uploadImages(paths, index) {
|
||||
if (index >= paths.length) {
|
||||
uploading.value = false
|
||||
return
|
||||
}
|
||||
uploading.value = true
|
||||
// H5 端 mask: true 会让页面无法点击,一旦上传出问题会导致用户被“锁住”
|
||||
// 这里改为 mask: false,允许用户取消(会提示正在上传)
|
||||
uni.showLoading({ title: `处理中 ${index + 1}/${paths.length}`, mask: false })
|
||||
try {
|
||||
// 上传前先压缩(超过 500KB 才压,避免小图多走一道)
|
||||
const compressedPath = await compressImage(paths[index])
|
||||
uni.showLoading({ title: `上传中 ${index + 1}/${paths.length}`, mask: false })
|
||||
uploadFile({
|
||||
filePath: paths[index],
|
||||
const res = await uploadFile({
|
||||
filePath: compressedPath,
|
||||
name: 'file'
|
||||
}).then(res => {
|
||||
})
|
||||
// 打印返回数据,便于调试
|
||||
console.log('==== upload response ====', JSON.stringify(res))
|
||||
// 兼容多种返回格式
|
||||
@@ -649,11 +652,11 @@ function uploadImages(paths, index) {
|
||||
}
|
||||
uni.hideLoading()
|
||||
uploadImages(paths, index + 1)
|
||||
}).catch(() => {
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
uploading.value = false
|
||||
proxy.$refs['uToast'].show({ message: `第 ${index + 1} 张上传失败`, type: 'error' })
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 删除图片
|
||||
|
||||
171
src/utils/imageCompress.ts
Normal file
171
src/utils/imageCompress.ts
Normal file
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* 跨端图片压缩工具
|
||||
*
|
||||
* 用途:上传附件前压缩图片,避免大图(特别是手机原图 4MB+)导致上传卡死
|
||||
*
|
||||
* - H5:用 Canvas 重绘 + toDataURL('image/jpeg', quality)
|
||||
* - 小程序/APP:用 uni.compressImage API(quality + compressedWidth)
|
||||
*
|
||||
* 策略:
|
||||
* - 原图小于 500KB 不压(避免无谓耗时)
|
||||
* - 最大宽度限制 1280px(横屏照片)或按比例缩放
|
||||
* - JPEG 质量 0.75(体积约 1/5 ~ 1/10,肉眼几乎无差)
|
||||
* - 透明 PNG 也压成 JPEG(牺牲透明通道换取体积),如需透明可改 quality 调用
|
||||
*
|
||||
* 用法:
|
||||
* import { compressImage } from '@/utils/imageCompress'
|
||||
* const compressed = await compressImage(filePath)
|
||||
* uploadFile({ filePath: compressed, ... })
|
||||
*/
|
||||
|
||||
/** 不压缩的体积阈值(字节),800KB(小图直接跳过,避免无谓耗时) */
|
||||
const SKIP_COMPRESS_SIZE = 800 * 1024
|
||||
/** 最大边长,超过按比例缩放(保留宽高比)。1920px 兼顾清晰度与体积 */
|
||||
const MAX_SIDE = 1920
|
||||
/** JPEG 压缩质量 0~1。0.85 可保证医疗单据/药品说明书文字清晰 */
|
||||
const JPEG_QUALITY = 0.85
|
||||
|
||||
/**
|
||||
* H5 端压缩:Canvas 重绘 + toBlob
|
||||
*/
|
||||
function compressH5(filePath: string): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const img = new Image()
|
||||
img.crossOrigin = 'anonymous'
|
||||
img.onload = () => {
|
||||
try {
|
||||
// 计算缩放后的尺寸
|
||||
let { width, height } = img
|
||||
const longSide = Math.max(width, height)
|
||||
if (longSide > MAX_SIDE) {
|
||||
const scale = MAX_SIDE / longSide
|
||||
width = Math.round(width * scale)
|
||||
height = Math.round(height * scale)
|
||||
}
|
||||
// 创建 canvas 重绘
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = width
|
||||
canvas.height = height
|
||||
const ctx = canvas.getContext('2d')
|
||||
if (!ctx) {
|
||||
resolve(filePath) // 极端情况降级到原图
|
||||
return
|
||||
}
|
||||
// 白底(防止 PNG 透明通道转 JPEG 后变黑)
|
||||
ctx.fillStyle = '#ffffff'
|
||||
ctx.fillRect(0, 0, width, height)
|
||||
ctx.drawImage(img, 0, 0, width, height)
|
||||
// 转成 Blob 返回 ObjectURL(避免 base64 体积膨胀)
|
||||
canvas.toBlob(
|
||||
(blob) => {
|
||||
if (!blob) {
|
||||
resolve(filePath)
|
||||
return
|
||||
}
|
||||
// 释放旧的 ObjectURL(如果是 blob: URL)
|
||||
if (filePath.startsWith('blob:')) {
|
||||
try { URL.revokeObjectURL(filePath) } catch (e) { /* ignore */ }
|
||||
}
|
||||
resolve(URL.createObjectURL(blob))
|
||||
},
|
||||
'image/jpeg',
|
||||
JPEG_QUALITY
|
||||
)
|
||||
} catch (err) {
|
||||
console.warn('[imageCompress] H5 压缩失败,降级原图', err)
|
||||
resolve(filePath)
|
||||
}
|
||||
}
|
||||
img.onerror = (err) => {
|
||||
console.warn('[imageCompress] H5 图片加载失败,降级原图', err)
|
||||
resolve(filePath)
|
||||
}
|
||||
img.src = filePath
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序/APP 端压缩:uni.compressImage
|
||||
*/
|
||||
function compressMP(filePath: string): Promise<string> {
|
||||
return new Promise((resolve) => {
|
||||
uni.compressImage({
|
||||
src: filePath,
|
||||
quality: Math.round(JPEG_QUALITY * 100), // 75
|
||||
compressedWidth: MAX_SIDE,
|
||||
success: (res) => resolve(res.tempFilePath),
|
||||
fail: (err) => {
|
||||
console.warn('[imageCompress] uni.compressImage 失败,降级原图', err)
|
||||
resolve(filePath) // 失败降级
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件大小(字节)。
|
||||
* - H5: blob: / data: URL 用 fetch 解析
|
||||
* - 小程序/APP: uni.getFileInfo
|
||||
*/
|
||||
function getFileSize(filePath: string): Promise<number> {
|
||||
return new Promise((resolve) => {
|
||||
// #ifdef H5
|
||||
try {
|
||||
if (filePath.startsWith('blob:') || filePath.startsWith('data:')) {
|
||||
fetch(filePath)
|
||||
.then(r => r.blob())
|
||||
.then(b => resolve(b.size))
|
||||
.catch(() => resolve(0))
|
||||
return
|
||||
}
|
||||
} catch (e) { /* fallthrough */ }
|
||||
resolve(0) // 无法获取则不压缩(保守策略)
|
||||
return
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
uni.getFileInfo({
|
||||
filePath,
|
||||
success: (res) => resolve(res.size),
|
||||
fail: () => resolve(0)
|
||||
})
|
||||
// #endif
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩图片入口(跨端)
|
||||
* @param filePath 图片临时路径
|
||||
* @returns 压缩后的图片路径(如失败则返回原路径)
|
||||
*/
|
||||
export async function compressImage(filePath: string): Promise<string> {
|
||||
if (!filePath) return filePath
|
||||
try {
|
||||
// 检查体积,小图直接跳过
|
||||
const size = await getFileSize(filePath)
|
||||
if (size > 0 && size < SKIP_COMPRESS_SIZE) {
|
||||
return filePath
|
||||
}
|
||||
// #ifdef H5
|
||||
return await compressH5(filePath)
|
||||
// #endif
|
||||
// #ifndef H5
|
||||
return await compressMP(filePath)
|
||||
// #endif
|
||||
} catch (err) {
|
||||
console.warn('[imageCompress] 压缩过程异常,降级原图', err)
|
||||
return filePath
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量压缩图片(串行执行,避免一次性占用过多内存)
|
||||
* @param filePaths 图片路径数组
|
||||
* @returns 压缩后的路径数组(与入参顺序一致)
|
||||
*/
|
||||
export async function compressImages(filePaths: string[]): Promise<string[]> {
|
||||
const result: string[] = []
|
||||
for (const p of filePaths) {
|
||||
result.push(await compressImage(p))
|
||||
}
|
||||
return result
|
||||
}
|
||||
Reference in New Issue
Block a user