Files
ys-app/src/utils/common.js
2025-12-19 16:54:02 +08:00

403 lines
14 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.

import { showAlert } from '@/utils/message.js'
// 递归算法
export const initTree = (arr, parentId = '0', id) => {
const tree = [];
arr.filter(item => item.parentId === parentId).forEach(item => {
const children = initTree(arr, item[id]);
if (children.length > 0) {
item.children = children;
}
tree.push(item);
});
return tree;
}
// 安卓异步调用
export const requestAndroidPermissionAsync = (systemInfo, permissions) => {
return new Promise((resolve, reject) => {
// if (uni.getSystemInfoSync().platform !== 'android') {
// resolve({ granted: true, nonSystem: true })
// return
// }
plus.android.requestPermissions(permissions, (result) => {
showAlert("result=>" + JSON.stringify(result))
// const granted = Object.values(result.granted).every(Boolean);
let granted = false;
if (systemInfo.osVersion < 13) {
granted = result.granted.length == 2
} else if (systemInfo.osVersion == 13) {
granted = result.granted.length == 3
} else {
granted = result.granted.length == 1
}
resolve({ ...result, granted })
}, (error) => {
reject(error)
})
})
}
// 安卓同步调用
export const requestAndroidPermission = (systemInfo) => {
let granted = false;
const Manifest = plus.android.importClass("android.Manifest");
const MainActivity = plus.android.runtimeMainActivity();
if (systemInfo.osVersion < 13) { // 安卓系统版本
let permissionStatus = MainActivity.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE);
let perStatus = 0;
if (permissionStatus === 0) {
perStatus++;
}
permissionStatus = MainActivity.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (permissionStatus === 0) {
perStatus++;
}
if (perStatus == 2) {
granted = true
} else {
granted = false //"当前文件保存权限被关闭,请到设置中开启才能继续后续操作"
goPermission();//调用授权方法去授权
}
} else if (systemInfo.osVersion == 13) {
let permissionStatus = MainActivity.checkSelfPermission(Manifest.permission.READ_MEDIA_IMAGES);
let perStatus = 0;
if (permissionStatus === 0) {
perStatus++;
}
permissionStatus = MainActivity.checkSelfPermission(Manifest.permission.READ_MEDIA_VIDEO);
if (permissionStatus === 0) {
perStatus++;
}
permissionStatus = MainActivity.checkSelfPermission(Manifest.permission.READ_MEDIA_AUDIO);
if (permissionStatus === 0) {
perStatus++;
}
if (perStatus == 3) {
granted = true
} else {
granted = false //"当前文件保存权限被关闭,请到设置中开启才能继续后续操作"
goPermission();//调用授权方法去授权
}
} else {
let permissionStatus = MainActivity.checkSelfPermission(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED);
let perStatus = 0;
if (permissionStatus === 0) {
perStatus++;
}
if (perStatus == 1) {
granted = true
} else {
granted = false //"当前文件保存权限被关闭,请到设置中开启才能继续后续操作"
goPermission();//调用授权方法去授权
}
}
return granted
}
// 弹窗跳授权页面
const goPermission = () => {
uni.showModal({
title: '提示',
content: "请进行设备授权",
cancelText: '去授权',
confirmText: '已授权',
success: function (res) {
if (res.confirm) {
uni.reLaunch({
url: '/pages/loading/loading',
});
} else if (res.cancel) {
jumpAuthPermission();
}
}
})
}
// 跳转授权按钮
const jumpAuthPermission=()=>{
var main = plus.android.runtimeMainActivity();
var Intent = plus.android.importClass('android.content.Intent');
var Uri = plus.android.importClass('android.net.Uri');
var pkg = main.getPackageName();
var intent = new Intent('android.settings.APPLICATION_DETAILS_SETTINGS');
intent.setData(Uri.parse('package:' + pkg));
main.startActivity(intent);
setTimeout(()=>{
uni.reLaunch({
url: '/pages/loading/loading',
});
},500)
}
// 跳转授权
const jumpAuthPermission2 = () => {
let main = plus.android.runtimeMainActivity();
let Intent = plus.android.importClass('android.content.Intent');
let Uri = plus.android.importClass('android.net.Uri');
let Build = plus.android.importClass('android.os.Build');
let Settings = plus.android.importClass('android.provider.Settings');
let PackageManager = plus.android.importClass('android.content.pm.PackageManager');
let pkg = main.getPackageName();
let intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
showAlert(Build.VERSION.SDK_INT)
// 尝试直接跳转到存储权限设置Android 13+ 支持)
if (Build.VERSION.SDK_INT >= 33) {
// Android 13+ 尝试直接打开存储权限页面
intent.setAction(Settings.ACTION_MANAGE_APP_PERMISSIONS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, pkg);
// 指定权限类型为存储需要Android 13+支持)
intent.putExtra(Settings.EXTRA_PERMISSION_NAME, "android.permission.READ_EXTERNAL_STORAGE");
}
// Android 11-12 尝试直接跳转到权限列表
else if (Build.VERSION.SDK_INT >= 30) {
intent.setAction(Settings.ACTION_MANAGE_APP_PERMISSIONS);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, pkg);
}
// Android 6.0-10 跳转到应用详情页(用户需手动点击权限)
else if (Build.VERSION.SDK_INT >= 23) {
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
let uri = Uri.fromParts("package", pkg, null);
intent.setData(uri);
}
// 低版本系统
else {
intent.setAction(Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
}
showAlert("main=>"+main)
showAlert("intent=>"+intent)
main.startActivity(intent);
setTimeout(() => {
uni.reLaunch({
url: '/pages/loading/loading',
});
}, 1000)
} catch (e) {
showAlert(e)
// 异常情况下降级处理
console.error("跳转存储权限页面失败,使用备用方案", e);
let fallbackIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
fallbackIntent.setData(Uri.parse('package:' + pkg));
fallbackIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
main.startActivity(fallbackIntent);
setTimeout(() => {
uni.reLaunch({
url: '/pages/loading/loading',
});
}, 1000)
}
}
// 判断文件是图片还是视频
export const getFileType = (filePathOrName) => {
// 从路径或文件名中提取扩展名
let suffix = '';
try {
suffix = filePathOrName.split('.').pop().toLowerCase();
} catch (err) {
return 'unknown';
}
// 定义常见的图片和视频扩展名
const imageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'];
const videoExtensions = ['mp4', 'mov', 'avi', 'm4v', '3gp', 'mpeg', 'mkv', 'wmv'];
if (imageExtensions.includes(suffix)) {
return 'image';
} else if (videoExtensions.includes(suffix)) {
return 'video';
} else {
return 'other';
}
}
// 计算图片的新尺寸
const calculateNewSize = (originalWidth, originalHeight)=>{
const MAX_SIZE = 1920;
let newWidth = originalWidth;
let newHeight = originalHeight;
// 如果宽或高超过最大尺寸,进行等比缩放
if (originalWidth > MAX_SIZE || originalHeight > MAX_SIZE) {
if (originalWidth > originalHeight) {
// 宽图
newWidth = MAX_SIZE;
newHeight = Math.round((originalHeight * MAX_SIZE) / originalWidth);
} else {
// 高图或方图
newHeight = MAX_SIZE;
newWidth = Math.round((originalWidth * MAX_SIZE) / originalHeight);
}
}
// console.log('调整后尺寸:', newWidth, 'x', newHeight);
return {
width: newWidth,
height: newHeight
};
}
// 图片压缩处理tempFilePaths
export const compressImageUni = (file) => {
return new Promise((resolve, reject) => {
try {
console.log("compressImageUni=>file=>",file)
uni.getImageInfo({
src: file,
success: function (image) {
const newSize = calculateNewSize(image.width, image.height);
console.log("调整后的尺寸=>",newSize)
uni.compressImage({
src: file,
compressedWidth:newSize.width,
compressedHeight:newSize.height,
quality: 100, // 压缩质量 (0-100)
success: (res) => {
// console.log('压缩成功,临时路径:', res.tempFilePath);
resolve(res.tempFilePath)
},
fail: (err) => {
console.log('压缩失败:', err);
reject(err)
}
});
}
});
} catch (error) {
console.log('压缩失败:', error);
}
})
}
// H5 获取视频第一帧
const getFirstFrameInH5 = (videoPath) => {
return new Promise((resolve, reject) => {
const video = document.createElement('video')
video.src = videoPath
video.crossOrigin = 'anonymous'
video.addEventListener('loadeddata', () => {
video.currentTime = 0.1
})
video.addEventListener('seeked', () => {
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = video.videoWidth
canvas.height = video.videoHeight
ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
const dataUrl = canvas.toDataURL('image/jpeg', 0.8)
resolve(dataUrl)
})
video.addEventListener('error', reject)
})
}
// App平台获取第一帧Android/iOS
const getFirstFrameInApp = (videoPath) => {
return new Promise((resolve, reject) => {
// 方法1使用原生VideoPlayer推荐
// #ifdef APP-PLUS
try {
const videoPlayer = plus.video.createVideoPlayer('firstFramePlayer', {
src: videoPath,
autoplay: false,
controls: false,
showLoading: false,
showProgress: false
})
// 监听视频准备完成
videoPlayer.addEventListener('loadeddata', () => {
// 截图
videoPlayer.snapshot({
format: 'jpg',
quality: 80
}, (res) => {
// res.target 是图片临时路径
console.log('截图成功:', res)
resolve(res.target)
// 销毁播放器
videoPlayer.close()
}, (error) => {
console.error('截图失败:', error)
reject(error)
videoPlayer.close()
})
}, false)
videoPlayer.addEventListener('error', (error) => {
console.error('视频加载失败:', error)
reject(error)
videoPlayer.close()
})
} catch (error) {
console.error('创建VideoPlayer失败:', error)
// 方法2备用方案使用HTML5 video如果原生方法失败
// showAppVideo.value = true
// showAppCanvas.value = true
// // 等待DOM更新后获取元素
// setTimeout(() => {
// const video = document.getElementById('appVideo')
// const canvas = document.getElementById('appCanvas')
// const ctx = canvas.getContext('2d')
// video.onloadedmetadata = () => {
// canvas.width = video.videoWidth
// canvas.height = video.videoHeight
// video.onseeked = () => {
// ctx.drawImage(video, 0, 0, canvas.width, canvas.height)
// const dataUrl = canvas.toDataURL('image/jpeg', 0.8)
// // 清理
// showAppVideo.value = false
// showAppCanvas.value = false
// resolve(dataUrl)
// }
// video.currentTime = 0.1
// }
// video.onerror = reject
// }, 100)
}
// #endif
})
}
// 获取视频第一帧(跨平台处理)
export const getVideoFirstFrame = (videoPath) => {
return new Promise((resolve, reject) => {
// #ifdef H5
// H5平台使用canvas
getFirstFrameInH5(videoPath).then(resolve).catch(reject)
// #endif
// #ifdef APP-PLUS
// App平台使用plus.video
getFirstFrameInApp(videoPath).then(resolve).catch(reject)
// #endif
})
}