// 媒体选择工具类 - 支持拍照、拍视频、相册选择 class MediaPicker { constructor() { this.maxImageCount = 9; // 最多选择9张图片 this.maxVideoCount = 1; // 最多选择1个视频 this.maxVideoDuration = 60; // 视频最长60秒 this.maxImageSize = 10 * 1024 * 1024; // 图片最大10MB this.maxVideoSize = 100 * 1024 * 1024; // 视频最大100MB } // 🔥 ===== 图片选择功能 ===== /** * 选择图片 - 支持拍照和相册 * @param {Object} options 选项 * @param {number} options.count 最多选择数量,默认9 * @param {Array} options.sourceType 来源类型 ['album', 'camera'] * @param {Array} options.sizeType 图片尺寸 ['original', 'compressed'] * @returns {Promise} 返回选择的图片信息 */ async chooseImages(options = {}) { const { count = this.maxImageCount, sourceType = ['album', 'camera'], sizeType = ['compressed', 'original'] } = options; try { // 优先使用新版API if (wx.chooseMedia) { return await this.chooseMediaImages({ count, sourceType, sizeType }); } else { return await this.chooseImageLegacy({ count, sourceType, sizeType }); } } catch (error) { console.error('❌ 选择图片失败:', error); throw error; } } /** * 使用新版chooseMedia API选择图片 */ chooseMediaImages(options) { return new Promise((resolve, reject) => { wx.chooseMedia({ count: options.count, mediaType: ['image'], sourceType: options.sourceType, camera: 'back', success: (res) => { const images = res.tempFiles.map(file => ({ path: file.tempFilePath, size: file.size, type: 'image', width: file.width || 0, height: file.height || 0, duration: 0 })); resolve({ success: true, files: images, count: images.length }); }, fail: (error) => { console.error('❌ chooseMedia选择图片失败:', error); reject(error); } }); }); } /** * 使用传统chooseImage API选择图片 */ chooseImageLegacy(options) { return new Promise((resolve, reject) => { wx.chooseImage({ count: options.count, sizeType: options.sizeType, sourceType: options.sourceType, success: (res) => { const images = res.tempFilePaths.map((path, index) => ({ path: path, size: res.tempFiles ? res.tempFiles[index]?.size || 0 : 0, type: 'image', width: 0, height: 0, duration: 0 })); resolve({ success: true, files: images, count: images.length }); }, fail: (error) => { console.error('❌ chooseImage选择图片失败:', error); reject(error); } }); }); } // 🔥 ===== 视频选择功能 ===== /** * 选择视频 - 支持拍摄和相册 * @param {Object} options 选项 * @param {Array} options.sourceType 来源类型 ['album', 'camera'] * @param {number} options.maxDuration 最大时长(秒) * @param {string} options.camera 摄像头 'front'|'back' * @returns {Promise} 返回选择的视频信息 */ async chooseVideo(options = {}) { const { sourceType = ['album', 'camera'], maxDuration = this.maxVideoDuration, camera = 'back' } = options; try { // 优先使用新版API if (wx.chooseMedia) { return await this.chooseMediaVideo({ sourceType, maxDuration, camera }); } else { return await this.chooseVideoLegacy({ sourceType, maxDuration, camera }); } } catch (error) { console.error('❌ 选择视频失败:', error); throw error; } } /** * 使用新版chooseMedia API选择视频 */ chooseMediaVideo(options) { return new Promise((resolve, reject) => { wx.chooseMedia({ count: 1, mediaType: ['video'], sourceType: options.sourceType, maxDuration: options.maxDuration, camera: options.camera, success: (res) => { // 健壮性判断,防止tempFiles为空或无元素 if (!res.tempFiles || !Array.isArray(res.tempFiles) || res.tempFiles.length === 0) { console.warn('⚠️ chooseMedia返回空tempFiles:', res); resolve({ success: false, files: [], count: 0, message: '未选择视频' }); return; } const video = res.tempFiles[0]; if (!video || !video.tempFilePath) { console.warn('⚠️ chooseMedia返回的video对象异常:', video); resolve({ success: false, files: [], count: 0, message: '未选择有效视频' }); return; } const videoInfo = { path: video.tempFilePath, size: video.size, type: 'video', width: video.width || 0, height: video.height || 0, duration: video.duration || 0, thumbTempFilePath: video.thumbTempFilePath || '' }; resolve({ success: true, files: [videoInfo], count: 1 }); }, fail: (error) => { console.error('❌ chooseMedia选择视频失败:', error); reject(error); } }); }); } /** * 使用传统chooseVideo API选择视频 */ chooseVideoLegacy(options) { return new Promise((resolve, reject) => { wx.chooseVideo({ sourceType: options.sourceType, maxDuration: options.maxDuration, camera: options.camera, success: (res) => { const videoInfo = { path: res.tempFilePath, size: res.size || 0, type: 'video', width: res.width || 0, height: res.height || 0, duration: res.duration || 0, thumbTempFilePath: res.thumbTempFilePath || '' }; resolve({ success: true, files: [videoInfo], count: 1 }); }, fail: (error) => { console.error('❌ chooseVideo选择视频失败:', error); reject(error); } }); }); } // 🔥 ===== 混合媒体选择功能 ===== /** * 选择混合媒体 - 图片和视频 * @param {Object} options 选项 * @returns {Promise} 返回选择的媒体信息 */ async chooseMedia(options = {}) { const { count = 9, mediaType = ['image', 'video'], sourceType = ['album', 'camera'], maxDuration = this.maxVideoDuration, camera = 'back' } = options; if (!wx.chooseMedia) { throw new Error('当前微信版本不支持chooseMedia API'); } return new Promise((resolve, reject) => { wx.chooseMedia({ count: count, mediaType: mediaType, sourceType: sourceType, maxDuration: maxDuration, camera: camera, success: (res) => { const files = res.tempFiles.map(file => ({ path: file.tempFilePath, size: file.size, type: file.fileType, // 'image' 或 'video' width: file.width || 0, height: file.height || 0, duration: file.duration || 0, thumbTempFilePath: file.thumbTempFilePath || '' })); resolve({ success: true, files: files, count: files.length }); }, fail: (error) => { console.error('❌ chooseMedia选择媒体失败:', error); reject(error); } }); }); } // 🔥 ===== 工具方法 ===== /** * 检查文件大小 */ checkFileSize(file) { const maxSize = file.type === 'image' ? this.maxImageSize : this.maxVideoSize; if (file.size > maxSize) { const maxSizeMB = Math.round(maxSize / 1024 / 1024); throw new Error(`文件大小超过限制,最大支持${maxSizeMB}MB`); } return true; } /** * 获取文件信息 */ async getFileInfo(filePath) { return new Promise((resolve, reject) => { wx.getFileInfo({ filePath: filePath, success: resolve, fail: reject }); }); } /** * 显示选择媒体的操作菜单 */ showMediaActionSheet(options = {}) { const { showCamera = true, showAlbum = true, showVideo = true } = options; const itemList = []; const actions = []; if (showCamera) { itemList.push('拍照'); actions.push(() => this.chooseImages({ sourceType: ['camera'] })); } if (showAlbum) { itemList.push('从相册选择图片'); actions.push(() => this.chooseImages({ sourceType: ['album'] })); } if (showVideo) { itemList.push('拍摄视频'); actions.push(() => this.chooseVideo({ sourceType: ['camera'] })); itemList.push('从相册选择视频'); actions.push(() => this.chooseVideo({ sourceType: ['album'] })); } return new Promise((resolve, reject) => { wx.showActionSheet({ itemList: itemList, success: (res) => { const selectedAction = actions[res.tapIndex]; if (selectedAction) { selectedAction().then(resolve).catch(reject); } }, fail: (error) => { if (error.errMsg !== 'showActionSheet:fail cancel') { reject(error); } } }); }); } } // 创建全局单例 const mediaPicker = new MediaPicker(); module.exports = mediaPicker;