From dc71590bd9f2ff4cc8fcb8439b32a56f6b479d5e Mon Sep 17 00:00:00 2001 From: Timi Date: Thu, 11 Dec 2025 15:06:50 +0800 Subject: [PATCH] fix progress --- .../pages/main/journal-creater/index.less | 13 +- .../pages/main/journal-creater/index.ts | 143 ++++++++++++------ .../pages/main/journal-creater/index.wxml | 20 ++- .../pages/main/journal-editor/index.less | 13 +- .../pages/main/journal-editor/index.ts | 131 +++++++++++----- .../pages/main/journal-editor/index.wxml | 20 ++- 6 files changed, 240 insertions(+), 100 deletions(-) diff --git a/miniprogram/pages/main/journal-creater/index.less b/miniprogram/pages/main/journal-creater/index.less index fb3896c..69f747b 100644 --- a/miniprogram/pages/main/journal-creater/index.less +++ b/miniprogram/pages/main/journal-creater/index.less @@ -111,9 +111,20 @@ } } - .progress { + .uploading { width: 100%; margin-top: 1rem; + + .progress { + margin-bottom: 8rpx; + } + + .text { + color: var(--theme-text-secondary); + display: flex; + font-size: .8rem; + justify-content: space-between; + } } .ctrl { diff --git a/miniprogram/pages/main/journal-creater/index.ts b/miniprogram/pages/main/journal-creater/index.ts index 2e910b0..f292f82 100644 --- a/miniprogram/pages/main/journal-creater/index.ts +++ b/miniprogram/pages/main/journal-creater/index.ts @@ -4,6 +4,7 @@ import Time from "../../../utils/Time"; import Toolkit from "../../../utils/Toolkit"; import config from "../../../config/index"; import { JournalType } from "../../../types/Journal"; +import IOSize, { Unit } from "../../../utils/IOSize"; enum MediaItemType { IMAGE, @@ -34,6 +35,11 @@ interface JournalEditorData { location?: Location; qqMapSDK?: any; isAuthLocation: boolean; + uploaded: string; + uploadTotal: string; + uploadSpeed: string; + uploadProgress: number; + isSubmitting: boolean; } Page({ @@ -44,13 +50,15 @@ Page({ type: JournalType.NORMAL, mediaList: [], location: undefined, - submitText: "提交", + isAuthLocation: false, + uploaded: "0", + uploadTotal: "0 MB", + uploadSpeed: "0 MB / s", + uploadProgress: 0, isSubmitting: false, - submitProgress: 0, mediaItemTypeEnum: { ...MediaItemType - }, - isAuthLocation: false + } }, async onLoad() { // 授权定位 @@ -194,16 +202,15 @@ Page({ submit() { const handleFail = () => { wx.showToast({ title: "上传失败", icon: "error" }); + wx.hideLoading(); this.setData({ - submitText: "提交", isSubmitting: false - }) + }); }; this.setData({ - submitText: "正在提交..", isSubmitting: true - }) + }); // 获取 openId const getOpenId = new Promise((resolve, reject) => { @@ -239,51 +246,97 @@ Page({ // 文件上传 const uploadFiles = new Promise((resolve, reject) => { const mediaList = this.data.mediaList || []; - const total = mediaList.length; - let completed = 0; - - if (total === 0) { + if (mediaList.length === 0) { resolve([]); return; } - // 更新进度初始状态 - this.setData({ - submitProgress: 0, - }); - const uploadPromises = mediaList.map((item) => { - return new Promise((uploadResolve, uploadReject) => { - wx.uploadFile({ - url: `${config.url}/temp/file/upload`, + wx.showLoading({ title: "正在上传..", mask: true }); + + // 计算总大小 + const sizePromises = mediaList.map(item => { + return new Promise((sizeResolve, sizeReject) => { + wx.getFileSystemManager().getFileInfo({ filePath: item.path, - name: "file", - success: (resp) => { - const result = JSON.parse(resp.data); - if (result && result.code === 20000) { - completed++; - // 更新进度 - this.setData({ - submitProgress: (completed / total), - }); - uploadResolve(result.data[0].id); - } else { - uploadReject(new Error(`文件上传失败: ${result?.message || '未知错误'}`)); - } - }, - fail: (err) => uploadReject(new Error(`文件上传失败: ${err.errMsg}`)) + success: (res) => sizeResolve(res.size), + fail: (err) => sizeReject(err) }); }); }); - // 并行执行所有文件上传 - Promise.all(uploadPromises).then((tempFileIds) => { + Promise.all(sizePromises).then(fileSizes => { + const totalSize = fileSizes.reduce((acc, size) => acc + size, 0); + const uploadTasks: WechatMiniprogram.UploadTask[] = []; + let uploadedSize = 0; + let lastUploadedSize = 0; + this.setData({ - submitProgress: 1, + uploadTotal: IOSize.format(totalSize, 2, Unit.MB) + }); + // 计算上传速度 + const speedUpdateInterval = setInterval(() => { + const chunkSize = uploadedSize - lastUploadedSize; + this.setData({ + uploadSpeed: `${IOSize.format(chunkSize)} / s` + }); + lastUploadedSize = uploadedSize; + }, 1000); + // 上传文件 + const uploadPromises = mediaList.map(item => { + return new Promise((uploadResolve, uploadReject) => { + const task = wx.uploadFile({ + url: `${config.url}/temp/file/upload`, + filePath: item.path, + name: "file", + success: (resp) => { + const result = JSON.parse(resp.data); + if (result && result.code === 20000) { + uploadResolve(result.data[0].id); + } else { + uploadReject(new Error(`文件上传失败: ${result?.message || "未知错误"}`)); + } + }, + fail: (err) => uploadReject(new Error(`文件上传失败: ${err.errMsg}`)) + }); + + // 监听上传进度 + let prevProgress = 0; + task.onProgressUpdate((res) => { + const fileUploaded = (res.totalBytesExpectedToSend * res.progress) / 100; + const delta = fileUploaded - prevProgress; + uploadedSize += delta; + prevProgress = fileUploaded; + + // 更新进度条 + this.setData({ + uploaded: IOSize.formatWithoutUnit(uploadedSize, 2, Unit.MB), + uploadProgress: Math.round((uploadedSize / totalSize) * 10000) / 100 + }); + }); + uploadTasks.push(task); + }); + }); + + Promise.all(uploadPromises).then((tempFileIds) => { + // 清除定时器 + clearInterval(speedUpdateInterval); + uploadTasks.forEach(task => task.offProgressUpdate()); + this.setData({ + uploadProgress: 100, + uploadSpeed: "0 MB / s" + }); + resolve(tempFileIds); + }).catch((e: Error) => { + // 取消所有上传任务 + uploadTasks.forEach(task => task.abort()); + clearInterval(speedUpdateInterval); + reject(e); }); - resolve(tempFileIds); }).catch(reject); }); + // 并行执行获取 openId 和文件上传 Promise.all([getOpenId, uploadFiles]).then(([openId, tempFileIds]) => { + wx.showLoading({ title: "正在保存..", mask: true }); wx.request({ url: `${config.url}/journal/create`, method: "POST", @@ -300,22 +353,24 @@ Page({ createdAt: Date.parse(`${this.data.date} ${this.data.time}`), tempFileIds }, - success: async (resp: any) => { + success: async () => { Events.emit("JOURNAL_REFRESH"); wx.showToast({ title: "提交成功", icon: "success" }); this.setData({ idea: "", mediaList: [], - submitText: "提交", isSubmitting: false, + uploaded: "0", + uploadTotal: "0 MB", + uploadProgress: 0 }); await Toolkit.sleep(1000); wx.switchTab({ - url: "/pages/main/journal/index", - }) + url: "/pages/main/journal/index" + }); }, fail: handleFail }); }).catch(handleFail); } -}); \ No newline at end of file +}); diff --git a/miniprogram/pages/main/journal-creater/index.wxml b/miniprogram/pages/main/journal-creater/index.wxml index 42ec86f..e3f3f98 100644 --- a/miniprogram/pages/main/journal-creater/index.wxml +++ b/miniprogram/pages/main/journal-creater/index.wxml @@ -87,13 +87,17 @@ - + + + + {{uploaded}} / {{uploadTotal}} + {{uploadSpeed}} + + {{submitText}} + >提交 \ No newline at end of file diff --git a/miniprogram/pages/main/journal-editor/index.less b/miniprogram/pages/main/journal-editor/index.less index ef85cad..54c3e97 100644 --- a/miniprogram/pages/main/journal-editor/index.less +++ b/miniprogram/pages/main/journal-editor/index.less @@ -119,9 +119,20 @@ } } - .progress { + .uploading { width: 100%; margin-top: 1rem; + + .progress { + margin-bottom: 8rpx; + } + + .text { + color: var(--theme-text-secondary); + display: flex; + font-size: .8rem; + justify-content: space-between; + } } .ctrl { diff --git a/miniprogram/pages/main/journal-editor/index.ts b/miniprogram/pages/main/journal-editor/index.ts index cddd80d..d3ee4bc 100644 --- a/miniprogram/pages/main/journal-editor/index.ts +++ b/miniprogram/pages/main/journal-editor/index.ts @@ -6,6 +6,7 @@ import config from "../../../config/index"; import { Location, MediaItem, MediaItemType, WechatMediaItem } from "../../../types/UI"; import { Journal, JournalType } from "../../../types/Journal"; import { MediaAttachExt, MediaAttachType } from "../../../types/Attachment"; +import IOSize, { Unit } from "../../../utils/IOSize"; interface JournalEditorData { id?: number; @@ -18,9 +19,11 @@ interface JournalEditorData { location?: Location; isAuthLocation: boolean; isLoading: boolean; - saveText: string; isSaving: boolean; - saveProgress: number; + uploaded: string; + uploadTotal: string; + uploadSpeed: string; + uploadProgress: number; mediaItemTypeEnum: any; deleteDialogVisible: boolean; deleteConfirmText: string; @@ -36,10 +39,12 @@ Page({ mediaList: [], newMediaList: [], location: undefined, - saveText: "保存", isSaving: false, - saveProgress: 0, isLoading: true, + uploaded: "0", + uploadTotal: "0 MB", + uploadSpeed: "0 MB / s", + uploadProgress: 0, mediaItemTypeEnum: { ...MediaItemType }, @@ -300,63 +305,111 @@ Page({ save() { const handleFail = () => { wx.showToast({ title: "保存失败", icon: "error" }); + wx.hideLoading(); this.setData({ - saveText: "保存", isSaving: false }); }; - this.setData({ - saveText: "正在保存..", isSaving: true }); // 收集保留的附件 ID(缩略图 ID) const attachmentIds = this.data.mediaList.map(item => item.attachmentId); + // 上传新媒体文件 const uploadFiles = new Promise((resolve, reject) => { - const total = this.data.newMediaList.length; - let completed = 0; - if (total === 0) { + if (this.data.newMediaList.length === 0) { resolve([]); return; } - this.setData({ - saveProgress: 0, - }); - // 上传临时文件 - const uploadPromises = this.data.newMediaList.map((item) => { - return new Promise((uploadResolve, uploadReject) => { - wx.uploadFile({ - url: `${config.url}/temp/file/upload`, + + wx.showLoading({ title: "正在上传..", mask: true }); + + // 计算总大小 + const sizePromises = this.data.newMediaList.map(item => { + return new Promise((sizeResolve, sizeReject) => { + wx.getFileSystemManager().getFileInfo({ filePath: item.path, - name: "file", - success: (resp) => { - const result = JSON.parse(resp.data); - if (result && result.code === 20000) { - completed++; - // 更新进度 - this.setData({ - saveProgress: (completed / total), - }); - uploadResolve(result.data[0].id); - } else { - uploadReject(new Error(`文件上传失败: ${result?.message || '未知错误'}`)); - } - }, - fail: (err) => uploadReject(new Error(`文件上传失败: ${err.errMsg}`)) + success: (res) => sizeResolve(res.size), + fail: (err) => sizeReject(err) }); }); }); - // 并行执行所有文件上传 - Promise.all(uploadPromises).then((tempFileIds) => { + + Promise.all(sizePromises).then(fileSizes => { + const totalSize = fileSizes.reduce((acc, size) => acc + size, 0); + const uploadTasks: WechatMiniprogram.UploadTask[] = []; + let uploadedSize = 0; + let lastUploadedSize = 0; + this.setData({ - saveProgress: 1, + uploadTotal: IOSize.format(totalSize, 2, Unit.MB) + }); + + // 计算上传速度 + const speedUpdateInterval = setInterval(() => { + const chunkSize = uploadedSize - lastUploadedSize; + this.setData({ + uploadSpeed: `${IOSize.format(chunkSize)} / s` + }); + lastUploadedSize = uploadedSize; + }, 1000); + + // 上传文件 + const uploadPromises = this.data.newMediaList.map(item => { + return new Promise((uploadResolve, uploadReject) => { + const task = wx.uploadFile({ + url: `${config.url}/temp/file/upload`, + filePath: item.path, + name: "file", + success: (resp) => { + const result = JSON.parse(resp.data); + if (result && result.code === 20000) { + uploadResolve(result.data[0].id); + } else { + uploadReject(new Error(`文件上传失败: ${result?.message || "未知错误"}`)); + } + }, + fail: (err) => uploadReject(new Error(`文件上传失败: ${err.errMsg}`)) + }); + + // 监听上传进度 + let prevProgress = 0; + task.onProgressUpdate((res) => { + const fileUploaded = (res.totalBytesExpectedToSend * res.progress) / 100; + const delta = fileUploaded - prevProgress; + uploadedSize += delta; + prevProgress = fileUploaded; + + // 更新进度条 + this.setData({ + uploaded: IOSize.formatWithoutUnit(uploadedSize, 2, Unit.MB), + uploadProgress: Math.round((uploadedSize / totalSize) * 10000) / 100 + }); + }); + uploadTasks.push(task); + }); + }); + Promise.all(uploadPromises).then((tempFileIds) => { + // 清除定时器 + clearInterval(speedUpdateInterval); + uploadTasks.forEach(task => task.offProgressUpdate()); + this.setData({ + uploadProgress: 100, + uploadSpeed: "0 MB / s" + }); + resolve(tempFileIds); + }).catch((e: Error) => { + // 取消所有上传任务 + uploadTasks.forEach(task => task.abort()); + clearInterval(speedUpdateInterval); + reject(e); }); - resolve(tempFileIds); }).catch(reject); }); // 提交保存 uploadFiles.then((tempFileIds) => { + wx.showLoading({ title: "正在保存..", mask: true }); wx.request({ url: `${config.url}/journal/update`, method: "POST", @@ -382,8 +435,10 @@ Page({ Events.emit("JOURNAL_LIST_REFRESH"); wx.showToast({ title: "保存成功", icon: "success" }); this.setData({ - saveText: "保存", isSaving: false, + uploaded: "0", + uploadTotal: "0 MB", + uploadProgress: 0 }); await Toolkit.sleep(1000); wx.navigateBack(); diff --git a/miniprogram/pages/main/journal-editor/index.wxml b/miniprogram/pages/main/journal-editor/index.wxml index f08b21c..9486504 100644 --- a/miniprogram/pages/main/journal-editor/index.wxml +++ b/miniprogram/pages/main/journal-editor/index.wxml @@ -131,13 +131,17 @@ - + + + + {{uploaded}} / {{uploadTotal}} + {{uploadSpeed}} + + 删除记录 {{saveText}} + >保存