findme-miniprogram-frontend/utils/media-picker.js
2025-12-27 17:16:03 +08:00

357 lines
9.6 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 媒体选择工具类 - 支持拍照、拍视频、相册选择
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;