Initial Commit
This commit is contained in:
commit
1d71a02738
237 changed files with 64293 additions and 0 deletions
365
utils/ui-helper.js
Normal file
365
utils/ui-helper.js
Normal file
|
|
@ -0,0 +1,365 @@
|
|||
// UI辅助工具 - 全局用户体验优化
|
||||
class UIHelper {
|
||||
constructor() {
|
||||
this.loadingCount = 0;
|
||||
this.toastQueue = [];
|
||||
this.isShowingToast = false;
|
||||
}
|
||||
|
||||
// 🔥 ===== 加载状态管理 =====
|
||||
|
||||
// 显示加载
|
||||
showLoading(title = '加载中...', mask = true) {
|
||||
this.loadingCount++;
|
||||
|
||||
if (this.loadingCount === 1) {
|
||||
wx.showLoading({
|
||||
title: title,
|
||||
mask: mask
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 隐藏加载
|
||||
hideLoading() {
|
||||
this.loadingCount = Math.max(0, this.loadingCount - 1);
|
||||
|
||||
if (this.loadingCount === 0) {
|
||||
wx.hideLoading();
|
||||
}
|
||||
}
|
||||
|
||||
// 强制隐藏加载
|
||||
forceHideLoading() {
|
||||
this.loadingCount = 0;
|
||||
wx.hideLoading();
|
||||
}
|
||||
|
||||
// 🔥 ===== 消息提示管理 =====
|
||||
|
||||
// 显示成功消息
|
||||
showSuccess(title, duration = 2000) {
|
||||
this.showToast({
|
||||
title: title,
|
||||
icon: 'success',
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
|
||||
// 显示错误消息
|
||||
showError(title, duration = 3000) {
|
||||
this.showToast({
|
||||
title: title,
|
||||
icon: 'error',
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
|
||||
// 显示警告消息
|
||||
showWarning(title, duration = 2500) {
|
||||
this.showToast({
|
||||
title: title,
|
||||
icon: 'none',
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
|
||||
// 显示信息消息
|
||||
showInfo(title, duration = 2000) {
|
||||
this.showToast({
|
||||
title: title,
|
||||
icon: 'none',
|
||||
duration: duration
|
||||
});
|
||||
}
|
||||
|
||||
// 队列化Toast显示
|
||||
showToast(options) {
|
||||
this.toastQueue.push(options);
|
||||
this.processToastQueue();
|
||||
}
|
||||
|
||||
// 处理Toast队列
|
||||
processToastQueue() {
|
||||
if (this.isShowingToast || this.toastQueue.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isShowingToast = true;
|
||||
const options = this.toastQueue.shift();
|
||||
|
||||
wx.showToast({
|
||||
...options,
|
||||
success: () => {
|
||||
setTimeout(() => {
|
||||
this.isShowingToast = false;
|
||||
this.processToastQueue();
|
||||
}, options.duration || 2000);
|
||||
},
|
||||
fail: () => {
|
||||
this.isShowingToast = false;
|
||||
this.processToastQueue();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 🔥 ===== 模态框管理 =====
|
||||
|
||||
// 显示确认对话框
|
||||
showConfirm(options) {
|
||||
return new Promise((resolve) => {
|
||||
wx.showModal({
|
||||
title: options.title || '提示',
|
||||
content: options.content || '',
|
||||
showCancel: options.showCancel !== false,
|
||||
cancelText: options.cancelText || '取消',
|
||||
confirmText: options.confirmText || '确定',
|
||||
cancelColor: options.cancelColor || '#666666',
|
||||
confirmColor: options.confirmColor || '#4CAF50',
|
||||
success: (res) => {
|
||||
resolve(res.confirm);
|
||||
},
|
||||
fail: () => {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 显示操作菜单
|
||||
showActionSheet(options) {
|
||||
return new Promise((resolve) => {
|
||||
wx.showActionSheet({
|
||||
itemList: options.itemList || [],
|
||||
itemColor: options.itemColor || '#000000',
|
||||
success: (res) => {
|
||||
resolve(res.tapIndex);
|
||||
},
|
||||
fail: () => {
|
||||
resolve(-1);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 🔥 ===== 网络状态管理 =====
|
||||
|
||||
// 检查网络状态
|
||||
async checkNetworkStatus() {
|
||||
try {
|
||||
const networkInfo = await this.getNetworkType();
|
||||
|
||||
if (networkInfo.networkType === 'none') {
|
||||
this.showError('网络连接不可用,请检查网络设置');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('检查网络状态失败:', error);
|
||||
return true; // 默认认为网络可用
|
||||
}
|
||||
}
|
||||
|
||||
// 获取网络类型
|
||||
getNetworkType() {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.getNetworkType({
|
||||
success: resolve,
|
||||
fail: reject
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 🔥 ===== 页面导航管理 =====
|
||||
|
||||
// 安全导航到页面
|
||||
navigateTo(url, options = {}) {
|
||||
// 检查URL格式
|
||||
if (!url || typeof url !== 'string') {
|
||||
this.showError('页面地址无效');
|
||||
return Promise.reject(new Error('Invalid URL'));
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.navigateTo({
|
||||
url: url,
|
||||
success: resolve,
|
||||
fail: (error) => {
|
||||
console.error('页面导航失败:', error);
|
||||
|
||||
// 如果是页面栈满了,尝试重定向
|
||||
if (error.errMsg && error.errMsg.includes('limit exceed')) {
|
||||
wx.redirectTo({
|
||||
url: url,
|
||||
success: resolve,
|
||||
fail: reject
|
||||
});
|
||||
} else {
|
||||
this.showError('页面跳转失败');
|
||||
reject(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 安全重定向到页面
|
||||
redirectTo(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.redirectTo({
|
||||
url: url,
|
||||
success: resolve,
|
||||
fail: (error) => {
|
||||
console.error('页面重定向失败:', error);
|
||||
this.showError('页面跳转失败');
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 安全重启到页面
|
||||
reLaunch(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.reLaunch({
|
||||
url: url,
|
||||
success: resolve,
|
||||
fail: (error) => {
|
||||
console.error('页面重启失败:', error);
|
||||
this.showError('页面跳转失败');
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 🔥 ===== 错误处理 =====
|
||||
|
||||
// 处理API错误
|
||||
handleApiError(error, defaultMessage = '操作失败,请重试') {
|
||||
console.error('API错误:', error);
|
||||
|
||||
let message = defaultMessage;
|
||||
|
||||
if (error && error.message) {
|
||||
message = error.message;
|
||||
} else if (typeof error === 'string') {
|
||||
message = error;
|
||||
}
|
||||
|
||||
// 特殊错误处理
|
||||
if (message.includes('网络')) {
|
||||
this.showError('网络连接异常,请检查网络设置');
|
||||
} else if (message.includes('登录') || message.includes('认证') || message.includes('token')) {
|
||||
this.showError('登录已过期,请重新登录');
|
||||
// 可以在这里触发重新登录逻辑
|
||||
} else {
|
||||
this.showError(message);
|
||||
}
|
||||
}
|
||||
|
||||
// 🔥 ===== 工具方法 =====
|
||||
|
||||
// 防抖函数
|
||||
debounce(func, wait) {
|
||||
let timeout;
|
||||
return function executedFunction(...args) {
|
||||
const later = () => {
|
||||
clearTimeout(timeout);
|
||||
func(...args);
|
||||
};
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
};
|
||||
}
|
||||
|
||||
// 节流函数
|
||||
throttle(func, limit) {
|
||||
let inThrottle;
|
||||
return function executedFunction(...args) {
|
||||
if (!inThrottle) {
|
||||
func.apply(this, args);
|
||||
inThrottle = true;
|
||||
setTimeout(() => inThrottle = false, limit);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 格式化文件大小
|
||||
formatFileSize(bytes) {
|
||||
if (bytes === 0) return '0 B';
|
||||
|
||||
const k = 1024;
|
||||
const sizes = ['B', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
// 格式化时间
|
||||
formatTime(timestamp) {
|
||||
const now = new Date();
|
||||
const time = new Date(timestamp);
|
||||
const diff = now - time;
|
||||
|
||||
// 一分钟内
|
||||
if (diff < 60000) {
|
||||
return '刚刚';
|
||||
}
|
||||
|
||||
// 一小时内
|
||||
if (diff < 3600000) {
|
||||
return Math.floor(diff / 60000) + '分钟前';
|
||||
}
|
||||
|
||||
// 今天
|
||||
if (now.toDateString() === time.toDateString()) {
|
||||
return time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
|
||||
// 昨天
|
||||
const yesterday = new Date(now);
|
||||
yesterday.setDate(yesterday.getDate() - 1);
|
||||
if (yesterday.toDateString() === time.toDateString()) {
|
||||
return '昨天 ' + time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
|
||||
// 其他
|
||||
return time.toLocaleDateString('zh-CN') + ' ' + time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });
|
||||
}
|
||||
|
||||
// 复制到剪贴板
|
||||
copyToClipboard(text) {
|
||||
return new Promise((resolve, reject) => {
|
||||
wx.setClipboardData({
|
||||
data: text,
|
||||
success: () => {
|
||||
this.showSuccess('已复制到剪贴板');
|
||||
resolve();
|
||||
},
|
||||
fail: (error) => {
|
||||
this.showError('复制失败');
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 震动反馈
|
||||
vibrateShort() {
|
||||
wx.vibrateShort({
|
||||
type: 'light'
|
||||
});
|
||||
}
|
||||
|
||||
// 震动反馈(长)
|
||||
vibrateLong() {
|
||||
wx.vibrateLong();
|
||||
}
|
||||
}
|
||||
|
||||
// 创建全局单例
|
||||
const uiHelper = new UIHelper();
|
||||
|
||||
module.exports = uiHelper;
|
||||
Loading…
Add table
Add a link
Reference in a new issue