366 lines
10 KiB
JavaScript
366 lines
10 KiB
JavaScript
// 媒体选择工具类 - 支持拍照、拍视频、相册选择
|
||
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;
|
||
|
||
console.log('📸 开始选择图片:', { count, sourceType, sizeType });
|
||
|
||
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) => {
|
||
console.log('✅ chooseMedia选择图片成功:', 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) => {
|
||
console.log('✅ chooseImage选择图片成功:', 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;
|
||
|
||
console.log('🎥 开始选择视频:', { sourceType, maxDuration, camera });
|
||
|
||
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) => {
|
||
console.log('✅ chooseMedia选择视频成功:', 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) => {
|
||
console.log('✅ chooseVideo选择视频成功:', 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;
|
||
|
||
console.log('📱 开始选择混合媒体:', { count, mediaType, sourceType });
|
||
|
||
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) => {
|
||
console.log('✅ chooseMedia选择媒体成功:', 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;
|