diff --git a/.env b/.env new file mode 100644 index 0000000..f9faf53 --- /dev/null +++ b/.env @@ -0,0 +1,2 @@ +# API +VITE_SYSTEM_URL = "http://ge465bd9.natappfree.cc" \ No newline at end of file diff --git a/components/cb-file-picker/cb-file-picker.vue b/components/cb-file-picker/cb-file-picker.vue new file mode 100644 index 0000000..a052557 --- /dev/null +++ b/components/cb-file-picker/cb-file-picker.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/pages.json b/pages.json index 0a82779..f0cfc60 100644 --- a/pages.json +++ b/pages.json @@ -87,6 +87,20 @@ "navigationBarBackgroundColor": "#ffffff" } }, + { + "path": "pages/my-index/wallet/real-id", + "style": { + "navigationBarTitleText": "实名认证", + "navigationBarBackgroundColor": "#ffffff" + } + }, + { + "path": "pages/my-index/my-team", + "style": { + "navigationBarTitleText": "我的团队", + "navigationBarBackgroundColor": "#ffffff" + } + }, { "path": "pages/my-index/wallet/bank-card/card-details", "style": { diff --git a/pages/my-index/components/card-input.vue b/pages/my-index/components/card-input.vue index 1e5c8ff..c58d350 100644 --- a/pages/my-index/components/card-input.vue +++ b/pages/my-index/components/card-input.vue @@ -1,4 +1,11 @@ + + + + diff --git a/pages/my-index/wallet/bank-card/card-details.vue b/pages/my-index/wallet/bank-card/card-details.vue index 3e9cff5..341a90a 100644 --- a/pages/my-index/wallet/bank-card/card-details.vue +++ b/pages/my-index/wallet/bank-card/card-details.vue @@ -51,6 +51,9 @@ stateData.state === '101' ? '支付宝账号' : '微信账号' }`" > + + + diff --git a/pages/my-index/wallet/index.vue b/pages/my-index/wallet/index.vue index 6b241c0..2926ccf 100644 --- a/pages/my-index/wallet/index.vue +++ b/pages/my-index/wallet/index.vue @@ -13,7 +13,7 @@ key: '3', url: '/pages/my-index/wallet/edit-password' }, - { title: '实名认证', key: '4', url: '' } + { title: '实名认证', key: '4', url: '/pages/my-index/wallet/real-id' } ] @@ -23,7 +23,7 @@ 我的资产 - 2222 + 1222 diff --git a/pages/my-index/wallet/real-id.vue b/pages/my-index/wallet/real-id.vue new file mode 100644 index 0000000..2fab6d3 --- /dev/null +++ b/pages/my-index/wallet/real-id.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/static/images/my-index/id-front.png b/static/images/my-index/id-front.png new file mode 100644 index 0000000..6c2c3ac Binary files /dev/null and b/static/images/my-index/id-front.png differ diff --git a/static/images/my-index/id-opposite.png b/static/images/my-index/id-opposite.png new file mode 100644 index 0000000..5d68e90 Binary files /dev/null and b/static/images/my-index/id-opposite.png differ diff --git a/static/images/my-index/team-bg.png b/static/images/my-index/team-bg.png new file mode 100644 index 0000000..a15d0d9 Binary files /dev/null and b/static/images/my-index/team-bg.png differ diff --git a/uni_modules/uni-file-picker/changelog.md b/uni_modules/uni-file-picker/changelog.md new file mode 100644 index 0000000..5320eb2 --- /dev/null +++ b/uni_modules/uni-file-picker/changelog.md @@ -0,0 +1,91 @@ +## 1.1.3(2025-12-03) +- 修复: 腾讯云目录错误导致的上传错误问题 +## 1.1.2(2025-09-17) +- 修复 设置readonly属性后内容插槽失效的问题。 +## 1.1.1(2025-09-03) +- 修复 动态dir目录,不生效的问题 +## 1.1.0(2025-09-02) +- 新增 dir 属性,可以选择上传目录 +## 1.0.13(2025-08-18) +- 修复 删除文件后,返回信息不包含file对象的问题 +## 1.0.12(2025-04-14) +- 修复 支付宝小程序 上传样式问题 +## 1.0.10(2024-07-09) +- 优化 vue3兼容性 +## 1.0.9(2024-07-09) +- 修复 value 属性不兼容vue3的bug +## 1.0.8(2024-03-20) +- 补充 删除文件时返回文件下标 +## 1.0.7(2024-02-21) +- 新增 微信小程序选择视频时改用chooseMedia,并返回视频缩略图 +## 1.0.6(2024-01-06) +- 新增 微信小程序不再调用chooseImage,而是调用chooseMedia +## 1.0.5(2024-01-03) +- 新增 上传文件至云存储携带本地文件名称 +## 1.0.4(2023-03-29) +- 修复 手动上传删除一个文件后不能再上传的bug +## 1.0.3(2022-12-19) +- 新增 sourceType 属性, 可以自定义图片和视频选择的来源 +## 1.0.2(2022-07-04) +- 修复 在uni-forms下样式不生效的bug +## 1.0.1(2021-11-23) +- 修复 参数为对象的情况下,url在某些情况显示错误的bug +## 1.0.0(2021-11-19) +- 优化 组件UI,并提供设计资源,详见:[https://uniapp.dcloud.io/component/uniui/resource](https://uniapp.dcloud.io/component/uniui/resource) +- 文档迁移,详见:[https://uniapp.dcloud.io/component/uniui/uni-file-picker](https://uniapp.dcloud.io/component/uniui/uni-file-picker) +## 0.2.16(2021-11-08) +- 修复 传入空对象 ,显示错误的Bug +## 0.2.15(2021-08-30) +- 修复 return-type="object" 时且存在v-model时,无法删除文件的Bug +## 0.2.14(2021-08-23) +- 新增 参数中返回 fileID 字段 +## 0.2.13(2021-08-23) +- 修复 腾讯云传入fileID 不能回显的bug +- 修复 选择图片后,不能放大的问题 +## 0.2.12(2021-08-17) +- 修复 由于 0.2.11 版本引起的不能回显图片的Bug +## 0.2.11(2021-08-16) +- 新增 clearFiles(index) 方法,可以手动删除指定文件 +- 修复 v-model 值设为 null 报错的Bug +## 0.2.10(2021-08-13) +- 修复 return-type="object" 时,无法删除文件的Bug +## 0.2.9(2021-08-03) +- 修复 auto-upload 属性失效的Bug +## 0.2.8(2021-07-31) +- 修复 fileExtname属性不指定值报错的Bug +## 0.2.7(2021-07-31) +- 修复 在某种场景下图片不回显的Bug +## 0.2.6(2021-07-30) +- 修复 return-type为object下,返回值不正确的Bug +## 0.2.5(2021-07-30) +- 修复(重要) H5 平台下如果和uni-forms组件一同使用导致页面卡死的问题 +## 0.2.3(2021-07-28) +- 优化 调整示例代码 +## 0.2.2(2021-07-27) +- 修复 vue3 下赋值错误的Bug +- 优化 h5平台下上传文件导致页面卡死的问题 +## 0.2.0(2021-07-13) +- 组件兼容 vue3,如何创建vue3项目,详见 [uni-app 项目支持 vue3 介绍](https://ask.dcloud.net.cn/article/37834) +## 0.1.1(2021-07-02) +- 修复 sourceType 缺少默认值导致 ios 无法选择文件 +## 0.1.0(2021-06-30) +- 优化 解耦与uniCloud的强绑定关系 ,如不绑定服务空间,默认autoUpload为false且不可更改 +## 0.0.11(2021-06-30) +- 修复 由 0.0.10 版本引发的 returnType 属性失效的问题 +## 0.0.10(2021-06-29) +- 优化 文件上传后进度条消失时机 +## 0.0.9(2021-06-29) +- 修复 在uni-forms 中,删除文件 ,获取的值不对的Bug +## 0.0.8(2021-06-15) +- 修复 删除文件时无法触发 v-model 的Bug +## 0.0.7(2021-05-12) +- 新增 组件示例地址 +## 0.0.6(2021-04-09) +- 修复 选择的文件非 file-extname 字段指定的扩展名报错的Bug +## 0.0.5(2021-04-09) +- 优化 更新组件示例 +## 0.0.4(2021-04-09) +- 优化 file-extname 字段支持字符串写法,多个扩展名需要用逗号分隔 +## 0.0.3(2021-02-05) +- 调整为uni_modules目录规范 +- 修复 微信小程序不指定 fileExtname 属性选择失败的Bug diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js b/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js new file mode 100644 index 0000000..9c6bcdf --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/choose-and-upload-file.js @@ -0,0 +1,287 @@ +'use strict'; + +const ERR_MSG_OK = 'chooseAndUploadFile:ok'; +const ERR_MSG_FAIL = 'chooseAndUploadFile:fail'; + +function chooseImage(opts) { + const { + count, + sizeType = ['original', 'compressed'], + sourceType, + extension + } = opts + return new Promise((resolve, reject) => { + // 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口 + // #ifdef MP-WEIXIN + uni.chooseMedia({ + count, + sizeType, + sourceType, + mediaType: ['image'], + extension, + success(res) { + res.tempFiles.forEach(item => { + item.path = item.tempFilePath; + }) + resolve(normalizeChooseAndUploadFileRes(res, 'image')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL), + }); + }, + }) + // #endif + // #ifndef MP-WEIXIN + uni.chooseImage({ + count, + sizeType, + sourceType, + extension, + success(res) { + resolve(normalizeChooseAndUploadFileRes(res, 'image')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL), + }); + }, + }); + // #endif + + }); +} + +function chooseVideo(opts) { + const { + count, + camera, + compressed, + maxDuration, + sourceType, + extension + } = opts; + return new Promise((resolve, reject) => { + // 微信由于旧接口不再维护,针对微信小程序平台改用chooseMedia接口 + // #ifdef MP-WEIXIN + uni.chooseMedia({ + count, + compressed, + maxDuration, + sourceType, + extension, + mediaType: ['video'], + success(res) { + const { + tempFiles, + } = res; + resolve(normalizeChooseAndUploadFileRes({ + errMsg: 'chooseVideo:ok', + tempFiles: tempFiles.map(item => { + return { + name: item.name || '', + path: item.tempFilePath, + thumbTempFilePath: item.thumbTempFilePath, + size:item.size, + type: (res.tempFile && res.tempFile.type) || '', + width:item.width, + height:item.height, + duration:item.duration, + fileType: 'video', + cloudPath: '', + } + }), + }, 'video')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL), + }); + }, + }) + // #endif + // #ifndef MP-WEIXIN + uni.chooseVideo({ + camera, + compressed, + maxDuration, + sourceType, + extension, + success(res) { + const { + tempFilePath, + duration, + size, + height, + width + } = res; + resolve(normalizeChooseAndUploadFileRes({ + errMsg: 'chooseVideo:ok', + tempFilePaths: [tempFilePath], + tempFiles: [{ + name: (res.tempFile && res.tempFile.name) || '', + path: tempFilePath, + size, + type: (res.tempFile && res.tempFile.type) || '', + width, + height, + duration, + fileType: 'video', + cloudPath: '', + }, ], + }, 'video')); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL), + }); + }, + }); + // #endif + }); +} + +function chooseAll(opts) { + const { + count, + extension + } = opts; + return new Promise((resolve, reject) => { + let chooseFile = uni.chooseFile; + if (typeof wx !== 'undefined' && + typeof wx.chooseMessageFile === 'function') { + chooseFile = wx.chooseMessageFile; + } + if (typeof chooseFile !== 'function') { + return reject({ + errMsg: ERR_MSG_FAIL + ' 请指定 type 类型,该平台仅支持选择 image 或 video。', + }); + } + chooseFile({ + type: 'all', + count, + extension, + success(res) { + resolve(normalizeChooseAndUploadFileRes(res)); + }, + fail(res) { + reject({ + errMsg: res.errMsg.replace('chooseFile:fail', ERR_MSG_FAIL), + }); + }, + }); + }); +} + +function normalizeChooseAndUploadFileRes(res, fileType) { + res.tempFiles.forEach((item, index) => { + if (!item.name) { + item.name = item.path.substring(item.path.lastIndexOf('/') + 1); + } + if (fileType) { + item.fileType = fileType; + } + item.cloudPath = + Date.now() + '_' + index + item.name.substring(item.name.lastIndexOf('.')); + }); + if (!res.tempFilePaths) { + res.tempFilePaths = res.tempFiles.map((file) => file.path); + } + return res; +} + +function uploadCloudFiles(files, max = 5, onUploadProgress) { + files = JSON.parse(JSON.stringify(files)) + const len = files.length + let count = 0 + let self = this + return new Promise(resolve => { + while (count < max) { + next() + } + + function next() { + let cur = count++ + if (cur >= len) { + !files.find(item => !item.url && !item.errMsg) && resolve(files) + return + } + const fileItem = files[cur] + const index = self.files.findIndex(v => v.uuid === fileItem.uuid) + fileItem.url = '' + delete fileItem.errMsg + + uniCloud + .uploadFile({ + filePath: fileItem.path, + cloudPath: fileItem.cloudPath, + fileType: fileItem.fileType, + onUploadProgress: res => { + res.index = index + onUploadProgress && onUploadProgress(res) + } + }) + .then(res => { + fileItem.url = res.fileID + fileItem.index = index + if (cur < len) { + next() + } + }) + .catch(res => { + fileItem.errMsg = res.errMsg || res.message + fileItem.index = index + if (cur < len) { + next() + } + }) + } + }) +} + + + + + +function uploadFiles(choosePromise, { + onChooseFile, + onUploadProgress +}) { + return choosePromise + .then((res) => { + if (onChooseFile) { + const customChooseRes = onChooseFile(res); + if (typeof customChooseRes !== 'undefined') { + return Promise.resolve(customChooseRes).then((chooseRes) => typeof chooseRes === 'undefined' ? + res : chooseRes); + } + } + return res; + }) + .then((res) => { + if (res === false) { + return { + errMsg: ERR_MSG_OK, + tempFilePaths: [], + tempFiles: [], + }; + } + return res + }) +} + +function chooseAndUploadFile(opts = { + type: 'all' +}) { + if (opts.type === 'image') { + return uploadFiles(chooseImage(opts), opts); + } else if (opts.type === 'video') { + return uploadFiles(chooseVideo(opts), opts); + } + return uploadFiles(chooseAll(opts), opts); +} + +export { + chooseAndUploadFile, + uploadCloudFiles +}; diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue new file mode 100644 index 0000000..cf67ac7 --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/uni-file-picker.vue @@ -0,0 +1,680 @@ + + + + + diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue new file mode 100644 index 0000000..0d26379 --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-file.vue @@ -0,0 +1,323 @@ + + + + + \ No newline at end of file diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue new file mode 100644 index 0000000..0ce5eb7 --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/upload-image.vue @@ -0,0 +1,285 @@ + + + + + diff --git a/uni_modules/uni-file-picker/components/uni-file-picker/utils.js b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js new file mode 100644 index 0000000..1bc9259 --- /dev/null +++ b/uni_modules/uni-file-picker/components/uni-file-picker/utils.js @@ -0,0 +1,110 @@ +/** + * 获取文件名和后缀 + * @param {String} name + */ +export const get_file_ext = (name) => { + const last_len = name.lastIndexOf('.') + const len = name.length + return { + name: name.substring(0, last_len), + ext: name.substring(last_len + 1, len) + } +} + +/** + * 获取扩展名 + * @param {Array} fileExtname + */ +export const get_extname = (fileExtname) => { + if (!Array.isArray(fileExtname)) { + let extname = fileExtname.replace(/(\[|\])/g, '') + return extname.split(',') + } else { + return fileExtname + } + return [] +} + +/** + * 获取文件和检测是否可选 + */ +export const get_files_and_is_max = (res, _extname) => { + let filePaths = [] + let files = [] + if(!_extname || _extname.length === 0){ + return { + filePaths, + files + } + } + res.tempFiles.forEach(v => { + let fileFullName = get_file_ext(v.name) + const extname = fileFullName.ext.toLowerCase() + if (_extname.indexOf(extname) !== -1) { + files.push(v) + filePaths.push(v.path) + } + }) + if (files.length !== res.tempFiles.length) { + uni.showToast({ + title: `当前选择了${res.tempFiles.length}个文件 ,${res.tempFiles.length - files.length} 个文件格式不正确`, + icon: 'none', + duration: 5000 + }) + } + + return { + filePaths, + files + } +} + + +/** + * 获取图片信息 + * @param {Object} filepath + */ +export const get_file_info = (filepath) => { + return new Promise((resolve, reject) => { + uni.getImageInfo({ + src: filepath, + success(res) { + resolve(res) + }, + fail(err) { + reject(err) + } + }) + }) +} +/** + * 获取封装数据 + */ +export const get_file_data = async (files, type = 'image') => { + // 最终需要上传数据库的数据 + let fileFullName = get_file_ext(files.name) + const extname = fileFullName.ext.toLowerCase() + let filedata = { + name: files.name, + uuid: files.uuid, + extname: extname || '', + cloudPath: files.cloudPath, + fileType: files.fileType, + thumbTempFilePath: files.thumbTempFilePath, + url: files.path || files.path, + size: files.size, //单位是字节 + image: {}, + path: files.path, + video: {} + } + if (type === 'image') { + const imageinfo = await get_file_info(files.path) + delete filedata.video + filedata.image.width = imageinfo.width + filedata.image.height = imageinfo.height + filedata.image.location = imageinfo.path + } else { + delete filedata.image + } + return filedata +} diff --git a/uni_modules/uni-file-picker/package.json b/uni_modules/uni-file-picker/package.json new file mode 100644 index 0000000..b13e315 --- /dev/null +++ b/uni_modules/uni-file-picker/package.json @@ -0,0 +1,105 @@ +{ + "id": "uni-file-picker", + "displayName": "uni-file-picker 文件选择上传", + "version": "1.1.3", + "description": "文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间", + "keywords": [ + "uni-ui", + "uniui", + "图片上传", + "文件上传" +], + "repository": "https://github.com/dcloudio/uni-ui", + "engines": { + "HBuilderX": "", + "uni-app": "^4.33", + "uni-app-x": "" + }, + "directories": { + "example": "../../temps/example_temps" + }, + "dcloudext": { + "sale": { + "regular": { + "price": "0.00" + }, + "sourcecode": { + "price": "0.00" + } + }, + "contact": { + "qq": "" + }, + "declaration": { + "ads": "无", + "data": "无", + "permissions": "无" + }, + "npmurl": "https://www.npmjs.com/package/@dcloudio/uni-ui", + "type": "component-vue", + "darkmode": "x", + "i18n": "x", + "widescreen": "x" + }, + "uni_modules": { + "dependencies": [ + "uni-scss" + ], + "encrypt": [], + "platforms": { + "cloud": { + "tcb": "√", + "aliyun": "√", + "alipay": "√" + }, + "client": { + "uni-app": { + "vue": { + "vue2": "√", + "vue3": "√" + }, + "web": { + "safari": "√", + "chrome": "√" + }, + "app": { + "vue": "√", + "nvue": "-", + "android": "√", + "ios": "√", + "harmony": "√" + }, + "mp": { + "weixin": "√", + "alipay": "√", + "toutiao": "√", + "baidu": "√", + "kuaishou": "√", + "jd": "-", + "harmony": "-", + "qq": "√", + "lark": "-" + }, + "quickapp": { + "huawei": "√", + "union": "√" + } + }, + "uni-app-x": { + "web": { + "safari": "-", + "chrome": "-" + }, + "app": { + "android": "-", + "ios": "-", + "harmony": "-" + }, + "mp": { + "weixin": "-" + } + } + } + } + } +} \ No newline at end of file diff --git a/uni_modules/uni-file-picker/readme.md b/uni_modules/uni-file-picker/readme.md new file mode 100644 index 0000000..7393e6c --- /dev/null +++ b/uni_modules/uni-file-picker/readme.md @@ -0,0 +1,10 @@ + +## FilePicker 文件选择上传 + +> **组件名:uni-file-picker** +> 代码块: `uFilePicker` + + +文件选择上传组件,可以选择图片、视频等任意文件并上传到当前绑定的服务空间 + +### [查看文档](https://uniapp.dcloud.io/component/uniui/uni-file-picker) \ No newline at end of file diff --git a/utils/request.js b/utils/request.js index dc54999..3a0ff57 100644 --- a/utils/request.js +++ b/utils/request.js @@ -1,6 +1,6 @@ import { getToken, removeToken } from './storage' -const BASE_URL = 'http://c36bd4b4.natappfree.cc' +const BASE_URL = import.meta.env.VITE_SYSTEM_URL /** * 网络请求封装 @@ -14,7 +14,7 @@ const request = options => { method: 'GET', data: {}, header: { - 'deviceId': uni.getDeviceInfo().deviceId, + deviceId: uni.getDeviceInfo().deviceId, 'Content-Type': 'application/json' // 默认请求内容类型 } } diff --git a/utils/uploadFile.js b/utils/uploadFile.js new file mode 100644 index 0000000..61e69a3 --- /dev/null +++ b/utils/uploadFile.js @@ -0,0 +1,134 @@ +import { getToken } from './storage' + +/** + * 二次封装的uni.uploadFile方法 (Promise化) + * @param {string} filePath - 要上传的文件路径 + * @param {Object} [config] - 可选配置项 + * @param {string} [config.url] - 上传接口地址,若不传则使用默认或全局配置 + * @param {string} [config.name='file'] - 文件对应的 key + * @param {Object} [config.formData={}] - 额外的 form data + * @param {Object} [config.header] - 请求头,可覆盖默认头 + * @param {number} [config.timeout] - 超时时间(ms) + * @returns {Promise} 返回一个Promise对象,成功时解析上传响应数据 + */ +export const uploadSingleFile = (filePath, config = {}) => { + // 默认配置,可从全局导入或在此定义 + const DEFAULT_CONFIG = { + baseURL: import.meta.env.VITE_SYSTEM_URL, + // timeout: 30000, + name: 'file', + header: { + deviceId: uni.getDeviceInfo().deviceId, + Authorization: `Bearer ${getToken()}` + } + } + + // 合并配置 + const mergedConfig = { + ...DEFAULT_CONFIG, + ...config, + header: { + ...DEFAULT_CONFIG.header + } + } + + const { baseURL, ...uploadOptions } = mergedConfig + const finalUrl = baseURL + ? `${baseURL}${uploadOptions.url || ''}` + : uploadOptions.url + + if (!finalUrl) { + return Promise.reject(new Error('上传接口地址不能为空')) + } + + return new Promise((resolve, reject) => { + uni.showLoading({ + title: '上传中...', + mask: true // 防止触摸穿透 + }) + const uploadTask = uni.uploadFile({ + url: finalUrl, + filePath: filePath, + name: uploadOptions.name, + formData: uploadOptions.formData, + header: uploadOptions.header, + timeout: uploadOptions.timeout, + success: res => { + uni.hideLoading() + if (res.statusCode === 200) { + try { + // 尝试解析返回数据,假设是 + const data = + typeof res.data === 'string' + ? JSON.parse(res.data) + : res.data + // 验证失效去登录页 + if (data.code === 401) { + uni.removeStorage({ + key: 'token' + }) + uni.reLaunch({ + url: '/pages/login/login' + }) + return + } + if (data.code === 200) { + console.log('上传成功:', data) + resolve(data.url) // 根据后端实际结构,可能需进一步处理,如 data.data.url + return + } + + uni.showToast({ + title: data.msg || '请求失败', + icon: 'none' + }) + } catch (e) { + // 解析失败可能返回的是字符串,直接返回 + resolve(res.data) + } + return + } + + reject(new Error(`上传失败,状态码: ${res.statusCode}`)) + }, + fail: err => { + uni.hideLoading() + reject(err) + } + }) + + // 可选:监听上传进度事件[6](@ref) + uploadTask.onProgressUpdate(res => { + console.log('上传进度:', res.progress) + console.log('已上传:', res.totalBytesSent, '字节') + console.log('总大小:', res.totalBytesExpectedToSend, '字节') + if (res.progress !== 100) { + uni.showLoading({ + title: `업로드 진행: ${res.progress}`, + mask: true // 防止触摸穿透 + }) + } + // 可通过自定义事件或回调函数将进度传递出去 + if (typeof config.onProgress === 'function') { + config.onProgress(res) + } + }) + }) +} + +/** + * 多文件上传 + * @param {Array} filePaths - 文件路径数组 + * @param {Object} config - 同uploadSingleFile的config + * @returns {Promise} 返回一个Promise,解析为所有上传结果数组 + */ +export const uploadMultipleFiles = (filePaths, config = {}) => { + // 使用Promise.all同时发起所有上传请求[3,4](@ref) + const uploadPromises = filePaths.map( + filePath => + uploadSingleFile(filePath, config) + .then(res => ({ status: 'fulfilled', value: res })) // 成功,记录结果 + .catch(err => ({ status: 'rejected', reason: err })) // 失败,记录原因 + ) + return Promise.all(uploadPromises) +}