upload project
This commit is contained in:
commit
06961cae04
422 changed files with 110626 additions and 0 deletions
357
utils/media-picker.js
Normal file
357
utils/media-picker.js
Normal file
|
|
@ -0,0 +1,357 @@
|
|||
// 媒体选择工具类 - 支持拍照、拍视频、相册选择
|
||||
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;
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue