findme-miniprogram-frontend/utils/media-picker.js

358 lines
9.6 KiB
JavaScript
Raw Normal View History

2025-12-27 17:16:03 +08:00
// 媒体选择工具类 - 支持拍照、拍视频、相册选择
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;