From d9d2ab05185a5a34f517f9ccf989d04f8c5f22ca Mon Sep 17 00:00:00 2001 From: liuBingWei <3134058912@qq.com> Date: Sun, 31 Aug 2025 15:28:16 +0800 Subject: [PATCH 1/2] =?UTF-8?q?feat(pages):=20=E6=B7=BB=E5=8A=A0=E5=88=86?= =?UTF-8?q?=E7=89=87=E4=B8=8A=E4=BC=A0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 pages.json 中新增 upload/index 页面 - 在 template.config.js 中添加分片上传的配置项 --- src/api/system/chunkUpload/index.js | 89 ++++++ .../geek-confirm-dialog.vue | 123 ++++++++ .../geek-uploadbox/geek-uploadbox.vue | 271 ++++++++++++++++ src/pages.json | 3 + src/pages/template.config.js | 8 +- src/pages_geek/pages/upload/index.vue | 155 ++++++++++ src/utils/ChunkUploaderApp.js | 288 ++++++++++++++++++ src/utils/ChunkUploaderWx.js | 202 ++++++++++++ src/utils/fileOper.js | 278 +++++++++++++++++ 9 files changed, 1416 insertions(+), 1 deletion(-) create mode 100644 src/api/system/chunkUpload/index.js create mode 100644 src/components/geek-xd/components/geek-confirm-dialog/geek-confirm-dialog.vue create mode 100644 src/components/geek-xd/components/geek-uploadbox/geek-uploadbox.vue create mode 100644 src/pages_geek/pages/upload/index.vue create mode 100644 src/utils/ChunkUploaderApp.js create mode 100644 src/utils/ChunkUploaderWx.js create mode 100644 src/utils/fileOper.js diff --git a/src/api/system/chunkUpload/index.js b/src/api/system/chunkUpload/index.js new file mode 100644 index 0000000..a61257f --- /dev/null +++ b/src/api/system/chunkUpload/index.js @@ -0,0 +1,89 @@ +import request from '@/utils/request' +import config from "@/config"; +import { getToken } from "@/utils/auth"; + + + + + + +/**初始化上传 */ +export function initChunkUpload(fileName, fileSize) { + return request({ + url: '/file/initUpload', + method: 'post', + params: { + fileName, + fileSize + } + }) +} + + +/**上传分片视频 */ +export function uploadChunk(uploadId, filePath, chunkIndex, formattedPath) { + return new Promise((resolve, reject) => { + uni.uploadFile({ + url: `${config.baseUrl}/file/uploadChunk`, + filePath: formattedPath, + name: "chunk", + timeout: 60000, // 增加超时时间到60秒 + header: { + Authorization: `Bearer ${getToken()}`, + }, + formData: { + uploadId: uploadId, + filePath: filePath, + chunkIndex: chunkIndex, + }, + success: (res) => { + try { + const resultData = JSON.parse(res.data); + resolve(resultData); + } catch (error) { + console.error("解析上传结果失败:", error); + reject(error); + } + }, + fail: (err) => { + console.error(`分片${chunkIndex}上传请求失败:`, err); + reject(err); + }, + }); + }); +} + + +/**完成分片上传 */ +export function completeChunkUpload(uploadId, filePath, fileSize, fileName, partETags) { + return request({ + url: '/file/completeUpload', + method: 'post', + params: { + uploadId, + filePath, + fileSize, + fileName, + }, + data: partETags + }) +} + + + + + + + + + + + + + + + + + + + diff --git a/src/components/geek-xd/components/geek-confirm-dialog/geek-confirm-dialog.vue b/src/components/geek-xd/components/geek-confirm-dialog/geek-confirm-dialog.vue new file mode 100644 index 0000000..aafb105 --- /dev/null +++ b/src/components/geek-xd/components/geek-confirm-dialog/geek-confirm-dialog.vue @@ -0,0 +1,123 @@ + + + + + \ No newline at end of file diff --git a/src/components/geek-xd/components/geek-uploadbox/geek-uploadbox.vue b/src/components/geek-xd/components/geek-uploadbox/geek-uploadbox.vue new file mode 100644 index 0000000..2cebba7 --- /dev/null +++ b/src/components/geek-xd/components/geek-uploadbox/geek-uploadbox.vue @@ -0,0 +1,271 @@ + + + + + \ No newline at end of file diff --git a/src/pages.json b/src/pages.json index 0e977d5..8248469 100644 --- a/src/pages.json +++ b/src/pages.json @@ -236,6 +236,9 @@ }, { "path": "code/index" + }, + { + "path": "upload/index" } ] } diff --git a/src/pages/template.config.js b/src/pages/template.config.js index 1e606a4..2e582d6 100644 --- a/src/pages/template.config.js +++ b/src/pages/template.config.js @@ -14,7 +14,13 @@ export default [ icon: 'wxCenter', title: '二维码', title_en: 'index', - } + }, + { + path: '/pages_geek/pages/upload/index', + icon: 'wxCenter', + title: '分片上传', + title_en: 'index', + }, ] }, { diff --git a/src/pages_geek/pages/upload/index.vue b/src/pages_geek/pages/upload/index.vue new file mode 100644 index 0000000..9180a8d --- /dev/null +++ b/src/pages_geek/pages/upload/index.vue @@ -0,0 +1,155 @@ + + + + + diff --git a/src/utils/ChunkUploaderApp.js b/src/utils/ChunkUploaderApp.js new file mode 100644 index 0000000..5f18afb --- /dev/null +++ b/src/utils/ChunkUploaderApp.js @@ -0,0 +1,288 @@ +import modal from '@/plugins/modal' +import { + deleteLocalFile, + copyFileToSandbox, + readAppFileChunk, + getFileName, + deleteTempFile, + createAndWriteTempFile +} from "@/utils/fileOper" +import { initChunkUpload, uploadChunk, completeChunkUpload } from '@/api/system/chunkUpload' + +/** + * APP端分片上传工具类 + */ +class AppChunkUploader { + constructor(options = {}) { + this.config = { + chunkSize: 15 * 1024 * 1024, // 默认分片大小15MB + concurrentLimit: 2, // 并发上传的分片数量 + ...options + } + } + + /** + * 获取切片end位置 + * @param {number} start - 开始位置 + * @param {number} chunkSize - 分片大小 + * @param {number} fileSize - 文件总大小 + * @param {number} index - 分片索引 + * @param {number} totalChunks - 总分片数 + * @returns {number} end位置 + */ + getSliceEnd(start, chunkSize, fileSize, index, totalChunks) { + return index < totalChunks - 1 ? start + chunkSize - 1 : fileSize + } + + + + /** + * APP端分片上传单个分片 + * @param {string} uploadId - 上传ID + * @param {string} filePath - 文件路径 + * @param {number} chunkIndex - 分片索引 + * @param {ArrayBuffer} chunk - 分片数据 + * @returns {Promise} 上传结果 + */ + async uploadAppChunk(uploadId, filePath, chunkIndex, chunk) { + try { + const response = await this.startUploadAppChunk(uploadId, filePath, chunkIndex, chunk) + return response + } catch (error) { + throw error + } + } + + /** + * 执行APP端分片上传 + * @param {string} uploadId - 上传ID + * @param {string} filePath - 文件路径 + * @param {number} chunkIndex - 分片索引 + * @param {ArrayBuffer} chunk - 分片数据 + * @returns {Promise} 上传结果 + */ + startUploadAppChunk(uploadId, filePath, chunkIndex, chunk) { + return new Promise(async (resolve, reject) => { + try { + // 1. 准备临时文件信息 + const tempFileName = `temp_chunk/chunk_${uploadId}_${chunkIndex}.bin` + const tempDirPath = plus.io.PRIVATE_DOC + + // 2. 创建并写入临时文件 + const tempFilePath = await createAndWriteTempFile( + tempDirPath, + tempFileName, + chunk + ) + + //设置文件的全路径 + let formattedPath = tempFilePath + if (tempFilePath && !tempFilePath.startsWith("file://")) { + formattedPath = `file://${tempFilePath}` + } + + // 3. 上传文件 + const result = await uploadChunk(uploadId, filePath, chunkIndex, formattedPath) + + // 4. 删除临时文件 + await deleteTempFile(tempDirPath, tempFileName) + + resolve(result) + } catch (error) { + reject(error) + } + }) + } + + /** + * 并发上传分片 + * @param {Array} tasks - 分片任务数组 + * @param {number} batchSize - 批次大小 + * @param {string} uploadId - 上传ID + * @param {string} filePath - 文件路径 + * @param {string} localFilePath - 本地文件路径 + * @param {Array} partETags - 分片ETag数组 + * @param {Object} progressInfo - 进度信息对象 + * @returns {Promise} 上传结果数组 + */ + async uploadChunksInBatches(tasks, batchSize, uploadId, filePath, localFilePath, partETags, progressInfo) { + const results = [] + const { chunkCount } = progressInfo + + for (let i = 0; i < tasks.length; i += batchSize) { + const batch = tasks.slice(i, i + batchSize) + + try { + const batchResults = await Promise.all( + batch.map((task) => this.uploadChunkConcurrently(task, uploadId, filePath, localFilePath, partETags, progressInfo)) + ) + results.push(...batchResults) + } catch (error) { + // 如果批次中有任何分片失败,立即停止上传 + throw error + } + } + return results + } + + /** + * 并发上传单个分片 + * @param {Object} chunkTask - 分片任务 + * @param {string} uploadId - 上传ID + * @param {string} filePath - 文件路径 + * @param {string} localFilePath - 本地文件路径 + * @param {Array} partETags - 分片ETag数组 + * @param {Object} progressInfo - 进度信息对象 + * @returns {Promise} 上传结果 + */ + async uploadChunkConcurrently(chunkTask, uploadId, filePath, localFilePath, partETags, progressInfo) { + const { index, start, end } = chunkTask + const { chunkCount } = progressInfo + + const chunk = await readAppFileChunk(localFilePath, start, end - start) + + const response = await this.uploadAppChunk(uploadId, filePath, index, chunk) + + if (response.data && response.data.etag) { + partETags[index] = { + partNumber: index + 1, + ETag: response.data.etag, + } + } + + progressInfo.completedChunks++ + const percent = Math.floor((progressInfo.completedChunks / chunkCount) * 100) + const displayPercent = Math.floor(percent / 10) * 10 // 每10%更新一次 + + if (displayPercent !== progressInfo.uploadProgress || progressInfo.completedChunks === chunkCount) { + modal.closeLoading() + modal.loading(`上传中 ${percent}% (请勿离开此页面)`) + progressInfo.uploadProgress = displayPercent + } + + return response + } + + /** + * 主要的分片上传方法 + * @param {Object} options - 上传选项 + * @param {Object} options.file - 文件对象(包含path和size属性) + * @param {string} options.filePath - 文件路径(如果提供file,此参数可选) + * @param {string} options.fileName - 文件名称(可选,会自动从路径提取) + * @param {number} options.fileSize - 文件大小(如果提供file,此参数可选) + * @param {Function} options.onProgress - 进度回调函数(可选) + * @param {Function} options.onSuccess - 成功回调函数(可选) + * @param {Function} options.onError - 错误回调函数(可选) + * @returns {Promise} 上传结果 + */ + async upload(options) { + const { + file, + onProgress, + onSuccess, + onError + } = options + + // 优先使用file对象,否则使用单独传入的参数 + const actualFilePath = file.path + const actualFileSize = file.size + + if (!actualFilePath) { + throw new Error('必须提供 filePath 或包含 path 属性的 file 对象') + } + + if (!actualFileSize) { + throw new Error('必须提供 fileSize 或包含 size 属性的 file 对象') + } + + try { + //初始化文件状态 + let localFilePath = actualFilePath + const actualFileName = getFileName(localFilePath) + + modal.loading("准备上传...") + + // 1.计算分片数量 + const chunkSize = this.config.chunkSize + const chunkCount = Math.ceil(actualFileSize / chunkSize) + + //2.初始化分片上传 + const initResult = await initChunkUpload(actualFileName, actualFileSize) + if (initResult.code !== 200) throw new Error("初始化上传失败") + + const { uploadId, filePath: serverFilePath } = initResult.data + const partETags = [] + + //3.将文件移动到应用 沙盒 目录 + localFilePath = await copyFileToSandbox(localFilePath) + + //4.上传所有分片 + modal.closeLoading() + modal.loading("上传中...") + + //5.进度信息对象 + const progressInfo = { + completedChunks: 0, + uploadProgress: 0, + chunkCount + } + + // 创建分片任务队列 + const chunkTasks = [] + for (let i = 0; i < chunkCount; i++) { + chunkTasks.push({ + index: i, + start: i * chunkSize, + end: this.getSliceEnd(i * chunkSize, chunkSize, actualFileSize, i, chunkCount), + }) + } + + //并发上传数据 + await this.uploadChunksInBatches( + chunkTasks, + this.config.concurrentLimit, + uploadId, + serverFilePath, + localFilePath, + partETags, + progressInfo + ) + + //合并分片 + modal.msg("正在合并分片...") + + const result = await completeChunkUpload( + uploadId, serverFilePath, actualFileSize, actualFileName, partETags + ) + + await deleteLocalFile(localFilePath) //将临时文件删除,防止占用空间 + + modal.msgSuccess("上传成功") + + // 执行成功回调 + if (onSuccess) { + onSuccess(result) + } + + return true + + } catch (error) { + modal.closeLoading() + const errorMessage = `上传失败: ${error.message || error}` + modal.msg(errorMessage) + + // 执行错误回调 + if (onError) { + onError(error) + } + + throw error + } + } +} + +// 创建默认实例 +const appChunkUploader = new AppChunkUploader() + +export default appChunkUploader +export { AppChunkUploader } diff --git a/src/utils/ChunkUploaderWx.js b/src/utils/ChunkUploaderWx.js new file mode 100644 index 0000000..35fe233 --- /dev/null +++ b/src/utils/ChunkUploaderWx.js @@ -0,0 +1,202 @@ +import { initChunkUpload, uploadChunk, completeChunkUpload } from '@/api/system/chunkUpload' +import modal from "@/plugins/modal"; +import { getFileExtension } from "@/utils/fileOper"; + + +/** + * 微信小程序分片上传工具类 + */ +export class WxChunkUploader { + constructor(config = {}) { + this.chunkSize = config.chunkSize || 15 * 1024 * 1024; //默认分片大小,为 15MB + this.lastDisplayPercent = 0; //初始化上次显示的上传进度百分比为0 + } + + /** + * 执行分片上传 + * @param {Object} options - 上传选项 + * @param {Function} options.onSuccess - 成功回调 + * @param {Function} options.onError - 错误回调 + */ + async upload(options) { + const { file, onSuccess, onError } = options; + + try { + // 1. 校验数据 + this._validateParams(file); + + // 2. 准备上传数据 + modal.loading("准备上传..."); + const uploadData = await this._prepareUploadData(file); + + // 3. 执行分片上传 + modal.closeLoading(); + modal.loading("上传中..."); + const partETags = await this._uploadChunks(uploadData); + + // 4. 合并文件 + modal.closeLoading(); + modal.loading("合并文件中..."); + + //模仿上传的时间,可删除 + await new Promise(resolve => setTimeout(resolve, 5000)); + + await this._completeUpload(uploadData, partETags); + + setTimeout(() => { + onSuccess?.({ success: true }); + }, 1000); + + return true; + } catch (error) { + console.error("分片上传失败:", error); + modal.closeLoading(); + modal.msgError("上传失败"); + onError?.(error); + return false; + } + } + + + + /** + * 校验参数 + */ + _validateParams(file) { + if (!file.path) throw new Error("文件路径不存在"); + if (!file.size) throw new Error("文件大小不存在"); + } + + /** + * 准备上传数据 + */ + async _prepareUploadData(file) { + const fileSize = file.size; + const tempFilePath = file.path; + const uploadFileName = `weixin_${Date.now()}.${getFileExtension(tempFilePath)}`; + const chunkCount = Math.ceil(fileSize / this.chunkSize); + + console.log("分片数量:", chunkCount); + + // 初始化分片上传 + const initResult = await initChunkUpload(uploadFileName, fileSize); + if (initResult.code !== 200) throw new Error("初始化上传失败"); + return { + uploadId: initResult.data.uploadId, + filePath: initResult.data.filePath, + uploadFileName: uploadFileName, + fileSize: fileSize, + chunkCount: chunkCount, + tempFilePath: tempFilePath, + }; + } + + + /** + * 上传所有分片 + */ + // return { + // uploadId: initResult.data.uploadId, + // filePath: initResult.data.filePath, + // fileName:initResult.data.fileName, + // fileSize:fileSize, + // chunkCount: chunkCount, + // }; + + async _uploadChunks(uploadData) { + const { uploadId, filePath, fileSize, chunkCount, tempFilePath } = uploadData; + const fileManager = uni.getFileSystemManager(); + const partETags = []; + + for (let i = 0; i < chunkCount; i++) { + const start = i * this.chunkSize; + const end = Math.min(start + this.chunkSize, fileSize); + const tempChunkPath = `${wx.env.USER_DATA_PATH}/chunk_${i}.tmp`; + + // 读取并写入分片 + await this._processChunk(fileManager, tempFilePath, tempChunkPath, start, end - start); + + // 上传分片 + const response = await uploadChunk(uploadId, filePath, i, tempChunkPath); + + if (response.data?.etag) { + partETags.push({ + partNumber: i + 1, + ETag: response.data.etag, + }); + } + // 清理临时文件 + this._cleanupTempFile(fileManager, tempChunkPath); + + // 更新进度 - 确保完全执行完毕 + this._updateProgress(i, chunkCount); + + } + + return partETags; + } + + /** + * 处理单个分片 + */ + async _processChunk(fileManager, tempFilePath, tempChunkPath, start, length) { + // 读取分片数据 + const readRes = await new Promise((resolve, reject) => { + fileManager.readFile({ + filePath: tempFilePath, + position: start, + length: length, + success: (res) => resolve(res.data), + fail: reject, + }); + }); + + // 写入临时文件 + await new Promise((resolve, reject) => { + fileManager.writeFile({ + filePath: tempChunkPath, + data: readRes, + success: resolve, + fail: reject, + }); + }); + } + + + /** + * 清理临时文件 + */ + _cleanupTempFile(fileManager, tempChunkPath) { + try { + fileManager.unlinkSync(tempChunkPath); + console.log("删除临时文件成功:", tempChunkPath); + } catch (e) { + console.error("删除临时文件错误:", e); + } + } + + + /** + * 更新上传进度 + */ + _updateProgress(currentIndex, totalCount) { + const percent = Math.floor(((currentIndex + 1) / totalCount) * 100); + const displayPercent = Math.floor(percent / 20) * 20; + if (displayPercent !== this.lastDisplayPercent || currentIndex === totalCount - 1) { + modal.closeLoading(); + modal.loading(`上传中${displayPercent}%`); + this.lastDisplayPercent = displayPercent; + } + } + + /** + * 完成上传 + */ + async _completeUpload(uploadData, partETags) { + const { uploadId, filePath, fileSize, uploadFileName } = uploadData; + await completeChunkUpload(uploadId, filePath, fileSize, uploadFileName, partETags); + + } + +} +export const wxChunkUploader = new WxChunkUploader(); \ No newline at end of file diff --git a/src/utils/fileOper.js b/src/utils/fileOper.js new file mode 100644 index 0000000..f68c6b5 --- /dev/null +++ b/src/utils/fileOper.js @@ -0,0 +1,278 @@ + +/** + * 将文件复制到应用沙盒目录 + * @param {*} srcUrl + * @returns + */ +export const copyFileToSandbox = (srcUrl) => { + return new Promise((resolve, reject) => { + const newName = `file_${Date.now()}.${getFileExtension(srcUrl)}`; + console.log("文件名称是什么>>>", newName); + plus.io.requestFileSystem( + plus.io.PRIVATE_DOC, + function (dstEntry) { + plus.io.resolveLocalFileSystemURL( + srcUrl, + function (srcEntry) { + srcEntry.copyTo( + dstEntry.root, + newName, + function (entry) { + console.log("文件复制成功:", entry.fullPath); + resolve(entry.fullPath); + }, + function (e) { + console.error("复制文件失败:", JSON.stringify(e)); + reject(e); + } + ); + }, + function (e) { + console.error("获取目标目录失败:", JSON.stringify(e)); + reject(e); + } + ); + }, + function (e) { + console.error("获取源文件失败:", JSON.stringify(e)); + reject(e); + } + ); + }); +} + +/** + * 删除临时文件 + * @param {string} dirPath - 目录路径 + * @param {string} fileName - 文件名 + * @returns {Promise} + */ +export function deleteTempFile(dirPath, fileName) { + return new Promise((resolve) => { + plus.io.requestFileSystem( + dirPath, + (dirEntry) => { + console.log("文件目录:", dirPath); + console.log("目录存在:", dirEntry); + dirEntry.root.getFile( + fileName, + { create: false }, + (fileEntry) => { + console.log("临时文件存在:", fileEntry); + fileEntry.remove( + () => { + console.log("删除成功XXXXX"); + resolve(); + }, + (err) => { + console.error("删除失败XXXXX:", err); + resolve(); + } + ); + }, + () => resolve() + ); + }, + () => resolve() + ); + }); +} + + + +/** + * 删除本地临时文件(临时文件是分片生成的) + * @param {*} filePath + * @returns + */ +export const deleteLocalFile = (filePath) => { + return new Promise((resolve, reject) => { + if (!filePath) { + resolve(); + return; + } + console.log("准备删除文件:", filePath); + plus.io.resolveLocalFileSystemURL( + filePath, + (entry) => { + entry.remove( + () => { + console.log("文件删除成功:", filePath); + resolve(true); + }, + (error) => { + console.error("删除文件失败:", JSON.stringify(error)); + // 失败也视为完成,不中断流程 + resolve(false); + } + ); + }, + (error) => { + console.error("获取文件引用失败:", JSON.stringify(error)); + // 失败也视为完成,不中断流程 + resolve(false); + } + ); + }); +}; + +/** + * 根据文件路径获取APP文件信息 + */ +export const getAppFileInfo = (filePath) => { + return new Promise((resolve, reject) => { + plus.io.resolveLocalFileSystemURL( + filePath, + (entry) => { + entry.file( + (file) => { + resolve({ + size: file.size, + name: file.name, + type: file.type, + }); + }, + (error) => { + reject(error); + } + ); + }, + (error) => { + reject(error); + } + ); + }); +}; + + + +/*读取分片的数据 */ +export const readAppFileChunk = (filePath, start, length) => { + console.log("读取分片的路径是什么>>>", filePath); + return new Promise((resolve, reject) => { + plus.io.resolveLocalFileSystemURL( + filePath, + (entry) => { + entry.file( + (file) => { + const reader = new plus.io.FileReader(); + try { + const slice = file.slice(start, start + length); + reader.readAsDataURL(slice); + } catch (sliceError) { + reject(sliceError); + } + reader.onloadend = (e) => { + if (e.target.readyState == 2) { + try { + const base64 = e.target.result.split(",")[1]; + resolve(base64); + } catch (err) { + reject(err); + } + } + }; + + reader.onerror = (err) => { + reject(err); + }; + }, + (error) => { + reject(error); + } + ); + }, + reject + ); + }); +}; + + +/** + * 获取文章的扩展名称 + * @param {*} filePath + * @returns + */ +export const getFileExtension = (filePath) => { + if (!filePath) { + return ""; + } + // 查找最后一个点号位置 + const dotIndex = filePath.lastIndexOf("."); + if (dotIndex === -1) { + return ""; // 没有找到扩展名 + } + // 从点号后面提取扩展名 + return filePath.substring(dotIndex + 1).toLowerCase(); +}; + + +/** + * 获取文件名称 + * @param {*} filePath + * @returns + */ + +export const getFileName = (filePath) => { + if (!filePath) { + return ""; + } + // 查找最后一个斜杠位置 + const slashIndex = filePath.lastIndexOf("/"); + if (slashIndex === -1) { + return filePath; // 没有斜杠,整个字符串可能就是文件名 + } + // 从最后一个斜杠后面提取文件名 + return filePath.substring(slashIndex + 1); +}; + + + +/** + * 创建临时文件并写入数据 + * @param {string} dirPath - 目录路径 + * @param {string} fileName - 文件名 + * @param {ArrayBuffer} data - 要写入的数据 + * @returns {Promise} 临时文件的完整路径 + */ +export const createAndWriteTempFile = (dirPath, fileName, data) => { + return new Promise((resolve, reject) => { + plus.io.requestFileSystem( + dirPath, + (dirEntry) => { + dirEntry.root.getFile( + fileName, + { create: true, exclusive: false }, + (fileEntry) => { + fileEntry.createWriter( + (writer) => { + const filePath = fileEntry.fullPath + // 设置写入成功回调 + writer.onwrite = function () { + resolve(filePath) + } + // 设置写入失败回调 + writer.onerror = function (e) { + reject(e) + } + // 写入数据 + try { + if (data) { + writer.writeAsBinary(data) + } + } catch (e) { + reject(e) + } + }, + (err) => reject(err) + ) + }, + (err) => reject(err) + ) + }, + (err) => { + reject(err) + } + ) + }) +} \ No newline at end of file -- Gitee From adf17d57fcfb25ee38b5c58b4485161bc59196d2 Mon Sep 17 00:00:00 2001 From: liuBingWei <3134058912@qq.com> Date: Tue, 2 Sep 2025 20:02:52 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0ts=E7=B1=BB=E5=9E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 + .../geek-uploadbox/geek-uploadbox.vue | 3 +- src/pages_geek/pages/upload/index.vue | 29 +- src/types/upload.ts | 47 ++ src/utils/ChunkUploaderApp.js | 288 ----------- src/utils/ChunkUploaderApp.ts | 479 ++++++++++++++++++ src/utils/ChunkUploaderWx.js | 202 -------- src/utils/ChunkUploaderWx.ts | 282 +++++++++++ src/utils/fileOper.js | 278 ---------- 9 files changed, 822 insertions(+), 788 deletions(-) create mode 100644 src/types/upload.ts delete mode 100644 src/utils/ChunkUploaderApp.js create mode 100644 src/utils/ChunkUploaderApp.ts delete mode 100644 src/utils/ChunkUploaderWx.js create mode 100644 src/utils/ChunkUploaderWx.ts delete mode 100644 src/utils/fileOper.js diff --git a/package.json b/package.json index 17f4887..b9059f9 100644 --- a/package.json +++ b/package.json @@ -87,9 +87,11 @@ "@dcloudio/uni-cli-shared": "3.0.0-4060420250429001", "@dcloudio/uni-stacktracey": "3.0.0-4060420250429001", "@dcloudio/vite-plugin-uni": "3.0.0-4060420250429001", + "@types/html5plus": "^1.0.5", "@vue/runtime-core": "^3.5.12", "@vue/tsconfig": "^0.5.1", "less": "^4.2.0", + "miniprogram-api-typings": "^4.1.0", "sass": "1.78.0", "sass-loader": "^16.0.1", "typescript": "^5.6.2", diff --git a/src/components/geek-xd/components/geek-uploadbox/geek-uploadbox.vue b/src/components/geek-xd/components/geek-uploadbox/geek-uploadbox.vue index 2cebba7..6d4a58b 100644 --- a/src/components/geek-xd/components/geek-uploadbox/geek-uploadbox.vue +++ b/src/components/geek-xd/components/geek-uploadbox/geek-uploadbox.vue @@ -151,8 +151,7 @@ const buildVideoData = (res) => { // #ifdef MP-WEIXIN videoData = { path: res.tempFilePath, - value: res.tempFilePath, - ...res, + size:res.size } // #endif diff --git a/src/pages_geek/pages/upload/index.vue b/src/pages_geek/pages/upload/index.vue index 9180a8d..cc46881 100644 --- a/src/pages_geek/pages/upload/index.vue +++ b/src/pages_geek/pages/upload/index.vue @@ -14,7 +14,7 @@