import {img_domian} from "./config"; import marketApi from '@/api/apiRoute.js'; function formatTime(time) { if (typeof time !== 'number' || time < 0) { return time } var hour = parseInt(time / 3600) time = time % 3600 var minute = parseInt(time / 60) time = time % 60 var second = time return ([hour, minute, second]).map(function(n) { n = n.toString() return n[1] ? n : '0' + n }).join(':') } function formatDateTime(date, fmt = 'yyyy-MM-dd hh:mm:ss') { if(!date) { return '' } if (typeof (date) === 'number') { date = new Date(date * 1000) } var o = { "M+": date.getMonth() + 1, //月份 "d+": date.getDate(), //日 "h+": date.getHours(), //小时 "m+": date.getMinutes(), //分 "s+": date.getSeconds(), //秒 "q+": Math.floor((date.getMonth() + 3) / 3), //季度 "S": date.getMilliseconds() //毫秒 } if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length)) for (var k in o) if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length))) return fmt } function formatLocation(longitude, latitude) { if (typeof longitude === 'string' && typeof latitude === 'string') { longitude = parseFloat(longitude) latitude = parseFloat(latitude) } longitude = longitude.toFixed(2) latitude = latitude.toFixed(2) return { longitude: longitude.toString().split('.'), latitude: latitude.toString().split('.') } } var dateUtils = { UNITS: { '年': 31557600000, '月': 2629800000, '天': 86400000, '小时': 3600000, '分钟': 60000, '秒': 1000 }, humanize: function(milliseconds) { var humanize = ''; for (var key in this.UNITS) { if (milliseconds >= this.UNITS[key]) { humanize = Math.floor(milliseconds / this.UNITS[key]) + key + '前'; break; } } return humanize || '刚刚'; }, format: function(dateStr) { var date = this.parse(dateStr) var diff = Date.now() - date.getTime(); if (diff < this.UNITS['天']) { return this.humanize(diff); } var _format = function(number) { return (number < 10 ? ('0' + number) : number); }; return date.getFullYear() + '/' + _format(date.getMonth() + 1) + '/' + _format(date.getDate()) + '-' + _format(date.getHours()) + ':' + _format(date.getMinutes()); }, parse: function(str) { //将"yyyy-mm-dd HH:MM:ss"格式的字符串,转化为一个Date对象 var a = str.split(/[^0-9]/); return new Date(a[0], a[1] - 1, a[2], a[3], a[4], a[5]); } }; const hexToRgba = (hex, opacity) => { //16进制颜色转rgba return "rgba(" + parseInt("0x" + hex.slice(1, 3)) + "," + parseInt("0x" + hex.slice(3, 5)) + "," + parseInt("0x" + hex.slice(5, 7)) + "," + opacity + ")" } /** * 图片路径转换 * @param {String} img_path 图片地址 * @param {Object} params 参数,针对商品、相册里面的图片区分大中小,size: big、mid、small */ function img(img_path, params) { var path = ""; if (img_path != undefined && img_path != "") { if (img_path.split(',').length > 1) { img_path = img_path.split(',')[0]; } if (params && img_path != getDefaultImage().goods) { // 过滤默认图 let arr = img_path.split("."); let suffix = arr[arr.length - 1]; arr.pop(); arr[arr.length - 1] = arr[arr.length - 1] + "_" + params.size.toUpperCase(); arr.push(suffix); img_path = arr.join("."); } if (img_path.indexOf("http://") == -1 && img_path.indexOf("https://") == -1) { path = img_domian + "/" + img_path; } else { path = img_path; } if(img_domian.indexOf('https://') != -1){ path = path.replace('http://', 'https://'); } } // path += '?t=' + parseInt(new Date().getTime() / 1000); return path; } /** * 获取默认图 */ function getDefaultImage() { let defaultImg = store.state.defaultImg; defaultImg.goods = img(defaultImg.goods); defaultImg.head = img(defaultImg.head); defaultImg.store = img(defaultImg.store); defaultImg.article = img(defaultImg.article); return defaultImg; } /** * 时间格式转换 * @param dateTime 如 2024-05-01 01:10:21 * @param fmt 可选参数[Y-m-d H:i:s,Y-m-d,Y-m-d H,Y-m-d H:i,H:i:s,H:i] * @returns {string} */ function formatToDateTime(dateTime, fmt = 'Y-m-d H:i:s') { if (!dateTime) return ''; // 如果为空,返回空字符串 const date = new Date(dateTime); // 将字符串转换为 Date 对象 // 定义格式化规则 const o = { 'Y+': date.getFullYear(), // 年 'm+': String(date.getMonth() + 1).padStart(2, '0'), // 月 'd+': String(date.getDate()).padStart(2, '0'), // 日 'H+': String(date.getHours()).padStart(2, '0'), // 小时 'i+': String(date.getMinutes()).padStart(2, '0'), // 分钟 's+': String(date.getSeconds()).padStart(2, '0'), // 秒 }; // 替换格式模板中的占位符 for (const k in o) { if (new RegExp(`(${k})`).test(fmt)) { fmt = fmt.replace(RegExp.$1, o[k]); } } return fmt; } //跳转首页 function openHomeView() { //获取用户类型缓存 let userType = uni.getStorageSync('userType') let url_path = '' switch (String(userType)) { case '1': //教练 url_path = '/pages/coach/home/index' break; case '2': //销售 url_path = '/pages/market/index/index' break; case '3': //学员 url_path = '/pages/student/index/index' break; default: uni.showToast({ title: '用户类型错误', icon: 'none' }) url_path = '/pages/student/login/login' return; } uni.navigateTo({ url: url_path }) } //退出登陆-清空缓存数据 function loginOut() { //清除token uni.removeStorageSync('token') //清除用户信息 uni.removeStorageSync('userInfo') //清除用户类型 uni.removeStorageSync('userType') //清除用户角色 uni.removeStorageSync('userRoles') //清除过期时间 uni.removeStorageSync('expires_time') //底部菜单选中 uni.removeStorageSync('tabBerIndex') // 重置Vuex中的用户信息和登录状态 // 注意:在非组件环境中无法直接访问store,需要在组件中调用 // 这里不做store的更新,而是在组件中使用时更新 // 直接跳转到登录页,不显示任何提示信息 uni.reLaunch({ url: '/pages/student/login/login' }) } // 全局内存字典缓存 // 使用模块级的变量保存缓存,在整个应用生命周期内都有效 const dictMemoryCache = {}; /** * 获取字典值,带内存和存储双重缓存 * @param {String} dictKey 字典key * @returns {Promise} */ async function getDict(dictKey) { console.log(`getDict - 开始获取字典: ${dictKey}`); // 先从内存缓存中获取 const now = Date.now(); if (dictMemoryCache[dictKey] && dictMemoryCache[dictKey].expire > now) { console.log(`getDict - 使用内存缓存: ${dictKey}`); return dictMemoryCache[dictKey].data; } // 内存缓存不存在或已过期,尝试从存储中获取 const cacheKey = `dict_${dictKey}`; try { const storageCache = uni.getStorageSync(cacheKey); if (storageCache && storageCache.data && storageCache.expire > now) { console.log(`getDict - 使用存储缓存: ${dictKey}`); // 更新内存缓存 dictMemoryCache[dictKey] = storageCache; return storageCache.data; } } catch (e) { console.error(`getDict - 读取存储缓存异常: ${dictKey}`, e); } console.log(`getDict - 缓存无效,请求接口: ${dictKey}`); // 缓存不存在或已过期,从服务器获取 try { // 添加超时处理和重试机制 let retryCount = 0; const maxRetries = 2; const fetchWithRetry = async () => { try { // 超时控制 const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error(`字典请求超时: ${dictKey}`)), 3000); }); // 实际API请求 const apiPromise = marketApi.common_Dictionary({ key: dictKey }); // 使用Promise.race来实现超时控制 return await Promise.race([apiPromise, timeoutPromise]); } catch (error) { if (retryCount < maxRetries) { retryCount++; console.log(`getDict - 重试第${retryCount}次: ${dictKey}`); return await fetchWithRetry(); } throw error; } }; const res = await fetchWithRetry(); if (res && res.code === 1) { // 处理接口返回的数据 const formattedData = Array.isArray(res.data) ? res.data : []; if (formattedData.length > 0) { // 设置缓存过期时间,默认1小时 const cacheData = { data: formattedData, expire: now + 3600 * 1000 }; // 同时更新内存缓存和存储缓存 dictMemoryCache[dictKey] = cacheData; try { uni.setStorageSync(cacheKey, cacheData); } catch (e) { console.error(`getDict - 存储缓存异常: ${dictKey}`, e); } console.log(`getDict - 字典获取成功: ${dictKey}, 条数: ${formattedData.length}`); } else { console.warn(`getDict - 字典数据为空: ${dictKey}`); } return formattedData; } else { console.error(`getDict - API请求失败: ${dictKey}`, res); return []; } } catch (error) { console.error(`getDict - 异常: ${dictKey}`, error); return []; } } module.exports = { loginOut, openHomeView, formatTime, formatDateTime, formatLocation, dateUtils, hexToRgba, img, formatToDateTime, getDict }