|
@@ -0,0 +1,347 @@
|
|
|
|
|
+import { Linking, Platform } from "react-native";
|
|
|
|
|
+import { showLocation } from 'react-native-map-link'
|
|
|
|
|
+import { host } from '../api/http';
|
|
|
|
|
+import apiUser from "../api/apiUser";
|
|
|
|
|
+import { getStorageSync, setStorage } from "./storage";
|
|
|
|
|
+import { PERMISSIONS } from "react-native-permissions";
|
|
|
|
|
+import app from '../../app.json';
|
|
|
|
|
+import { PageList } from "../pages/Router";
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 工具集
|
|
|
|
|
+ * @邠心vbe on 2021/04/20
|
|
|
|
|
+ */
|
|
|
|
|
+const formatNumber = (n) => {
|
|
|
|
|
+ n = n.toString()
|
|
|
|
|
+ return n[1] ? n : '0' + n
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+export default {
|
|
|
|
|
+ getDistance(dis) {
|
|
|
|
|
+ if (dis) {
|
|
|
|
|
+ if (dis > 1000) {
|
|
|
|
|
+ return Number((dis / 1000).toFixed(1)) + 'km';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return dis + 'm';
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return 'NA';
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ directMaps(lat, lng, address) {
|
|
|
|
|
+ if (isIOS) {
|
|
|
|
|
+ showLocation({
|
|
|
|
|
+ latitude: lat,
|
|
|
|
|
+ longitude: lng,
|
|
|
|
|
+ title: address,
|
|
|
|
|
+ dialogMessage: "",
|
|
|
|
|
+ googleForceLatLon: true
|
|
|
|
|
+ }).catch(erros => {
|
|
|
|
|
+ console.warn("directMaps", erros);
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ var uri = "geo:" + lat + "," + lng + "?q=" + lat + "," + lng + "(" + address + ")";
|
|
|
|
|
+ Linking.openURL(uri).catch(erros => {
|
|
|
|
|
+ console.warn("directMaps", erros);
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ getSiteInfo(obj) {
|
|
|
|
|
+ if (obj) {
|
|
|
|
|
+ const acRates = [], dcRates = [];
|
|
|
|
|
+ obj?.rates.forEach((item) => {
|
|
|
|
|
+ if (item.type?.indexOf('AC') >= 0) {
|
|
|
|
|
+ acRates.push(item)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ dcRates.push(item)
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ return {
|
|
|
|
|
+ id: obj.sitePk,
|
|
|
|
|
+ name: obj.siteName,
|
|
|
|
|
+ address: obj.siteAddress,
|
|
|
|
|
+ latitude: obj.locationLatitude,
|
|
|
|
|
+ longitude: obj.locationLongitude,
|
|
|
|
|
+ acConnector: obj.acConnector,
|
|
|
|
|
+ allConnector: obj.allConnector,
|
|
|
|
|
+ dcConnector: obj.dcConnector,
|
|
|
|
|
+ distance: this.getDistance(obj.distance),
|
|
|
|
|
+ favorite: obj.favorite,
|
|
|
|
|
+ acRates: acRates,
|
|
|
|
|
+ dcRates: dcRates,
|
|
|
|
|
+ idleFee: obj.idleDetail,
|
|
|
|
|
+ labels: obj.siteLabels,
|
|
|
|
|
+ upcoming: obj.upcoming,
|
|
|
|
|
+ rateList: obj.rates,
|
|
|
|
|
+ siteType: obj.siteType,
|
|
|
|
|
+ parkingFee: obj.parkingFee,
|
|
|
|
|
+ hasDiscount: obj.hasDiscount,
|
|
|
|
|
+ parkingFeeFree: obj.free,
|
|
|
|
|
+ operatingHours: obj.operatingHours,
|
|
|
|
|
+ additionalNotes: obj.additionalNotes,
|
|
|
|
|
+ endlessService: obj.endlessService,
|
|
|
|
|
+ serviceProvider: obj.serviceProvider,
|
|
|
|
|
+ enableReservation: obj.enableReservation,
|
|
|
|
|
+ payPerUseAmount: obj.payPerUseAmount
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return {id: 0}
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ getNowHHmm() {
|
|
|
|
|
+ const now = new Date();
|
|
|
|
|
+ var month = now.getHours();
|
|
|
|
|
+ var minute = now.getMinutes();
|
|
|
|
|
+ return [month, minute].map(formatNumber).join(':');
|
|
|
|
|
+ },
|
|
|
|
|
+ getYYMMdd(date) {
|
|
|
|
|
+ var year = date.getFullYear()
|
|
|
|
|
+ var month = date.getMonth() + 1
|
|
|
|
|
+ var day = date.getDate()
|
|
|
|
|
+
|
|
|
|
|
+ //var hour = date.getHours()
|
|
|
|
|
+ //var minute = date.getMinutes()
|
|
|
|
|
+ //var second = date.getSeconds()
|
|
|
|
|
+
|
|
|
|
|
+ return [year, month, day].map(formatNumber).join('/')
|
|
|
|
|
+ },
|
|
|
|
|
+ formatYYMM(date) {
|
|
|
|
|
+ var year = date.getFullYear()
|
|
|
|
|
+ var month = date.getMonth() + 1
|
|
|
|
|
+ return [year, month].map(formatNumber).join('-')
|
|
|
|
|
+ },
|
|
|
|
|
+ hour2HHmm(hour) {
|
|
|
|
|
+ if (hour) {
|
|
|
|
|
+ if (hour > 0) {
|
|
|
|
|
+ const h = parseInt(hour);
|
|
|
|
|
+ const m = (hour - h) * 60;
|
|
|
|
|
+ return h + ' hr ' + parseInt(m) + 'min';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ const m = hour * 60;
|
|
|
|
|
+ return parseInt(m) + 'min';
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return '0 min';
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ minutes2HHmm(minutes) {
|
|
|
|
|
+ if (minutes) {
|
|
|
|
|
+ const m = Number(minutes);
|
|
|
|
|
+ if (m > 60) {
|
|
|
|
|
+ const h = m / 60;
|
|
|
|
|
+ const mm = m % 60;
|
|
|
|
|
+ return parseInt(h) + ' hr ' + parseInt(mm) + ' min';
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return parseInt(minutes) + ' min';
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return '0 min';
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ minutes2HHMM(minutes) {
|
|
|
|
|
+ if (minutes) {
|
|
|
|
|
+ const m = Number(minutes);
|
|
|
|
|
+ if (m > 60) {
|
|
|
|
|
+ const h = m / 60;
|
|
|
|
|
+ const mm = m % 60;
|
|
|
|
|
+ if (h >= 24) {
|
|
|
|
|
+ const hh = h % 24;
|
|
|
|
|
+ const d = h / 24;
|
|
|
|
|
+ return parseInt(d) + "d " + formatNumber(parseInt(hh)) + ':' + formatNumber(parseInt(mm));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return formatNumber(parseInt(h)) + ':' + formatNumber(parseInt(mm));
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return '00:' + formatNumber(parseInt(minutes));
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return '00:00';
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 判断指定对象是否为空
|
|
|
|
|
+ * @param {*} str 判定对象(字符串、数字、JSON)
|
|
|
|
|
+ * @param {Boolean} encNo 是否判定数字(为true则数字0判定为空)
|
|
|
|
|
+ */
|
|
|
|
|
+ isEmpty(str, encNo=false) {
|
|
|
|
|
+ if (typeof str == 'number') {
|
|
|
|
|
+ if (encNo) {
|
|
|
|
|
+ return str === 0;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (str) {
|
|
|
|
|
+ if (typeof str == 'object') {
|
|
|
|
|
+ return Object.keys(str).length == 0;
|
|
|
|
|
+ } else if (Array.isArray(str)) {
|
|
|
|
|
+ return str.length == 0;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (str == undefined || str == null || str == "")
|
|
|
|
|
+ return true;
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ isNotEmpty(str, encNo) {
|
|
|
|
|
+ return !this.isEmpty(str, encNo);
|
|
|
|
|
+ },
|
|
|
|
|
+ getParamsFromUrl(url) {
|
|
|
|
|
+ var params = {}
|
|
|
|
|
+ const list = url.split('&');
|
|
|
|
|
+ for (let item of list) {
|
|
|
|
|
+ if (item.indexOf('=') > 0) {
|
|
|
|
|
+ const param = item.split('=');
|
|
|
|
|
+ if (param.length == 2)
|
|
|
|
|
+ params[param[0]] = param[1];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return params;
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将数组以指定分隔符组装为字符串
|
|
|
|
|
+ * @param {Array} arrays 源数组
|
|
|
|
|
+ * @param {String} spect 分隔符
|
|
|
|
|
+ */
|
|
|
|
|
+ join(arrays=[], spect="") {
|
|
|
|
|
+ let str = ''
|
|
|
|
|
+ if (arrays) {
|
|
|
|
|
+ arrays.forEach((item, index) => {
|
|
|
|
|
+ if (index == 0) {
|
|
|
|
|
+ str += item;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ str += spect + item;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ return str;
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将给定数字保留任意位小数
|
|
|
|
|
+ * @param {number} text 源数字
|
|
|
|
|
+ * @param {number} scape 小数位
|
|
|
|
|
+ * @returns 小数
|
|
|
|
|
+ */
|
|
|
|
|
+ toFixed(text, scape) {
|
|
|
|
|
+ if (text) {
|
|
|
|
|
+ return Number(Number(text).toFixed(scape));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return text;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 16进制颜色转为RGB
|
|
|
|
|
+ * @param {*} value 16进制颜色
|
|
|
|
|
+ * @returns {Array} RGB数据
|
|
|
|
|
+ */
|
|
|
|
|
+ hexColorToRgb(value) {
|
|
|
|
|
+ let sColor = value.toLowerCase()
|
|
|
|
|
+ if (sColor && sColor.indexOf("#") >= 0) {
|
|
|
|
|
+ if (sColor.length === 4) {
|
|
|
|
|
+ let sColorNew = '#'
|
|
|
|
|
+ for (let i = 1; i < 4; i += 1) {
|
|
|
|
|
+ sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
|
|
|
|
|
+ }
|
|
|
|
|
+ sColor = sColorNew
|
|
|
|
|
+ }
|
|
|
|
|
+ // 处理1+6位的颜色值
|
|
|
|
|
+ let sColorChange = []
|
|
|
|
|
+ for (let i = 1; i < 7; i += 2) {
|
|
|
|
|
+ sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
|
|
|
|
|
+ }
|
|
|
|
|
+ return sColorChange;//'rgb(' + sColorChange.join(',') + ')'
|
|
|
|
|
+ } else if (sColor && sColor.indexOf("0x") >= 0) {
|
|
|
|
|
+ if (sColor.length === 4) {
|
|
|
|
|
+ let sColorNew = '0x'
|
|
|
|
|
+ for (let i = 1; i < 4; i += 1) {
|
|
|
|
|
+ sColorNew += sColor.slice(i, i + 1).concat(sColor.slice(i, i + 1))
|
|
|
|
|
+ }
|
|
|
|
|
+ sColor = sColorNew
|
|
|
|
|
+ }
|
|
|
|
|
+ // 处理2+6位的颜色值
|
|
|
|
|
+ let sColorChange = []
|
|
|
|
|
+ for (let i = 2; i < 8; i += 2) {
|
|
|
|
|
+ sColorChange.push(parseInt('0x' + sColor.slice(i, i + 2)))
|
|
|
|
|
+ }
|
|
|
|
|
+ return sColorChange;//'rgb(' + sColorChange.join(',') + ')'
|
|
|
|
|
+ }
|
|
|
|
|
+ return sColor
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 给颜色值添加透明度
|
|
|
|
|
+ * @param {Array} colors 10进制颜色
|
|
|
|
|
+ * @param {Number} alpha 透明度(0-1)
|
|
|
|
|
+ */
|
|
|
|
|
+ getRgbaColor(colors, alpha=1) {
|
|
|
|
|
+ if (colors.length == 3) {
|
|
|
|
|
+ return "rgba(" + this.join(colors, ",") + "," +alpha + ")";
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 注册FCM通知token
|
|
|
|
|
+ * @param {String} token 原始保存的Firebase令牌
|
|
|
|
|
+ * @param {Function} back 执行结果(boolean)
|
|
|
|
|
+ */
|
|
|
|
|
+ async registerFirebaseToken(token, back) {
|
|
|
|
|
+ const thisDate = this.formatYYMM(new Date()) + "-" + getUserId();
|
|
|
|
|
+ const lastDate = await getStorageSync('RegisterTokenDate');
|
|
|
|
|
+ console.log('>>>RegisterToken<<<', thisDate, lastDate + "●");
|
|
|
|
|
+ if (thisDate != lastDate || token != notifyToken.token) {
|
|
|
|
|
+ const params = {
|
|
|
|
|
+ os: isIOS ? "ios": "android",
|
|
|
|
|
+ googleToken: notifyToken.token
|
|
|
|
|
+ }
|
|
|
|
|
+ apiUser.setNotifyToken(params).then(res => {
|
|
|
|
|
+ console.log('>>>RegisterToken-Suc<<<', res);
|
|
|
|
|
+ setStorage('RegisterTokenDate', thisDate);
|
|
|
|
|
+ if (back) back(true);
|
|
|
|
|
+ }).catch(err => {
|
|
|
|
|
+ console.log('>>>RegisterToken-Err<<<', err);
|
|
|
|
|
+ if (back) back(false);
|
|
|
|
|
+ });
|
|
|
|
|
+ } else {
|
|
|
|
|
+ if (back) back(false);
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ setBackClick(routeNames, func) {
|
|
|
|
|
+ global.pageBackFallback = {
|
|
|
|
|
+ names: routeNames,
|
|
|
|
|
+ callback: func
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ getImageUrl(path) {
|
|
|
|
|
+ if (path && path.indexOf("http") >= 0) {
|
|
|
|
|
+ return path;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return host + path;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ getFilePermissionString() {
|
|
|
|
|
+ if (Platform.Version >= 33) {
|
|
|
|
|
+ return PERMISSIONS.ANDROID.READ_MEDIA_IMAGES;
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return PERMISSIONS.ANDROID.WRITE_EXTERNAL_STORAGE;
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ toChargeDetailPage(sitePk, action, form) {
|
|
|
|
|
+ if (app.charge.version == 1) {
|
|
|
|
|
+ startPage(PageList.chargeDetail, { stationInfo: {id: sitePk}, action: action, from: form});
|
|
|
|
|
+ } else {
|
|
|
|
|
+ startPage(PageList.chargeDetailPage, {stationInfo: {id: sitePk}, action: action, from: form});
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ toChargingPage(connectorInfo) {
|
|
|
|
|
+ startPage(app.charge.version == 4 ? PageList.chargingPageV4 : PageList.chargingPage, connectorInfo);
|
|
|
|
|
+ },
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 校验邮箱是否合法
|
|
|
|
|
+ * @param {String} email 邮箱地址
|
|
|
|
|
+ * @returns {Boolean}
|
|
|
|
|
+ */
|
|
|
|
|
+ isValidEmail(email) {
|
|
|
|
|
+ const pattern = /^[a-zA-Z0-9]+[\S]*@[a-zA-Z0-9_-]+[\.][\Sa-zA-Z]+$/
|
|
|
|
|
+ return pattern.test(email)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|