|
|
@@ -0,0 +1,373 @@
|
|
|
+
|
|
|
+// 日期格式化原型扩展(单独维护)
|
|
|
+Date.prototype.Format = function (fmt) {
|
|
|
+ const o = {
|
|
|
+ "M+": this.getMonth() + 1, // 月份
|
|
|
+ "D+": this.getDate(), // 日
|
|
|
+ "h+": this.getHours(), // 小时
|
|
|
+ "m+": this.getMinutes(), // 分
|
|
|
+ "s+": this.getSeconds(), // 秒
|
|
|
+ "q+": Math.floor((this.getMonth() + 3) / 3), // 季度
|
|
|
+ "S": this.getMilliseconds() // 毫秒
|
|
|
+ };
|
|
|
+ if (/(Y+)/.test(fmt)) {
|
|
|
+ fmt = fmt.replace(
|
|
|
+ RegExp.$1,
|
|
|
+ (this.getFullYear() + "").substr(4 - RegExp.$1.length)
|
|
|
+ );
|
|
|
+ }
|
|
|
+ for (const 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;
|
|
|
+};
|
|
|
+
|
|
|
+// 路由相关工具方法
|
|
|
+const routerUtil = {
|
|
|
+ navTo(url) {
|
|
|
+ if (!url) return;
|
|
|
+ uni.navigateTo({ url });
|
|
|
+ },
|
|
|
+
|
|
|
+ switchTo(url) {
|
|
|
+ uni.switchTab({ url });
|
|
|
+ },
|
|
|
+
|
|
|
+ reLaunchTo(url) {
|
|
|
+ uni.reLaunch({ url });
|
|
|
+ },
|
|
|
+
|
|
|
+ meRouter(option) {
|
|
|
+ const type = parseInt(option.jump || 0);
|
|
|
+ switch (type) {
|
|
|
+ case 1:
|
|
|
+ this.navTo(`/pages/activity/lifeDetail?id=${option.jump_address}`);
|
|
|
+ break;
|
|
|
+ case 2:
|
|
|
+ this.navTo(`/pages/activity/newsDetail?id=${option.jump_address}`);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 图片相关工具方法
|
|
|
+const imageUtil = {
|
|
|
+ showPic(arr, index) {
|
|
|
+ uni.previewImage({
|
|
|
+ indicator: "none",
|
|
|
+ current: index,
|
|
|
+ urls: arr
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ save(imgs) {
|
|
|
+ uni.downloadFile({
|
|
|
+ url: imgs,
|
|
|
+ success: res => {
|
|
|
+ if (res.statusCode === 200) {
|
|
|
+ uni.saveImageToPhotosAlbum({
|
|
|
+ filePath: res.tempFilePath,
|
|
|
+ success: () => this.$u.toast('保存下载成功'),
|
|
|
+ fail: () => this.$u.toast('保存失败,请稍后重试')
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ this.tools.toast('下载失败');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 数据格式化工具方法
|
|
|
+const formatUtil = {
|
|
|
+ formatTime(time, pattern) {
|
|
|
+ // uview: uni.$u.date('1585926095536', 'yyyy-mm')
|
|
|
+ // 过滤器: '1585926095536' | date('yyyy-mm')
|
|
|
+ const times = time * 1000;
|
|
|
+ let d = new Date(times).Format("YYYY-MM-DD hh:mm:ss");
|
|
|
+ if (pattern) {
|
|
|
+ d = new Date(times).Format(pattern);
|
|
|
+ }
|
|
|
+ return d.toLocaleString();
|
|
|
+ },
|
|
|
+ // 格式化距离
|
|
|
+ formatDistance(value) {
|
|
|
+ if (value == null) return '-';
|
|
|
+ const numValue = parseFloat(value);
|
|
|
+ if (isNaN(numValue)) return '无效距离';
|
|
|
+
|
|
|
+ if (numValue < 0.001) return '<1m';
|
|
|
+ if (numValue < 1) return `${Math.round(numValue * 1000)}m`;
|
|
|
+
|
|
|
+ return numValue % 1 === 0
|
|
|
+ ? `${numValue}km`
|
|
|
+ : `${numValue.toFixed(2)}km`;
|
|
|
+ },
|
|
|
+ // 格式化销售数
|
|
|
+ formatSales(sales) {
|
|
|
+ if (typeof sales !== 'number' || !isFinite(sales)) return '0';
|
|
|
+ // 处理负数
|
|
|
+ sales = Math.max(0, Math.floor(sales));
|
|
|
+
|
|
|
+ if (sales < 100) return `${sales}`;
|
|
|
+ if (sales < 1000) return `${Math.floor(sales / 100) * 100}+`;
|
|
|
+ if (sales < 10000) return `${Math.floor(sales / 1000)}k+`;
|
|
|
+ return '1w+';
|
|
|
+ },
|
|
|
+ // 格式化评价星数
|
|
|
+ formatRating(val) {
|
|
|
+ if (val >= 4.5) return "超赞";
|
|
|
+ if (val >= 4.0) return "满意";
|
|
|
+ if (val >= 3.0) return "一般";
|
|
|
+ if (val >= 2.0) return "不满意";
|
|
|
+ return "非常差";
|
|
|
+ },
|
|
|
+ // 格式化数额差值
|
|
|
+ formatSubtract(num1, num2) {
|
|
|
+ const len1 = (num1.toString().split('.')[1] || '').length;
|
|
|
+ const len2 = (num2.toString().split('.')[1] || '').length;
|
|
|
+ const base = Math.pow(10, Math.max(len1, len2));
|
|
|
+ return (Math.round(num1 * base) - Math.round(num2 * base)) / base;
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+// 节流工具方法
|
|
|
+const throttleUtil = {
|
|
|
+ // 基础节流
|
|
|
+ throttle(func, wait = 500, immediate = false) {
|
|
|
+ let timeout = null;
|
|
|
+ return function (...args) {
|
|
|
+ if (timeout !== null) clearTimeout(timeout);
|
|
|
+
|
|
|
+ if (immediate) {
|
|
|
+ const callNow = !timeout;
|
|
|
+ timeout = setTimeout(() => {
|
|
|
+ timeout = null;
|
|
|
+ }, wait);
|
|
|
+ if (callNow) func && func.apply(this, args);
|
|
|
+ } else {
|
|
|
+ timeout = setTimeout(() => {
|
|
|
+ func && func.apply(this, args);
|
|
|
+ }, wait);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ },
|
|
|
+ // 高级节流(带配置项)
|
|
|
+ throttles(func, delay, options = {}) {
|
|
|
+ let lastTime = 0;
|
|
|
+ let timer = null;
|
|
|
+ const { leading = true, trailing = true } = options;
|
|
|
+
|
|
|
+ return function (...args) {
|
|
|
+ const now = Date.now();
|
|
|
+ if (!lastTime && !leading) lastTime = now;
|
|
|
+
|
|
|
+ const remaining = delay - (now - lastTime);
|
|
|
+ if (remaining <= 0) {
|
|
|
+ if (timer) {
|
|
|
+ clearTimeout(timer);
|
|
|
+ timer = null;
|
|
|
+ }
|
|
|
+ lastTime = now;
|
|
|
+ func.apply(this, args);
|
|
|
+ } else if (!timer && trailing) {
|
|
|
+ timer = setTimeout(() => {
|
|
|
+ lastTime = !leading ? 0 : Date.now();
|
|
|
+ timer = null;
|
|
|
+ func.apply(this, args);
|
|
|
+ }, remaining);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 其他工具方法
|
|
|
+const otherUtil = {
|
|
|
+ makePhoneCall(phone) {
|
|
|
+ if (phone) {
|
|
|
+ console.log(typeof phone, phone)
|
|
|
+ uni.makePhoneCall({ phoneNumber: phone });
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 以token判断是否登录
|
|
|
+ checkLogin(options = {}) {
|
|
|
+ const {
|
|
|
+ type,
|
|
|
+ modalText = '请登录账号后再操作',
|
|
|
+ } = options;
|
|
|
+
|
|
|
+ const token = uni.getStorageSync('token') || '';
|
|
|
+ const expireTime = uni.getStorageSync("expireTime");
|
|
|
+ const now = Date.now();
|
|
|
+ const isLogin = !!token && expireTime > now;
|
|
|
+
|
|
|
+ // 后退参数
|
|
|
+ let str = uni.$u.queryParams({ isBack: 1 });
|
|
|
+ // 跳转路由
|
|
|
+ let path = `/packageF/pages/login/login${str}`;
|
|
|
+ // #ifdef MP-WEIXIN
|
|
|
+ path = `/packageF/pages/login/wxLogin${str}`;
|
|
|
+ // #endif
|
|
|
+
|
|
|
+ // 未登录时,根据 type 执行对应操作
|
|
|
+ if (!isLogin) {
|
|
|
+ switch (type) {
|
|
|
+ case 'reLaunch':
|
|
|
+ uni.reLaunch({
|
|
|
+ url: path,
|
|
|
+ success: () => {
|
|
|
+ console.log('未登录,已跳转至登录页');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'navigate':
|
|
|
+ // 跳转登录页(带返回跳转,可返回原页面)
|
|
|
+ uni.navigateTo({
|
|
|
+ url: path,
|
|
|
+ success: () => {
|
|
|
+ console.log('未登录,已跳转至登录页');
|
|
|
+ }
|
|
|
+ });
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'modal':
|
|
|
+ // 弹窗提示,确认后跳转登录页
|
|
|
+ uni.showModal({
|
|
|
+ title: '温馨提示',
|
|
|
+ content: modalText,
|
|
|
+ confirmText: '前往登录',
|
|
|
+ confirmColor: '#0879FF',
|
|
|
+ success: (res) => {
|
|
|
+ if (res.confirm) {
|
|
|
+ uni.navigateTo({ url: path });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ break;
|
|
|
+
|
|
|
+ // 默认:仅返回登录状态,不执行额外操作
|
|
|
+ default:
|
|
|
+ console.log('未登录,仅返回登录状态');
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return isLogin;
|
|
|
+ },
|
|
|
+
|
|
|
+ // 获取多级对象的长链
|
|
|
+ getProp(obj, path, defaultValue = '') {
|
|
|
+ const keys = path.split('.');
|
|
|
+ let result = obj;
|
|
|
+ for (const key of keys) {
|
|
|
+ if (result && typeof result === 'object' && key in result) {
|
|
|
+ result = result[key];
|
|
|
+ } else {
|
|
|
+ return defaultValue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ },
|
|
|
+ // 获取多图拼接的值
|
|
|
+ getSplitImg(e, index = 0) {
|
|
|
+ // 先处理原始数据:若e为空,返回空数组
|
|
|
+ if (!e || typeof e !== 'string') {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 分割图片字符串为数组
|
|
|
+ const imgArr = e.split(',');
|
|
|
+
|
|
|
+ // 判断index是否为null/undefined(用户传空时),返回完整数组
|
|
|
+ if (index === null || index === undefined) {
|
|
|
+ return imgArr;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理索引:确保是整数,且在有效范围内(0 <= index < 数组长度)
|
|
|
+ const validIndex = Math.floor(Number(index)); // 转为整数(避免传入字符串/小数)
|
|
|
+ if (isNaN(validIndex) || validIndex < 0 || validIndex >= imgArr.length) {
|
|
|
+ return ''; // 索引无效时,返回空字符串(避免显示错误图片)
|
|
|
+ }
|
|
|
+
|
|
|
+ // 返回指定索引的图片URL
|
|
|
+ return imgArr[validIndex];
|
|
|
+ },
|
|
|
+ //判断是安装了支付宝
|
|
|
+ isAlipayConfig() {
|
|
|
+ const params = {
|
|
|
+ pname: 'com.eg.android.AlipayGphone',
|
|
|
+ action: 'alipay://'
|
|
|
+ };
|
|
|
+ // 判断是否安装支付宝
|
|
|
+ if (!plus.runtime.isApplicationExist(params)) {
|
|
|
+ uni.$u.toast('未检测到支付宝,请安装后重试');
|
|
|
+ return false
|
|
|
+ }else{
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ },
|
|
|
+ //判断是安装了微信
|
|
|
+ isWechatConfig() {
|
|
|
+ const params = {
|
|
|
+ pname: 'com.tencent.mm',
|
|
|
+ action: 'weixin://'
|
|
|
+ };
|
|
|
+ // 判断是否安装支付宝
|
|
|
+ if (!plus.runtime.isApplicationExist(params)) {
|
|
|
+ uni.$u.toast('未检测到微信,请安装后重试');
|
|
|
+ return false
|
|
|
+ }else{
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /*
|
|
|
+ 会员部分使用
|
|
|
+ */
|
|
|
+ // 转json
|
|
|
+ getConfigJson(item) {
|
|
|
+ // 先判断是否有值,避免null/undefined
|
|
|
+ if (!item || !item.configJson) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ // 防止JSON格式错误导致报错
|
|
|
+ try {
|
|
|
+ return JSON.parse(item.configJson);
|
|
|
+ } catch (e) {
|
|
|
+ console.error('解析configJson失败:', e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 获取 configJson 类型
|
|
|
+ getConfigType(item) {
|
|
|
+ const cfg = this.getConfigJson(item);
|
|
|
+ if (!cfg) return null;
|
|
|
+ return cfg;
|
|
|
+ },
|
|
|
+ // 安全取值,空时返回 ''
|
|
|
+ getConfigVal(item, key) {
|
|
|
+ const cfg = this.getConfigJson(item);
|
|
|
+ if (!cfg || cfg[key] == null || cfg[key] === '') return '';
|
|
|
+ return cfg[key];
|
|
|
+ },
|
|
|
+};
|
|
|
+
|
|
|
+// 组合导出
|
|
|
+export default {
|
|
|
+ ...routerUtil,
|
|
|
+ ...imageUtil,
|
|
|
+ ...formatUtil,
|
|
|
+ ...throttleUtil,
|
|
|
+ ...otherUtil,
|
|
|
+};
|