first commit
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
import type {CustomRequestOptions} from '@/interceptor/request'
|
||||
import {useConfigStore, useUserStore} from '@/store'
|
||||
import Config from '@/config'
|
||||
import {i18n} from "@/locale";
|
||||
|
||||
type IRes<T> = T extends ArrayBuffer ? ArrayBuffer : IResData<T>
|
||||
|
||||
|
||||
export const http = <T>(options: CustomRequestOptions) => {
|
||||
console.log(options, 'options')
|
||||
// 1. 返回 Promise 对象
|
||||
return new Promise<IRes<T>>((resolve, reject) => {
|
||||
uni.request({
|
||||
...options,
|
||||
dataType: 'json',
|
||||
// 响应成功
|
||||
success(res) {
|
||||
console.log(res, '111111')
|
||||
|
||||
const ErrorMessage = {
|
||||
401: i18n.global.t('common.prompt.authentication-failed-please-log-in'),
|
||||
700: i18n.global.t('common.prompt.login-expired-please-log-in-again'),
|
||||
}
|
||||
const configStore = useConfigStore()
|
||||
const userStore = useUserStore()
|
||||
const data = res.data as IRes<T>
|
||||
|
||||
if (!(data instanceof ArrayBuffer) && data.systemTime) {
|
||||
// @ts-ignore
|
||||
configStore.serverTime = +data.systemTime
|
||||
}
|
||||
if (data instanceof ArrayBuffer || data.code === 200) {
|
||||
resolve(data)
|
||||
} else if (data.code === 401 || data.code === 700) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: ErrorMessage[data.code],
|
||||
})
|
||||
|
||||
userStore?.clear?.()
|
||||
uni.navigateTo({url: Config.loginPath})
|
||||
reject(data)
|
||||
} else if (data.code === 711) {
|
||||
reject(data)
|
||||
} else {
|
||||
// 其他错误 -> 根据后端错误信息轻提示
|
||||
!options.hideErrorToast &&
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: (res.data as IResData<T>).msg || i18n.global.t('common.prompt.request-incorrect'),
|
||||
})
|
||||
reject(data)
|
||||
}
|
||||
},
|
||||
// 响应失败
|
||||
fail(err) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: i18n.global.t('common.prompt.request-failed-please-try-again-later'),
|
||||
})
|
||||
reject(err)
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* GET 请求
|
||||
* @param url 后台地址
|
||||
* @param query 请求query参数
|
||||
* @param responseType
|
||||
* @returns
|
||||
*/
|
||||
export const httpGet = <T>(url: string, query?: Record<string, any>, responseType: 'text' | 'arraybuffer' = 'text') => {
|
||||
return http<T>({
|
||||
url,
|
||||
query,
|
||||
responseType,
|
||||
method: 'GET',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* DELETE 请求
|
||||
* @param url 后台地址
|
||||
* @param query 请求query参数
|
||||
* @param data 请求body参数
|
||||
* @param responseType
|
||||
* @returns
|
||||
*/
|
||||
export const httpDelete = <T>(
|
||||
url: string,
|
||||
query?: Record<string, any>,
|
||||
data?: Record<string, any>,
|
||||
responseType: 'text' | 'arraybuffer' = 'text',
|
||||
) => {
|
||||
return http<T>({
|
||||
url,
|
||||
query,
|
||||
data,
|
||||
responseType,
|
||||
method: 'DELETE',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* POST 请求
|
||||
* @param url 后台地址
|
||||
* @param data 请求body参数
|
||||
* @param query 请求query参数,post请求也支持query,很多微信接口都需要
|
||||
* @param responseType 数据响应格式
|
||||
* @returns
|
||||
*/
|
||||
export const httpPost = <T>(
|
||||
url: string,
|
||||
data?: Record<string, any> | string,
|
||||
query?: Record<string, any>,
|
||||
responseType: 'text' | 'arraybuffer' = 'text',
|
||||
) => {
|
||||
return http<T>({
|
||||
url,
|
||||
query,
|
||||
data,
|
||||
responseType,
|
||||
method: 'POST',
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* PUT 请求
|
||||
* @param url 后台地址
|
||||
* @param data 请求body参数
|
||||
* @param query 请求query参数,post请求也支持query,很多微信接口都需要
|
||||
* @param responseType 数据响应格式
|
||||
* @returns
|
||||
*/
|
||||
export const httpPut = <T>(
|
||||
url: string,
|
||||
data?: Record<string, any> | string,
|
||||
query?: Record<string, any>,
|
||||
responseType: 'text' | 'arraybuffer' = 'text',
|
||||
) => {
|
||||
return http<T>({
|
||||
url,
|
||||
query,
|
||||
data,
|
||||
responseType,
|
||||
method: 'PUT',
|
||||
})
|
||||
}
|
||||
|
||||
http.get = httpGet
|
||||
http.post = httpPost
|
||||
http.put = httpPut
|
||||
http.delete = httpDelete
|
||||
@@ -0,0 +1,59 @@
|
||||
import {dayjs} from '@/plugin/index'
|
||||
import * as R from 'ramda'
|
||||
|
||||
// 店铺营业时间格式化
|
||||
export function businessTimeFormat(weekNums: string, timePeriod: string) {
|
||||
if (!weekNums || !timePeriod) {
|
||||
return ''
|
||||
}
|
||||
if (!weekNums.length || !timePeriod.length) {
|
||||
return ''
|
||||
}
|
||||
let timeString = ''
|
||||
const weeks: string[] = dayjs.weekdays()
|
||||
console.log('weeks', weeks)
|
||||
const weekNumsArr = R.map(item => +item, R.split(',', R.trim(weekNums || '')))
|
||||
const groupWeek = R.groupWith((a, b) => +a + 1 === +b, weekNumsArr)
|
||||
console.log('weekNums', groupWeek)
|
||||
R.forEach((weekNumsArr) => {
|
||||
if (R.gt(weekNumsArr.length, 1)) {
|
||||
timeString += `${weeks[weekNumsArr[0] - 1]}-${weeks[weekNumsArr[weekNumsArr.length - 1] - 1]} `
|
||||
} else {
|
||||
timeString += `${weeks[weekNumsArr[0] - 1]} `
|
||||
}
|
||||
}, groupWeek)
|
||||
|
||||
const groupTimePeriod = R.map(item => R.map(time => time + ':00', item.split('-')), R.split(',', R.trim(timePeriod || '')))
|
||||
console.log('timePeriodArr', groupTimePeriod)
|
||||
R.forEach((timePeriodArr) => {
|
||||
timeString += `${timePeriodArr[0]}-${timePeriodArr[1]} `
|
||||
}, groupTimePeriod)
|
||||
return timeString
|
||||
}
|
||||
|
||||
|
||||
// 转换手机号码中间四位为*
|
||||
export function isPhone(mobile: string) {
|
||||
const regex = /^1[3-9]\d{9}$/;
|
||||
const regex1 = /^[1-9]\d{7}$/
|
||||
return regex.test(mobile) || regex1.test(mobile);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证邮箱
|
||||
*/
|
||||
export function isEmail(email: string) {
|
||||
const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
|
||||
return reg.test(email)
|
||||
}
|
||||
|
||||
|
||||
// 转换手机号码中间四位为*
|
||||
export function conversionMobile(mobile: string) {
|
||||
if (!mobile) {
|
||||
return
|
||||
}
|
||||
return mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
|
||||
}
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
let isIos = false;
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
isIos = plus.os.name === "iOS";
|
||||
// #endif
|
||||
|
||||
// 判断安卓主方法
|
||||
function requestAndroidPermission(permissionID, ifRequest) {
|
||||
return new Promise((resolve, reject) => {
|
||||
plus.android.requestPermissions([permissionID], onSuccess, onError);
|
||||
function onSuccess(res) {
|
||||
const grantedList = res.granted;
|
||||
const deniedList = res.deniedPresent;
|
||||
const deniedAlwaysList = res.deniedAlways;
|
||||
console.log("res", res, grantedList.includes(permissionID));
|
||||
if (grantedList.includes(permissionID)) {
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(false);
|
||||
ifRequest && gotoAppPermissionSetting();
|
||||
}
|
||||
}
|
||||
function onError(err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 分别判断Ios
|
||||
function judgeIosPermissionPush(ifRequest) {
|
||||
return new Promise((resolve) => {
|
||||
let UIApplication = plus.ios.import("UIApplication");
|
||||
let app = UIApplication.sharedApplication();
|
||||
let enabledTypes = 0;
|
||||
if (app.currentUserNotificationSettings) {
|
||||
let settings = app.currentUserNotificationSettings();
|
||||
enabledTypes = settings.plusGetAttribute("types");
|
||||
if (enabledTypes == 0) {
|
||||
ifRequest && gotoAppPermissionSetting();
|
||||
resolve(false);
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
plus.ios.deleteObject(settings);
|
||||
} else {
|
||||
enabledTypes = app.enabledRemoteNotificationTypes();
|
||||
if (enabledTypes == 0) {
|
||||
ifRequest && gotoAppPermissionSetting();
|
||||
resolve(false);
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
}
|
||||
plus.ios.deleteObject(app);
|
||||
plus.ios.deleteObject(UIApplication);
|
||||
});
|
||||
}
|
||||
|
||||
// 判断定位权限是否开启
|
||||
function judgeIosPermissionLocation(ifRequest) {
|
||||
return new Promise((resolve) => {
|
||||
let cllocationManger = plus.ios.import("CLLocationManager");
|
||||
let status = cllocationManger.authorizationStatus();
|
||||
if (status == 2) {
|
||||
ifRequest && gotoAppPermissionSetting();
|
||||
resolve(false);
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
plus.ios.deleteObject(cllocationManger);
|
||||
});
|
||||
}
|
||||
|
||||
// 判断麦克风权限是否开启
|
||||
function judgeIosPermissionRecord(ifRequest) {
|
||||
return new Promise((resolve) => {
|
||||
let avaudiosession = plus.ios.import("AVAudioSession");
|
||||
let avaudio = avaudiosession.sharedInstance();
|
||||
let permissionStatus = avaudio.recordPermission();
|
||||
if (permissionStatus == 1684369017 || permissionStatus == 1970168948) {
|
||||
ifRequest && gotoAppPermissionSetting();
|
||||
resolve(false);
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
plus.ios.deleteObject(avaudiosession);
|
||||
});
|
||||
}
|
||||
|
||||
// 判断相机权限是否开启
|
||||
function judgeIosPermissionCamera(ifRequest) {
|
||||
return new Promise((resolve) => {
|
||||
let AVCaptureDevice = plus.ios.import("AVCaptureDevice");
|
||||
let authStatus = AVCaptureDevice.authorizationStatusForMediaType("vide");
|
||||
if (authStatus == 3) {
|
||||
resolve(true);
|
||||
} else {
|
||||
ifRequest && gotoAppPermissionSetting();
|
||||
resolve(false);
|
||||
}
|
||||
plus.ios.deleteObject(AVCaptureDevice);
|
||||
});
|
||||
}
|
||||
|
||||
// 判断相册权限是否开启
|
||||
function judgeIosPermissionPhotoLibrary(ifRequest) {
|
||||
return new Promise((resolve) => {
|
||||
let PHPhotoLibrary = plus.ios.import("PHPhotoLibrary");
|
||||
let authStatus = PHPhotoLibrary.authorizationStatus();
|
||||
if (authStatus == 3) {
|
||||
resolve(true);
|
||||
} else {
|
||||
ifRequest && gotoAppPermissionSetting();
|
||||
resolve(false);
|
||||
}
|
||||
plus.ios.deleteObject(PHPhotoLibrary);
|
||||
});
|
||||
}
|
||||
|
||||
// 判断通讯录权限是否开启
|
||||
function judgeIosPermissionContact(ifRequest) {
|
||||
return new Promise((resolve) => {
|
||||
let CNContactStore = plus.ios.import("CNContactStore");
|
||||
let cnAuthStatus = CNContactStore.authorizationStatusForEntityType(0);
|
||||
if (cnAuthStatus == 3) {
|
||||
resolve(true);
|
||||
} else {
|
||||
ifRequest && gotoAppPermissionSetting();
|
||||
resolve(false);
|
||||
}
|
||||
plus.ios.deleteObject(CNContactStore);
|
||||
});
|
||||
}
|
||||
|
||||
// 安卓判断通知权限是否开启
|
||||
function judgeIosPermissionNotification(ifRequest) {
|
||||
return new Promise((resolve) => {
|
||||
let main = plus.android.runtimeMainActivity();
|
||||
let pkName = main.getPackageName();
|
||||
let uid = main.getApplicationInfo().plusGetAttribute("uid");
|
||||
let NotificationManagerCompat = plus.android.importClass("android.support.v4.app.NotificationManagerCompat");
|
||||
//android.support.v4升级为androidx
|
||||
if (NotificationManagerCompat == null) {
|
||||
NotificationManagerCompat = plus.android.importClass("androidx.core.app.NotificationManagerCompat");
|
||||
}
|
||||
let areNotificationsEnabled = NotificationManagerCompat.from(main).areNotificationsEnabled();
|
||||
|
||||
console.log("areNotificationsEnabled", areNotificationsEnabled);
|
||||
// 未开通‘允许通知'权限,则弹窗提醒开通,并点击确认后,跳转到系统设置页面进行设置
|
||||
if (areNotificationsEnabled) {
|
||||
resolve(true);
|
||||
} else {
|
||||
resolve(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 判断所有权限
|
||||
function getPermission(permission, ifRequest = false) {
|
||||
switch (permission) {
|
||||
case "location":
|
||||
if (isIos) {
|
||||
return judgeIosPermissionLocation(ifRequest);
|
||||
} else {
|
||||
return requestAndroidPermission("android.permission.ACCESS_FINE_LOCATION", ifRequest);
|
||||
}
|
||||
break;
|
||||
case "camera":
|
||||
if (isIos) {
|
||||
return judgeIosPermissionCamera(ifRequest);
|
||||
} else {
|
||||
return requestAndroidPermission("android.permission.CAMERA", ifRequest);
|
||||
}
|
||||
break;
|
||||
case "photo":
|
||||
if (isIos) {
|
||||
return judgeIosPermissionPhotoLibrary(ifRequest);
|
||||
} else {
|
||||
return requestAndroidPermission("android.permission.READ_EXTERNAL_STORAGE", ifRequest);
|
||||
}
|
||||
break;
|
||||
case "record":
|
||||
if (isIos) {
|
||||
return judgeIosPermissionRecord(ifRequest);
|
||||
} else {
|
||||
return requestAndroidPermission("android.permission.RECORD_AUDIO", ifRequest);
|
||||
}
|
||||
break;
|
||||
case "contact":
|
||||
if (isIos) {
|
||||
return judgeIosPermissionContact(ifRequest);
|
||||
} else {
|
||||
return requestAndroidPermission("android.permission.READ_CONTACTS", ifRequest);
|
||||
}
|
||||
break;
|
||||
case "call":
|
||||
if (isIos) {
|
||||
return Promise.resolve(true);
|
||||
} else {
|
||||
return requestAndroidPermission("android.permission.CALL_PHONE", ifRequest);
|
||||
}
|
||||
break;
|
||||
case "push":
|
||||
if (isIos) {
|
||||
return judgeIosPermissionPush(ifRequest);
|
||||
} else {
|
||||
return judgeIosPermissionNotification(ifRequest);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 去设置
|
||||
function gotoAppPermissionSetting() {
|
||||
if (isIos) {
|
||||
let UIApplication = plus.ios.import("UIApplication");
|
||||
let application2 = UIApplication.sharedApplication();
|
||||
let NSURL2 = plus.ios.import("NSURL");
|
||||
// let setting2 = NSURL2.URLWithString("prefs:root=LOCATION_SERVICES");
|
||||
let setting2 = NSURL2.URLWithString("app-settings:");
|
||||
application2.openURL(setting2);
|
||||
|
||||
plus.ios.deleteObject(setting2);
|
||||
plus.ios.deleteObject(NSURL2);
|
||||
plus.ios.deleteObject(application2);
|
||||
} else {
|
||||
let Intent = plus.android.importClass("android.content.Intent");
|
||||
let Settings = plus.android.importClass("android.provider.Settings");
|
||||
let Uri = plus.android.importClass("android.net.Uri");
|
||||
let mainActivity = plus.android.runtimeMainActivity();
|
||||
let intent = new Intent();
|
||||
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
let uri = Uri.fromParts("package", mainActivity.getPackageName(), null);
|
||||
intent.setData(uri);
|
||||
mainActivity.startActivity(intent);
|
||||
}
|
||||
}
|
||||
|
||||
// 检查是否开启了定位
|
||||
function checkSystemEnableLocation() {
|
||||
if (isIos) {
|
||||
let result = false;
|
||||
let cllocationManger = plus.ios.import("CLLocationManager");
|
||||
result = cllocationManger.locationServicesEnabled();
|
||||
plus.ios.deleteObject(cllocationManger);
|
||||
return result;
|
||||
} else {
|
||||
let context = plus.android.importClass("android.content.Context");
|
||||
let locationManager = plus.android.importClass("android.location.LocationManager");
|
||||
let main = plus.android.runtimeMainActivity();
|
||||
let mainSvr = main.getSystemService(context.LOCATION_SERVICE);
|
||||
let result = mainSvr.isProviderEnabled(locationManager.GPS_PROVIDER);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
getPermission,
|
||||
checkSystemEnableLocation,
|
||||
gotoAppPermissionSetting,
|
||||
};
|
||||
@@ -0,0 +1,11 @@
|
||||
export const platform = __UNI_PLATFORM__
|
||||
export const isH5 = __UNI_PLATFORM__ === 'h5'
|
||||
export const isApp = __UNI_PLATFORM__ === 'app'
|
||||
export const isMp = __UNI_PLATFORM__.startsWith('mp-')
|
||||
const PLATFORM = {
|
||||
platform,
|
||||
isH5,
|
||||
isApp,
|
||||
isMp,
|
||||
}
|
||||
export default PLATFORM
|
||||
@@ -0,0 +1,214 @@
|
||||
import {tipView, updateView} from '@/static/app/js/updateView'
|
||||
import { appVersionIsUpdateVersionPost } from '@/service'
|
||||
import {dayjs} from '@/plugin/index'
|
||||
import Config from "@/config";
|
||||
import {i18n} from "@/locale";
|
||||
|
||||
|
||||
// 比较版本号 v1 > v2 返回1,v1 < v2 返回-1,v1 = v2 返回0
|
||||
export function compareVersion(v1: string | undefined, v2: string | undefined) {
|
||||
if (!v1 || !v2) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const v1Arr = v1.split('.')
|
||||
const v2Arr = v2.split('.')
|
||||
const len = Math.max(v1Arr.length, v2Arr.length)
|
||||
while (v1Arr.length < len) {
|
||||
v1Arr.push('0')
|
||||
}
|
||||
while (v2Arr.length < len) {
|
||||
v2Arr.push('0')
|
||||
}
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const num1 = parseInt(v1Arr[i])
|
||||
const num2 = parseInt(v2Arr[i])
|
||||
|
||||
if (num1 > num2) {
|
||||
return 1
|
||||
} else if (num1 < num2) {
|
||||
return -1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// app版本更新
|
||||
export function appUpdate() {
|
||||
if (!plus?.runtime?.appid) {
|
||||
return
|
||||
}
|
||||
plus?.runtime?.getProperty(plus?.runtime?.appid, async (info) => {
|
||||
const currentVersion = info.version as string
|
||||
const platform = plus?.os?.name
|
||||
|
||||
console.log('info', platform, platform === 'iOS', info)
|
||||
|
||||
|
||||
if (platform === 'Android') {
|
||||
await updateAndroid(currentVersion, platform)
|
||||
} else if (platform === 'iOS') {
|
||||
await updateIos(currentVersion, platform)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async function updateAndroid(currentVersion: string, platform: string) {
|
||||
try {
|
||||
const res = await appVersionIsUpdateVersionPost({
|
||||
body: {
|
||||
// 1 用户端 2 门店端
|
||||
port: 1,
|
||||
// 设备类型:1-安卓(默认) 2-ios
|
||||
appType: 1,
|
||||
}
|
||||
})
|
||||
console.log('res', res)
|
||||
const versionInfo: AppVersion = res.data
|
||||
const newVersion = versionInfo?.versionNo
|
||||
const result = compareVersion(currentVersion, newVersion)
|
||||
console.log(result)
|
||||
// 本地版本最新
|
||||
if (result >= 0) {
|
||||
return
|
||||
}
|
||||
if (+versionInfo.isForce === 1) {
|
||||
installApp(versionInfo.url)
|
||||
} else {
|
||||
tipView.viewHotFixInit(versionInfo, platform)
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
async function updateIos(currentVersion: string, platform: string) {
|
||||
|
||||
|
||||
const res = await appVersionIsUpdateVersionPost({
|
||||
body: {
|
||||
// 1 用户端 2 门店端
|
||||
port: 1,
|
||||
// 设备类型:1-安卓(默认) 2-ios
|
||||
appType: 2,
|
||||
}
|
||||
})
|
||||
console.log('res', res)
|
||||
const versionInfo: AppVersion = res.data
|
||||
const newVersion = versionInfo?.versionNo
|
||||
const result = compareVersion(currentVersion, newVersion)
|
||||
console.log(result)
|
||||
// 本地版本最新
|
||||
if (result >= 0) {
|
||||
return
|
||||
}
|
||||
if (+versionInfo.isForce === 1) {
|
||||
installApp(versionInfo.url)
|
||||
} else {
|
||||
tipView.viewHotFixInit(versionInfo, platform)
|
||||
}
|
||||
}
|
||||
|
||||
async function updateIosOnline(currentVersion: string, platform: string, versionInfo: AppVersion) {
|
||||
const res = await uni.request({
|
||||
method: 'POST',
|
||||
url: `https://itunes.apple.com/lookup?id=${Config.iosId}`,
|
||||
})
|
||||
console.log('iOS', res)
|
||||
// @ts-ignore
|
||||
const {currentVersionReleaseDate, version} = res?.data?.results[0] ?? {}
|
||||
|
||||
const res1 = await uni.request({
|
||||
method: 'POST',
|
||||
url: `https://itunes.apple.com/cn/lookup?id=${Config.iosId}`,
|
||||
})
|
||||
console.log('iOS', res1)
|
||||
|
||||
const {
|
||||
currentVersionReleaseDate: currentVersionReleaseDate1,
|
||||
version: version1
|
||||
// @ts-ignore
|
||||
} = res1?.data?.results[0] ?? {}
|
||||
|
||||
if (version || version1) {
|
||||
if (currentVersionReleaseDate && version && currentVersionReleaseDate1 && version1) {
|
||||
let newVersion
|
||||
if (dayjs(currentVersionReleaseDate).isSameOrAfter(currentVersionReleaseDate1)) {
|
||||
newVersion = version
|
||||
} else {
|
||||
newVersion = version1
|
||||
}
|
||||
const result = compareVersion(currentVersion, newVersion)
|
||||
// 本地版本最新
|
||||
if (result >= 0) {
|
||||
return
|
||||
}
|
||||
|
||||
tipView.viewHotFixInit(versionInfo, platform)
|
||||
|
||||
} else {
|
||||
const result = compareVersion(currentVersion, version || version1)
|
||||
// 本地版本最新
|
||||
if (result >= 0) {
|
||||
return
|
||||
}
|
||||
tipView.viewHotFixInit(versionInfo, platform)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// app安装
|
||||
export function installApp(downloadUrl: string) {
|
||||
updateView.viewHotFixInit()
|
||||
uni
|
||||
.downloadFile({
|
||||
url: downloadUrl,
|
||||
complete: (res) => {
|
||||
console.log('res', downloadUrl, res)
|
||||
updateView.viewHotFixHide()
|
||||
if (res && res.statusCode === 200) {
|
||||
plus.runtime.install(
|
||||
(res.tempFilePath),
|
||||
{
|
||||
force: true
|
||||
},
|
||||
function (widgetInfo) {
|
||||
console.log(widgetInfo)
|
||||
uni.showToast({
|
||||
title: i18n.global.t('common.prompt.update-successfully'),
|
||||
icon: 'none',
|
||||
position: 'bottom',
|
||||
duration: 2000,
|
||||
})
|
||||
setTimeout(() => {
|
||||
plus.runtime.restart()
|
||||
}, 1000)
|
||||
|
||||
},
|
||||
function (error) {
|
||||
console.log(error)
|
||||
uni.showToast({
|
||||
title: i18n.global.t('common.prompt.update-failed'),
|
||||
icon: 'none',
|
||||
position: 'bottom',
|
||||
duration: 2000,
|
||||
})
|
||||
},
|
||||
)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: i18n.global.t('common.prompt.download-failed'),
|
||||
icon: 'none',
|
||||
position: 'bottom',
|
||||
duration: 2000,
|
||||
})
|
||||
}
|
||||
},
|
||||
})
|
||||
.onProgressUpdate((res) => {
|
||||
// console.log('下载进度' + res.progress);
|
||||
updateView.viewHotFixUpdate(res.progress)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import Crypto from 'crypto-js'
|
||||
import {Base64} from 'js-base64'
|
||||
import {i18n} from "@/locale";
|
||||
|
||||
const env = {
|
||||
uploadImageUrl: 'https://wendy123.oss-ap-southeast-1.aliyuncs.com/', // 默认存在根目录,可根据需求改
|
||||
accessKeySecret: 'TSZOD1jULKPFsNp2zKhAopLe3c3AiH', // accessKeySecret 去你的阿里云上控制台上找
|
||||
ossAccessKeyId: 'LTAI5tQq1bSBFCfsbvwX6DqQ', // AccessKeyId 去你的阿里云上控制台上找
|
||||
timeout: 87600, // 这个是上传文件时Policy的失效时间
|
||||
}
|
||||
|
||||
const getPolicyBase64 = function (): string {
|
||||
const date = new Date()
|
||||
date.setHours(date.getHours() + env.timeout)
|
||||
const expirationTime = date.toISOString()
|
||||
const policyText = {
|
||||
expiration: expirationTime, // 设置该Policy的失效时间,超过这个失效时间之后,就没有办法通过这个policy上传文件了
|
||||
conditions: [
|
||||
['content-length-range', 0, 2000 * 1024 * 1024], // 设置上传文件的大小限制,2G
|
||||
],
|
||||
}
|
||||
|
||||
return Base64.encode(JSON.stringify(policyText))
|
||||
}
|
||||
|
||||
const getSignature = function (policyBase64: string): string {
|
||||
const bytes = Crypto.HmacSHA1(policyBase64, env.accessKeySecret)
|
||||
return Crypto.enc.Base64.stringify(bytes)
|
||||
}
|
||||
|
||||
// 上传图片到阿里云oss
|
||||
const upload = function (filePath: string, suffix = '.png', dir = 'app/image/') {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!filePath) {
|
||||
return uni.showToast({icon: "none", title: i18n.global.t('common.prompt.picture-wrong-please-try-again')})
|
||||
}
|
||||
|
||||
// 图片名字 可以自行定义,这里是采用当前的时间戳 + 150内的随机数来给图片命名的
|
||||
const fileKey = dir + new Date().getTime() + Math.floor(Math.random() * 150) + suffix
|
||||
|
||||
const aliyunServerURL = env.uploadImageUrl // OSS地址,需要https
|
||||
const policyBase64 = getPolicyBase64()
|
||||
const signature = getSignature(policyBase64) // 获取签名
|
||||
|
||||
uni.uploadFile({
|
||||
url: aliyunServerURL, // 开发者服务器 url
|
||||
filePath: filePath, // 要上传文件资源的路径
|
||||
name: 'file', // 必须填file
|
||||
formData: {
|
||||
key: fileKey,
|
||||
policy: policyBase64,
|
||||
OSSAccessKeyId: env.ossAccessKeyId,
|
||||
signature: signature,
|
||||
success_action_status: '200',
|
||||
},
|
||||
success: function (res) {
|
||||
console.log(res)
|
||||
if (res.statusCode !== 200) {
|
||||
reject(new Error('upload error:' + JSON.stringify(res)))
|
||||
return
|
||||
}
|
||||
resolve(aliyunServerURL + fileKey)
|
||||
},
|
||||
fail: function (err) {
|
||||
console.log(err)
|
||||
uni.hideLoading()
|
||||
uni.showToast({icon: "none", title: i18n.global.t('common.prompt.up-failed')})
|
||||
reject(err)
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export {upload}
|
||||
@@ -0,0 +1,163 @@
|
||||
import CryptoJS from 'crypto-js'
|
||||
import {Base64} from 'js-base64'
|
||||
import {i18n} from '@/locale'
|
||||
|
||||
// === 👉 请在这里填写你的 AWS 信息 ===
|
||||
const S3Config = {
|
||||
bucket: 'cheflink', // 你的存储桶名称
|
||||
region: 'us-east-1', // 桶所在区域
|
||||
accessKeyId: 'AKIA3LKQVMAPD3KFPJGS',
|
||||
secretKey: 'tV7yvBESDPemtiHGlFOg/oFxz3L1BNXu8KutKjZS',
|
||||
timeout: 0.1 // 签名有效时间(小时)
|
||||
}
|
||||
|
||||
// === 签名函数 ===
|
||||
function getPolicyBase64(): string {
|
||||
const expiration = new Date(Date.now() + 10 * 60 * 1000).toISOString() // 10分钟有效
|
||||
const policyText = {
|
||||
expiration,
|
||||
conditions: [
|
||||
{bucket: S3Config.bucket},
|
||||
['starts-with', '$key', 'cheflink/'],
|
||||
['starts-with', '$Content-Type', 'image/']
|
||||
]
|
||||
}
|
||||
return Base64.encode(JSON.stringify(policyText))
|
||||
}
|
||||
|
||||
|
||||
function getSignature(policyBase64: string): string {
|
||||
const bytes = CryptoJS.HmacSHA1(policyBase64, S3Config.secretKey)
|
||||
return CryptoJS.enc.Base64.stringify(bytes)
|
||||
}
|
||||
|
||||
// === 图片压缩函数 ===
|
||||
function compressImageIfNeeded(filePath: string, size: number): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
// #ifdef APP-PLUS
|
||||
if (size > 3 * 1024 * 1024) {
|
||||
uni.compressImage({
|
||||
src: filePath,
|
||||
quality: 70,
|
||||
success: res => {
|
||||
uni.getFileInfo({
|
||||
filePath: res.tempFilePath,
|
||||
success: info => resolve(res.tempFilePath),
|
||||
fail: () => resolve(res.tempFilePath),
|
||||
})
|
||||
},
|
||||
fail: err => reject(err),
|
||||
})
|
||||
} else {
|
||||
resolve(filePath)
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
if (size > 3 * 1024 * 1024) {
|
||||
const img = new Image()
|
||||
img.crossOrigin = 'Anonymous'
|
||||
img.onload = function () {
|
||||
const canvas = document.createElement('canvas')
|
||||
canvas.width = img.width
|
||||
canvas.height = img.height
|
||||
const ctx = canvas.getContext('2d')
|
||||
ctx?.drawImage(img, 0, 0, img.width, img.height)
|
||||
canvas.toBlob(
|
||||
blob => {
|
||||
if (blob) {
|
||||
const url = URL.createObjectURL(blob)
|
||||
resolve(url)
|
||||
} else {
|
||||
reject(new Error('图片压缩失败'))
|
||||
}
|
||||
},
|
||||
'image/jpeg',
|
||||
0.7
|
||||
)
|
||||
}
|
||||
img.onerror = () => reject(new Error('图片加载失败'))
|
||||
img.src = filePath
|
||||
} else {
|
||||
resolve(filePath)
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-PLUS || H5
|
||||
resolve(filePath)
|
||||
// #endif
|
||||
})
|
||||
}
|
||||
|
||||
// === S3 上传函数 ===
|
||||
const uploadToS3 = async function (filePath: string, suffix = '.jpg', dir = 'cheflink/'): Promise<string> {
|
||||
if (!filePath) {
|
||||
uni.showToast({icon: 'none', title: i18n.global.t('common.prompt.picture-wrong-please-try-again')})
|
||||
return Promise.reject(new Error('filePath is empty'))
|
||||
}
|
||||
|
||||
// 获取文件信息
|
||||
let fileInfo: UniApp.GetFileInfoSuccessCallbackResult
|
||||
try {
|
||||
fileInfo = await new Promise((resolve, reject) => {
|
||||
uni.getFileInfo({
|
||||
filePath,
|
||||
success: resolve,
|
||||
fail: reject,
|
||||
})
|
||||
})
|
||||
} catch (err) {
|
||||
uni.showToast({icon: 'none', title: i18n.global.t('common.prompt.request-incorrect')})
|
||||
return Promise.reject(err)
|
||||
}
|
||||
|
||||
// 压缩图片(如果大于 3MB)
|
||||
let uploadPath: string
|
||||
try {
|
||||
uploadPath = await compressImageIfNeeded(filePath, fileInfo.size)
|
||||
} catch (err) {
|
||||
uni.showToast({icon: 'none', title: i18n.global.t('common.prompt.request-incorrect')})
|
||||
return Promise.reject(err)
|
||||
}
|
||||
|
||||
// 文件名
|
||||
const filename = Date.now() + Math.floor(Math.random() * 1000) + suffix
|
||||
const key = dir + filename
|
||||
const policyBase64 = getPolicyBase64()
|
||||
const signature = getSignature(policyBase64)
|
||||
const uploadUrl = `https://${S3Config.bucket}.s3.${S3Config.region}.amazonaws.com/`
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: uploadUrl,
|
||||
filePath: uploadPath,
|
||||
name: 'file',
|
||||
formData: {
|
||||
key,
|
||||
AWSAccessKeyId: S3Config.accessKeyId,
|
||||
policy: policyBase64,
|
||||
signature,
|
||||
'Content-Type': 'image/jpeg',
|
||||
},
|
||||
success: res => {
|
||||
if (res.statusCode === 204) {
|
||||
uni.showToast({icon: 'none', title: i18n.global.t('common.operation-success')})
|
||||
resolve(`${uploadUrl}${key}`)
|
||||
} else {
|
||||
uni.showToast({icon: 'none', title: i18n.global.t('common.prompt.up-failed')})
|
||||
reject(new Error(`上传失败,状态码: ${res.statusCode}`))
|
||||
}
|
||||
},
|
||||
fail: err => {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: i18n.global.t('common.prompt.request-failed-please-try-again-later')
|
||||
})
|
||||
reject(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export {uploadToS3}
|
||||
|
||||
@@ -0,0 +1,414 @@
|
||||
// 拨打电话
|
||||
import {i18n} from "@/locale";
|
||||
import Config from "@/config";
|
||||
import {dayjs} from "@/plugin";
|
||||
import {useConfigStore} from "@/store";
|
||||
|
||||
|
||||
// 缩略图
|
||||
export function thumbnailImg(url: string, width = 400, height = 400) {
|
||||
if (!url || !url.startsWith("http") || !url.startsWith("https")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return url + `?x-oss-process=image/resize,m_fill,w_${width},h_${height}`;
|
||||
}
|
||||
|
||||
// 转换webp
|
||||
export function formatImgWebp(url: string, width = 400, height = 400) {
|
||||
if (!url || !url.startsWith("http") || !url.startsWith("https")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return url + `?x-oss-process=image/interlace,1/format,webp`;
|
||||
}
|
||||
|
||||
|
||||
// 拨打电话
|
||||
export function callPhone(mobile: string) {
|
||||
console.log('mobile', mobile)
|
||||
|
||||
if (!mobile) {
|
||||
return uni.showToast({
|
||||
title: i18n.global.t('common.prompt.phone-number-empty'),
|
||||
icon: 'none',
|
||||
})
|
||||
}
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
const configStore = useConfigStore()
|
||||
if (configStore.isIos) {
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: mobile.trim(),
|
||||
fail(error) {
|
||||
console.error(error)
|
||||
},
|
||||
})
|
||||
} else {
|
||||
// 获取宿主上下文
|
||||
var main = plus.android.runtimeMainActivity();
|
||||
var Uri = plus.android.importClass("android.net.Uri");
|
||||
// 通过反射获取Android的Intent对象
|
||||
var Intent = plus.android.importClass("android.content.Intent");
|
||||
// 创建Intent,设置Action为ACTION_DIAL
|
||||
var intent = new Intent("android.intent.action.DIAL");
|
||||
// 设置要拨打的电话号码
|
||||
intent.setData(Uri.parse("tel:" + mobile));
|
||||
// 启动Intent
|
||||
main.startActivity(intent);
|
||||
}
|
||||
// #endif
|
||||
|
||||
// #ifndef APP-PLUS
|
||||
uni.makePhoneCall({
|
||||
phoneNumber: mobile.trim(),
|
||||
fail(error) {
|
||||
console.error(error)
|
||||
},
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
|
||||
// 复制到剪切板
|
||||
export function setClipboardData(data: string, showToast = true) {
|
||||
uni.setClipboardData({
|
||||
data,
|
||||
showToast: showToast,
|
||||
success: function () {
|
||||
uni.showToast({
|
||||
title: i18n.global.t('common.prompt.replication-successful'),
|
||||
icon: 'none',
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 微信客服
|
||||
export function loadWeixinService() {
|
||||
uni.navigateTo({
|
||||
url: `/pages/web-view/index?url=${Config.weixinServiceUrl}&title=${Config.weixinServiceName}`
|
||||
})
|
||||
}
|
||||
|
||||
// 地图导航 latLng 例如:'31.1443439,121.808273'
|
||||
export function navGoogleMap(latLng: string) {
|
||||
console.log('latLng', latLng)
|
||||
// 应用地址
|
||||
let url = ''
|
||||
// android 包名
|
||||
let pname = ''
|
||||
// ios id
|
||||
let appid: number
|
||||
if (plus.os.name == 'Android') {
|
||||
plus.nativeUI.actionSheet({
|
||||
title: i18n.global.t('common.select-maps-app'),
|
||||
cancel: i18n.global.t('common.cancel'),
|
||||
buttons: [{
|
||||
title: i18n.global.t('common.google-map')
|
||||
}]
|
||||
}, function (e) {
|
||||
switch (e.index) {
|
||||
case 1:
|
||||
url = 'google.navigation:q=' + latLng
|
||||
pname = 'com.android.vending'
|
||||
}
|
||||
if (url) {
|
||||
plus.runtime.openURL(url, function () {
|
||||
plus.nativeUI.actionSheet({
|
||||
title: i18n.global.t('common.app-marketplace'),
|
||||
cancel: i18n.global.t('common.cancel'),
|
||||
buttons: [{
|
||||
title: i18n.global.t('common.app-marketplace')
|
||||
}]
|
||||
}, function ({
|
||||
index
|
||||
}) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
plus.runtime.openURL('market://details?id=' + pname,
|
||||
function () {
|
||||
plus.nativeUI.alert(i18n.global.t('common.prompt.installed-specified-app'));
|
||||
})
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
plus.nativeUI.actionSheet({
|
||||
title: i18n.global.t('common.select-maps-app'),
|
||||
cancel: i18n.global.t('common.cancel'),
|
||||
buttons: [{
|
||||
title: i18n.global.t('common.google-map')
|
||||
}]
|
||||
}, function (e) {
|
||||
switch (e.index) {
|
||||
case 1:
|
||||
url = 'comgooglemaps://?saddr=&daddr=' + latLng
|
||||
appid = 585027354
|
||||
}
|
||||
if (url) {
|
||||
plus.runtime.launchApplication({action: url}, function (err) {
|
||||
plus.nativeUI.actionSheet({
|
||||
title: i18n.global.t('common.app-marketplace'),
|
||||
cancel: i18n.global.t('common.cancel'),
|
||||
buttons: [{
|
||||
title: i18n.global.t('common.app-marketplace')
|
||||
}]
|
||||
}, function ({
|
||||
index
|
||||
}) {
|
||||
switch (index) {
|
||||
case 1:
|
||||
plus.runtime.openURL(
|
||||
`itms-apps://itunes.apple.com/cn/app/id${appid}?mt=8')`,
|
||||
function () {
|
||||
plus.nativeUI.alert(i18n.global.t('common.prompt.installed-specified-app'));
|
||||
})
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将时间戳格式化为 "MMM.DD YYYY" 格式(例如:Mar.06 2025)
|
||||
* @param {number} timestamp - 毫秒级时间戳
|
||||
* @returns {string} 格式化后的日期字符串
|
||||
*/
|
||||
export function formatTimestamp(timestamp: number): string {
|
||||
return dayjs(Number(timestamp))
|
||||
.format('MMM.DD YYYY') // 核心格式化指令
|
||||
.replace(/\b([a-z])/, match => match.toUpperCase()); // 确保月份首字母大写
|
||||
}
|
||||
|
||||
/**
|
||||
* 将时间戳格式化为 "YYYY.MM.DD HH:mm 星期几" 格式
|
||||
* 星期几根据当前语言环境显示(中文:周一,英文:Mon)
|
||||
* 例如:2025.08.22 14:30 Fri 或 2025.08.22 14:30 周五
|
||||
* @param {number} timestamp - 毫秒级时间戳
|
||||
* @returns {string} 格式化后的日期时间字符串
|
||||
*/
|
||||
export function formatTimestampWithWeekday(timestamp: number): string {
|
||||
const locale = uni.getLocale()
|
||||
const date = dayjs(Number(timestamp))
|
||||
|
||||
// 设置对应的语言环境
|
||||
if (locale === 'zh-Hans') {
|
||||
date.locale('zh-cn')
|
||||
} else {
|
||||
date.locale('en')
|
||||
}
|
||||
|
||||
// 获取星期几的简写
|
||||
const weekdayShort = date.format('ddd')
|
||||
|
||||
return `${date.format('YYYY.MM.DD HH:mm')} ${weekdayShort}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 将时间戳格式化为带月份名称的格式(如:June 3, 2025 12:25)
|
||||
* 根据当前语言环境显示中文或英文月份
|
||||
* @param {number} timestamp - 时间戳(毫秒)
|
||||
* @returns {string} 格式化后的时间字符串
|
||||
*/
|
||||
export function formatTimestampWithMonthName(timestamp: number): string {
|
||||
const locale = uni.getLocale()
|
||||
const date = dayjs(Number(timestamp))
|
||||
|
||||
// 设置对应的语言环境
|
||||
if (locale === 'zh-Hans') {
|
||||
date.locale('zh-cn')
|
||||
// 中文格式:2025年6月3日 12:25
|
||||
return date.format('YYYY年M月D日 HH:mm')
|
||||
} else {
|
||||
date.locale('en')
|
||||
// 英文格式:June 3, 2025 12:25
|
||||
return date.format('MMMM D, YYYY HH:mm')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将时间戳格式化为简短的月日时间格式(如:Jun 3 19:00)
|
||||
* 根据当前语言环境显示中文或英文月份
|
||||
* @param {number} timestamp - 时间戳(毫秒)
|
||||
* @returns {string} 格式化后的时间字符串
|
||||
*/
|
||||
export function formatTimestampShort(timestamp: number): string {
|
||||
const locale = uni.getLocale()
|
||||
const date = dayjs(Number(timestamp))
|
||||
|
||||
// 设置对应的语言环境
|
||||
if (locale === 'zh-Hans') {
|
||||
date.locale('zh-cn')
|
||||
// 中文格式:6月3日 19:00
|
||||
return date.format('M月D日 HH:mm')
|
||||
} else {
|
||||
date.locale('en')
|
||||
// 英文格式:Jun 3 19:00
|
||||
return date.format('MMM D HH:mm')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个经纬度之间的球面距离(单位:英里)
|
||||
* @param {number} lat1 - 第一个点的纬度(十进制度)
|
||||
* @param {number} lon1 - 第一个点的经度(十进制度)
|
||||
* @param {number} lat2 - 第二个点的纬度(十进制度)
|
||||
* @param {number} lon2 - 第二个点的经度(十进制度)
|
||||
* @returns {number} 距离(英里)
|
||||
*/
|
||||
export function getDistanceInMiles(lat1: number, lon1: number, lat2: number, lon2: number): string {
|
||||
const toRad = (angle: number) => angle * Math.PI / 180;
|
||||
const R = 6371000; // 地球半径,单位:米
|
||||
const metersToMiles = 0.000621371; // 米到英里的转换系数
|
||||
|
||||
const φ1 = toRad(lat1);
|
||||
const φ2 = toRad(lat2);
|
||||
const Δφ = toRad(lat2 - lat1);
|
||||
const Δλ = toRad(lon2 - lon1);
|
||||
|
||||
const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
|
||||
Math.cos(φ1) * Math.cos(φ2) *
|
||||
Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
|
||||
|
||||
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
||||
|
||||
const meters = R * c;
|
||||
return (meters * metersToMiles).toFixed(2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析商家营业时间字符串
|
||||
* @param businessHours 营业时间字符串,格式如:"MONDAY/TUESDAY/WEDNESDAY/THURSDAY/FRIDAY/SATURDAY/SUNDAY 05:00-16:00"
|
||||
* @returns 格式化后的营业时间,如:"周一,周二,周三,周四,周五,周六,周日 05:00-16:00" 或 "Mon,Tue,Wed,Thu,Fri,Sat,Sun 05:00-16:00"
|
||||
*/
|
||||
export function parseBusinessHoursUtils(businessHours: string): string {
|
||||
if (!businessHours || !businessHours.trim()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const locale = uni.getLocale()
|
||||
|
||||
// 英文星期到中文和英文简写的映射
|
||||
const weekMapChinese: { [key: string]: string } = {
|
||||
'MONDAY': '周一',
|
||||
'TUESDAY': '周二',
|
||||
'WEDNESDAY': '周三',
|
||||
'THURSDAY': '周四',
|
||||
'FRIDAY': '周五',
|
||||
'SATURDAY': '周六',
|
||||
'SUNDAY': '周日'
|
||||
};
|
||||
|
||||
const weekMapEnglish: { [key: string]: string } = {
|
||||
'MONDAY': 'Mon',
|
||||
'TUESDAY': 'Tue',
|
||||
'WEDNESDAY': 'Wed',
|
||||
'THURSDAY': 'Thu',
|
||||
'FRIDAY': 'Fri',
|
||||
'SATURDAY': 'Sat',
|
||||
'SUNDAY': 'Sun'
|
||||
};
|
||||
|
||||
// 根据语言环境选择映射表
|
||||
const weekMap = locale === 'en' ? weekMapEnglish : weekMapChinese;
|
||||
const weekOrder = locale === 'en'
|
||||
? ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
|
||||
: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'];
|
||||
const separator = locale === 'en' ? '-' : '-';
|
||||
|
||||
try {
|
||||
// 分割星期和时间部分
|
||||
const parts = businessHours.trim().split(' ');
|
||||
if (parts.length < 2) {
|
||||
return businessHours; // 格式不正确,返回原字符串
|
||||
}
|
||||
|
||||
const weekPart = parts[0]; // 星期部分
|
||||
const timePart = parts.slice(1).join(' '); // 时间部分(可能有多个时间段)
|
||||
|
||||
// 解析星期
|
||||
const weekDays = weekPart.split('/');
|
||||
const translatedWeeks = weekDays
|
||||
.map(day => weekMap[day.toUpperCase()])
|
||||
.filter(day => day); // 过滤掉无效的星期
|
||||
|
||||
if (translatedWeeks.length === 0) {
|
||||
return businessHours; // 没有有效的星期,返回原字符串
|
||||
}
|
||||
|
||||
// 处理连续的星期(如周一到周五)
|
||||
let weekString = '';
|
||||
if (translatedWeeks.length > 2) {
|
||||
// 检查是否为连续的星期
|
||||
const indices = translatedWeeks.map(week => weekOrder.indexOf(week)).filter(index => index !== -1);
|
||||
|
||||
if (indices.length > 1) {
|
||||
indices.sort((a, b) => a - b);
|
||||
|
||||
// 检查是否连续
|
||||
let isContinuous = true;
|
||||
for (let i = 1; i < indices.length; i++) {
|
||||
if (indices[i] !== indices[i-1] + 1) {
|
||||
isContinuous = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isContinuous && indices.length > 2) {
|
||||
weekString = `${weekOrder[indices[0]]}${separator}${weekOrder[indices[indices.length - 1]]}`;
|
||||
} else {
|
||||
weekString = translatedWeeks.join(',');
|
||||
}
|
||||
} else {
|
||||
weekString = translatedWeeks.join(',');
|
||||
}
|
||||
} else {
|
||||
weekString = translatedWeeks.join(',');
|
||||
}
|
||||
|
||||
return `${weekString} ${timePart}`;
|
||||
} catch (error) {
|
||||
console.error('解析营业时间出错:', error);
|
||||
return businessHours; // 出错时返回原字符串
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 安全获取多语言文本并做占位符替换
|
||||
* - 不经过 t()
|
||||
* - 不触发 vue-i18n 插值
|
||||
* - 全平台稳定
|
||||
*/
|
||||
export function tWithParams(
|
||||
key: string,
|
||||
params: Record<string, any> = {}
|
||||
) {
|
||||
const locale =
|
||||
typeof i18n.global.locale === 'string'
|
||||
? i18n.global.locale
|
||||
: i18n.global.locale.value
|
||||
|
||||
const messages = i18n.global.getLocaleMessage(locale)
|
||||
if (!messages) return key
|
||||
|
||||
// 支持 a.b.c 深层 key
|
||||
let str: any = key.split('.').reduce((obj, k) => obj?.[k], messages)
|
||||
|
||||
if (typeof str !== 'string') {
|
||||
// fallback:交给 i18n 自己处理
|
||||
return i18n.global.t(key, params)
|
||||
}
|
||||
|
||||
// 使用 split + join(比正则更安全)
|
||||
Object.keys(params).forEach(k => {
|
||||
const val = params[k] ?? ''
|
||||
str = str.split(`{${k}}`).join(String(val))
|
||||
})
|
||||
|
||||
return str
|
||||
}
|
||||
Reference in New Issue
Block a user