449 lines
11 KiB
JavaScript
449 lines
11 KiB
JavaScript
import {
|
||
get_base_url
|
||
} from '@/api/request';
|
||
// #ifdef APP-PLUS
|
||
import showDialog from '@/common/dialogMessage'
|
||
import common from '@/common/common'
|
||
// #endif
|
||
function msg(title, duration = 1500) {
|
||
uni.showToast({
|
||
title: title,
|
||
duration: duration,
|
||
icon: 'none',
|
||
mask: true,
|
||
});
|
||
}
|
||
|
||
let isShowConfirm = false
|
||
|
||
function show(title, msg, showCancel = true, cancelText = '取消', confirmText = '确定') {
|
||
if (isShowConfirm) {
|
||
return new Promise((resolve, reject) => {
|
||
reject({});
|
||
});
|
||
}
|
||
isShowConfirm = true
|
||
return new Promise((resolve, reject) => {
|
||
// 创建通用参数对象
|
||
const dialogOptions = {
|
||
title,
|
||
content: msg,
|
||
showCancel,
|
||
cancelText,
|
||
confirmText,
|
||
success: (res) => {
|
||
// 统一处理成功回调,解析为布尔值
|
||
resolve(!!res.confirm);
|
||
isShowConfirm = false
|
||
},
|
||
|
||
};
|
||
// #ifdef APP-PLUS
|
||
if (getPhoneEnvBool('AND')) {
|
||
// 安卓环境使用showDialog,补充cancel回调
|
||
showDialog({
|
||
...dialogOptions,
|
||
cancel: () => {
|
||
console.log('用户点击取消');
|
||
isShowConfirm = false
|
||
resolve(false); // 取消时也返回Promise结果
|
||
}
|
||
});
|
||
} else {
|
||
// 其他环境使用uni.showModal,补充fail回调
|
||
uni.showModal({
|
||
...dialogOptions,
|
||
fail: (res) => {
|
||
isShowConfirm = false
|
||
reject(res);
|
||
}
|
||
});
|
||
}
|
||
// #endif
|
||
// #ifdef H5
|
||
uni.showModal({
|
||
...dialogOptions,
|
||
fail: (res) => {
|
||
isShowConfirm = false
|
||
reject(res);
|
||
}
|
||
});
|
||
// #endif
|
||
});
|
||
}
|
||
|
||
const closeStatus = () => {
|
||
isShowConfirm = false
|
||
}
|
||
const loading = (title = '加载中', mask = true) => uni.showLoading({
|
||
title: title,
|
||
mask: mask
|
||
})
|
||
const hideLoading = () => uni.hideLoading()
|
||
|
||
// 根据姓名的长度生成对应的带星号格式
|
||
export const formatName = (name) => {
|
||
// 处理空值或非字符串情况
|
||
if (!name || typeof name !== 'string') {
|
||
return '';
|
||
}
|
||
const familyName = name.charAt(0); // 取姓氏(第一个字符)
|
||
const givenNameLength = name.length - 1; // 名字部分的长度
|
||
|
||
// 根据名字长度计算星号数量,最多4个
|
||
const starCount = Math.min(givenNameLength, 3);
|
||
const stars = '*'.repeat(starCount);
|
||
|
||
return familyName + stars;
|
||
}
|
||
|
||
// 防抖工具函数
|
||
function debounce(fn, wait = 300) {
|
||
let isLocked = false; // 锁定状态标记
|
||
return function(...args) {
|
||
// 如果处于锁定状态,直接返回不执行
|
||
if (isLocked) {
|
||
return;
|
||
}
|
||
// 执行函数
|
||
fn.apply(this, args);
|
||
|
||
// 锁定,防止再次执行
|
||
isLocked = true;
|
||
|
||
// 等待指定时间后解锁
|
||
setTimeout(() => {
|
||
isLocked = false;
|
||
}, wait);
|
||
};
|
||
}
|
||
|
||
// 保留当前页面,跳转到应用内的某个页面,使用uni.navigateBack可以返回到原页面。
|
||
const navigateTo = debounce(function(url, data = {}) {
|
||
uni.navigateTo({
|
||
url: url,
|
||
...data
|
||
});
|
||
})
|
||
|
||
// 关闭所有页面,打开到应用内的某个页面。
|
||
const reLaunch = url => {
|
||
uni.reLaunch({
|
||
url: url
|
||
});
|
||
}
|
||
// 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。
|
||
const switchTab = url => {
|
||
uni.switchTab({
|
||
url: url
|
||
});
|
||
}
|
||
// 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages() 获取当前的页面栈,决定需要返回几层。
|
||
const navigateBack = (delta = 1, fun = () => {}, data = {}) => {
|
||
uni.navigateBack({
|
||
delta: delta,
|
||
...data,
|
||
success() {
|
||
fun()
|
||
}
|
||
})
|
||
}
|
||
|
||
//关闭当前页面,跳转到应用内的某个页面。
|
||
const redirectTo = (url, obj = {}) => uni.redirectTo({
|
||
url: url,
|
||
...obj
|
||
});
|
||
|
||
// 时间转换时间戳
|
||
const dateToTime = (dateString) => {
|
||
let date = new Date(dateString);
|
||
let timestamp = date.getTime();
|
||
return timestamp
|
||
}
|
||
|
||
// 数字格式化
|
||
const formatDate2 = (timestamp, format = 'yyyy-MM-dd HH:mm:ss') => {
|
||
if (!timestamp)
|
||
return ''
|
||
let date
|
||
try {
|
||
if (timestamp) {
|
||
if (typeof timestamp == 'number' && timestamp <= 9999999999) {
|
||
timestamp *= 1000
|
||
}
|
||
date = new Date(timestamp)
|
||
} else {
|
||
date = new Date()
|
||
}
|
||
} catch (e) {
|
||
return ''
|
||
}
|
||
let day = date.getDate()
|
||
let month = date.getMonth() + 1
|
||
let year = date.getFullYear()
|
||
let hours = date.getHours()
|
||
let minutes = date.getMinutes()
|
||
let seconds = date.getSeconds()
|
||
|
||
// 替换日期格式中的占位符
|
||
return format
|
||
.replace('yyyy', year)
|
||
.replace('MM', month.toString().padStart(2, '0'))
|
||
.replace('dd', day.toString().padStart(2, '0'))
|
||
.replace('HH', hours.toString().padStart(2, '0'))
|
||
.replace('mm', minutes.toString().padStart(2, '0'))
|
||
.replace('ss', seconds.toString().padStart(2, '0'))
|
||
}
|
||
|
||
|
||
|
||
// 获取token
|
||
export const getToken = () => uni.getStorageSync('token')
|
||
export const setToken = data => uni.setStorageSync('token', data)
|
||
export const setUserInfo = data => uni.setStorageSync('userInfo', data)
|
||
export const getUserInfo = (key = '') => {
|
||
const userInfo = uni.getStorageSync('userInfo')
|
||
return '' === key ? userInfo : userInfo[key];
|
||
}
|
||
// 数字转换,把传入的秒转换为HH:mm:ss格式
|
||
export const formatSeconds = (seconds) => {
|
||
// 处理非数字或负数情况
|
||
if (typeof seconds !== 'number' || isNaN(seconds) || seconds < 0) {
|
||
return '00:00:00';
|
||
}
|
||
|
||
// 计算小时、分钟和剩余秒数
|
||
const hours = Math.floor(seconds / 3600);
|
||
const minutes = Math.floor((seconds % 3600) / 60);
|
||
const remainingSeconds = Math.floor(seconds % 60);
|
||
|
||
// 补零函数:将数字转为两位数字符串
|
||
const padZero = (num) => num.toString().padStart(2, '0');
|
||
|
||
// 拼接成00:00:00格式
|
||
return `${padZero(hours)}:${padZero(minutes)}:${padZero(remainingSeconds)}`;
|
||
};
|
||
|
||
/**
|
||
* 判断当前运行平台是否匹配指定标识
|
||
* @param {string} flag - 平台标识:'IOS' 表示苹果iOS平台,'AND' 表示安卓平台
|
||
* @returns {boolean} 如果当前平台匹配指定标识返回true,否则返回false
|
||
*/
|
||
export const getPhoneEnvBool = (flag) => {
|
||
// 获取当前设备的平台信息
|
||
|
||
const {
|
||
platform
|
||
} = uni.getSystemInfoSync();
|
||
|
||
// 平台与标识的映射关系
|
||
const platformMap = {
|
||
ios: 'IOS',
|
||
android: 'AND',
|
||
};
|
||
|
||
// 根据当前平台返回匹配结果
|
||
return platformMap[platform] === flag;
|
||
};
|
||
|
||
|
||
// 将对象和字符串相互转换
|
||
export const objToJson = obj => encodeURLComponent('page_data', obj)
|
||
export const jsonToObj = () => uni.getStorageSync('page_data')
|
||
|
||
// 将对象存入缓存
|
||
export const setPageCache = (name, obj) => {
|
||
uni.setStorageSync(name, obj)
|
||
}
|
||
|
||
// 将对象取出并且删除缓存
|
||
export const getPageCache = name => {
|
||
const cache = uni.getStorageSync(name)
|
||
uni.removeStorageSync(name)
|
||
return cache
|
||
}
|
||
|
||
function setValue(key, value) {
|
||
uni.setStorageSync(key, value);
|
||
}
|
||
|
||
function getValue(key, defaultValue = null) {
|
||
return uni.getStorageSync(key) ?? defaultValue
|
||
}
|
||
|
||
function isLogin() {
|
||
return !!getToken();
|
||
}
|
||
|
||
|
||
/**
|
||
* 获取额外高度(纯函数,返回对应高度值)
|
||
* @returns {string} 最终的额外高度值(带单位)
|
||
*/
|
||
export const getExtraHeight = () => {
|
||
// 所有常量移入函数内部定义,TARGET_DEVICE_MODEL 改为数组类型
|
||
const TARGET_DEVICE_MODEL = ['XT2321-2']; // 目标设备型号数组(摩托罗拉razr 40 Ultra)
|
||
const EXTRA_HEIGHT_TARGET = '15rpx'; // 目标设备额外高度
|
||
const EXTRA_HEIGHT_DEFAULT = '2rpx'; // 默认额外高度
|
||
try {
|
||
// 1. 优先读取缓存
|
||
const cachedHeight = getValue('extra_height', '');
|
||
if (cachedHeight) {
|
||
console.log('缓存有值直接返回', cachedHeight);
|
||
return cachedHeight; // 缓存有值直接返回
|
||
}
|
||
// 2. 缓存无值时,获取设备信息
|
||
const deviceInfo = uni.getDeviceInfo();
|
||
// 校验设备信息有效性
|
||
if (!deviceInfo || !deviceInfo.deviceModel) {
|
||
throw new Error('设备信息获取失败');
|
||
}
|
||
|
||
// 3. 判断设备型号(数组包含判断,适配多型号)
|
||
const isTargetDevice = TARGET_DEVICE_MODEL.includes(deviceInfo.deviceModel);
|
||
const finalHeight = isTargetDevice ? EXTRA_HEIGHT_TARGET : EXTRA_HEIGHT_DEFAULT;
|
||
|
||
// 4. 缓存结果(后续复用)
|
||
setValue('extra_height', finalHeight);
|
||
return finalHeight; // 返回计算后的高度
|
||
|
||
} catch (error) {
|
||
// 5. 异常兜底:返回默认值并缓存
|
||
console.warn('获取/设置额外高度失败:', error.message);
|
||
setValue('extra_height', EXTRA_HEIGHT_DEFAULT);
|
||
return EXTRA_HEIGHT_DEFAULT;
|
||
}
|
||
};
|
||
|
||
|
||
|
||
|
||
// 封装键盘高度变化处理
|
||
export function setupKeyboardHeightListener(updateCallback) {
|
||
// #ifndef APP-PLUS
|
||
return () => {};
|
||
// #endif
|
||
// #ifdef APP-PLUS
|
||
// 校验回调函数类型,避免非函数传入导致报错
|
||
if (typeof updateCallback !== 'function') {
|
||
console.error('setupKeyboardHeightListener: updateCallback 必须是函数');
|
||
return () => {};
|
||
}
|
||
|
||
// 定义处理函数
|
||
const handleKeyboardHeightChange = (res) => {
|
||
// 获取系统信息
|
||
const systemInfo = uni.getSystemInfoSync();
|
||
// console.log('systemInfo', systemInfo);
|
||
// 计算安全区域底部高度
|
||
const safeAreaBottomHeight = systemInfo.screenHeight - systemInfo.safeArea.bottom;
|
||
// console.log('计算安全区域底部高度', safeAreaBottomHeight);
|
||
let keyboardHeight = res.height;
|
||
// console.log('软键盘高度', keyboardHeight);
|
||
// 仅在iOS端补偿安全区域高度
|
||
if (systemInfo.platform === 'ios') {
|
||
keyboardHeight = Math.max(0, keyboardHeight); // 避免负数
|
||
}
|
||
// console.log('keyboardHeight', keyboardHeight);
|
||
// 通过回调函数更新外部的响应式变量
|
||
updateCallback(keyboardHeight);
|
||
};
|
||
|
||
// 监听键盘高度变化
|
||
uni.onKeyboardHeightChange(handleKeyboardHeightChange);
|
||
|
||
// 返回取消监听的函数,方便组件卸载时清理
|
||
return () => {
|
||
uni.offKeyboardHeightChange(handleKeyboardHeightChange);
|
||
};
|
||
// #endif
|
||
|
||
}
|
||
|
||
let isDownloading = false
|
||
export const previewFileFnc = ({
|
||
fileId,
|
||
getFileSrc,
|
||
fileName
|
||
}) => {
|
||
let userInfo = getUserInfo()
|
||
let userParams = '/' + (userInfo?.loginName ?? '')
|
||
navigateTo('/pages/index/preview?fileId=' + fileId + '&fileApiSrc=' + getFileSrc);
|
||
// if (getPhoneEnvBool('AND')) {
|
||
// navigateTo('/pages/index/preview?fileId=' + fileId + '&fileApiSrc=' + getFileSrc);
|
||
// } else {
|
||
// if (isDownloading) return
|
||
// const base_url = get_base_url(getFileSrc);
|
||
// let fileUrl = base_url + getFileSrc + fileId + userParams;
|
||
// const localFilePath = '_doc/pdf_view/' + fileName + '.pdf';
|
||
// isDownloading = true
|
||
// downloadFileFnc(fileUrl, localFilePath).then((res) => {
|
||
// uni.openDocument({
|
||
// filePath: res,
|
||
// showMenu: true,
|
||
// success: function() {
|
||
// console.log('打开文档成功');
|
||
// }
|
||
// })
|
||
// }).finally(() => {
|
||
// setTimeout(() => {
|
||
// isDownloading = false
|
||
// }, 1000)
|
||
// });
|
||
// }
|
||
}
|
||
const downloadFileFnc = async (fileUrl, localFilePath) => {
|
||
try {
|
||
//#ifdef APP-PLUS
|
||
return new Promise((resolve, reject) => {
|
||
console.log('开始下载:', fileUrl);
|
||
const dtask = plus.downloader.createDownload(
|
||
fileUrl, {
|
||
filename: localFilePath
|
||
},
|
||
(d, status) => {
|
||
if (status === 200) {
|
||
console.log('保存路径:', d.filename);
|
||
resolve(d.filename);
|
||
} else {
|
||
console.error('文件下载失败:', status);
|
||
reject(new Error(`下载失败,状态码: ${status}`));
|
||
}
|
||
}
|
||
);
|
||
dtask.start();
|
||
});
|
||
// #endif
|
||
//#ifdef H5
|
||
return new Promise((resolve, reject) => {
|
||
resolve();
|
||
});
|
||
// #endif
|
||
} catch (error) {
|
||
console.error('创建目录失败:', error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
|
||
export default {
|
||
getPageCache,
|
||
setPageCache,
|
||
objToJson,
|
||
jsonToObj,
|
||
hideLoading,
|
||
loading,
|
||
msg,
|
||
show,
|
||
redirectTo,
|
||
navigateTo,
|
||
navigateBack,
|
||
formatDate2,
|
||
setValue,
|
||
getValue,
|
||
isLogin,
|
||
reLaunch,
|
||
switchTab,
|
||
dateToTime,
|
||
} |