import { pages, subPackages, tabBar } from '@/pages.json' import { isMpWeixin } from './platform' import { useAppStore } from '@/store' const getLastPage = () => { // getCurrentPages() 至少有1个元素,所以不再额外判断 // const lastPage = getCurrentPages().at(-1) // 上面那个在低版本安卓中打包回报错,所以改用下面这个【虽然我加了src/interceptions/prototype.ts,但依然报错】 const pages = getCurrentPages() return pages[pages.length - 1] } /** 判断当前页面是否是tabbar页 */ export const getIsTabbar = () => { if (!tabBar) { return false } if (!tabBar.list.length) { // 通常有tabBar的话,list不能有空,且至少有2个元素,这里其实不用处理 return false } const lastPage = getLastPage() const currPath = lastPage.route return !!tabBar.list.find((e) => e.pagePath === currPath) } /** * 获取当前页面路由的 path 路径和 redirectPath 路径 * path 如 ‘/pages/login/index’ * redirectPath 如 ‘/pages/demo/base/route-interceptor’ */ export const currRoute = () => { const lastPage = getLastPage() const currRoute = (lastPage as any).$page // 经过多端测试,只有 fullPath 靠谱,其他都不靠谱 const { fullPath } = currRoute as { fullPath : string } // eg: /pages/login/index?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor (小程序) // eg: /pages/login/index?redirect=%2Fpages%2Froute-interceptor%2Findex%3Fname%3Dfeige%26age%3D30(h5) return getUrlObj(fullPath) } const ensureDecodeURIComponent = (url : string) => { if (url.startsWith('%')) { return ensureDecodeURIComponent(decodeURIComponent(url)) } return url } /** * 解析 url 得到 path 和 query * 比如输入url: /pages/login/index?redirect=%2Fpages%2Fdemo%2Fbase%2Froute-interceptor * 输出: {path: /pages/login/index, query: {redirect: /pages/demo/base/route-interceptor}} */ export const getUrlObj = (url : string) => { const [path, queryStr] = url.split('?') if (!queryStr) { return { path, query: {}, } } const query : Record = {} queryStr.split('&').forEach((item) => { const [key, value] = item.split('=') query[key] = ensureDecodeURIComponent(value) // 这里需要统一 decodeURIComponent 一下,可以兼容h5和微信y }) return { path, query } } /** * 得到所有的需要登录的pages,包括主包和分包的 * 这里设计得通用一点,可以传递key作为判断依据,默认是 needLogin, 与 route-block 配对使用 * 如果没有传 key,则表示所有的pages,如果传递了 key, 则表示通过 key 过滤 */ export const getAllPages = (key = 'needLogin') => { // 这里处理主包 const mainPages = [ ...pages .filter((page) => !key || page[key]) .map((page) => ({ ...page, path: `/${page.path}`, })), ] // 这里处理分包 const subPages : any[] = [] subPackages.forEach((subPageObj) => { const { root } = subPageObj subPageObj.pages .filter((page) => !key || page[key]) .forEach((page : { path : string } & Record) => { subPages.push({ ...page, path: `/${root}/${page.path}`, }) }) }) const result = [...mainPages, ...subPages] return result } /** * 得到所有的需要登录的pages,包括主包和分包的 * 只得到 path 数组 */ export const getNeedLoginPages = () : string[] => getAllPages('needLogin').map((page) => page.path) /** * 得到所有的需要登录的pages,包括主包和分包的 * 只得到 path 数组 */ export const needLoginPages : string[] = getAllPages('needLogin').map((page) => page.path) /** * 根据微信小程序当前环境,判断应该获取的BaseUrl */ export const getEnvBaseUrl = () => { // 请求基准地址 let baseUrl = import.meta.env.VITE_SERVER_BASEURL // 微信小程序端环境区分 if (isMpWeixin) { const { miniProgram: { envVersion }, } = uni.getAccountInfoSync() switch (envVersion) { case 'develop': baseUrl = import.meta.env.VITE_SERVER_BASEURL__WEIXIN_DEVELOP || baseUrl break case 'trial': baseUrl = import.meta.env.VITE_SERVER_BASEURL__WEIXIN_TRIAL || baseUrl break case 'release': baseUrl = import.meta.env.VITE_SERVER_BASEURL__WEIXIN_RELEASE || baseUrl break } } return baseUrl } /** * 根据微信小程序当前环境,判断应该获取的UPLOAD_BASEURL */ export const getEnvBaseUploadUrl = () => { // 请求基准地址 let baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL // 微信小程序端环境区分 if (isMpWeixin) { const { miniProgram: { envVersion }, } = uni.getAccountInfoSync() switch (envVersion) { case 'develop': baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL__WEIXIN_DEVELOP || baseUploadUrl break case 'trial': baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL__WEIXIN_TRIAL || baseUploadUrl break case 'release': baseUploadUrl = import.meta.env.VITE_UPLOAD_BASEURL__WEIXIN_RELEASE || baseUploadUrl break } } return baseUploadUrl } /** * 时间格式化 * @param value * @param fmt * @returns {*} */ export function formatDate(value, fmt) { var regPos = /^\d+(\.\d+)?$/; if (regPos.test(value)) { //如果是数字 let getDate = new Date(value); let o = { 'M+': getDate.getMonth() + 1, 'd+': getDate.getDate(), 'h+': getDate.getHours(), 'H+': getDate.getHours(), 'm+': getDate.getMinutes(), 's+': getDate.getSeconds(), 'q+': Math.floor((getDate.getMonth() + 3) / 3), 'S': getDate.getMilliseconds() }; if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (getDate.getFullYear() + '').substr(4 - RegExp.$1.length)) } for (let 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; } else { //TODO if (value && value.length > 0) { value = value.trim(); return value.substr(0, fmt.length); } return value } } /** * 判断是否有新版本 * @param version 接口返回的版本号 * @param isWgt 是否是热资源更新 默认不是 */ export const hasNewVersion = (version, isWgt = false) => { // #ifdef APP_PLUS return new Promise((resolve) => { const transfer = (str) => { const parts = str.split('.').map(part => part.padStart(4, '0')) return parts.join('') } if (isWgt) { plus.runtime.getProperty(plus.runtime.appid, (widgetInfo) => { const currentVersion = widgetInfo.version resolve(+transfer(version) > +transfer(currentVersion)) }) } else { const currentVersion = plus.runtime.version resolve(+transfer(version) > +transfer(currentVersion)) } }) // #endif } export function onClickUpdate(updateType : string, url) { // #ifdef APP-PLUS if (updateType != 'wgt') plus.runtime.openURL(url.apkUrl) else downloadApp(url.wgtUrl) // #endif } function downloadApp(url : string) { var dtask = plus.downloader.createDownload(url, { filename: `_downloads/wgt-${Date.now()}.wgt` //利用保存路径,实现下载文件的重命名 }, function (d, status) { //d为下载的文件对象 if (status == 200) { //下载成功,d.filename是文件在保存在本地的相对路径,使用下面的API可转为平台绝对路径 var fileSaveUrl = plus.io.convertLocalFileSystemURL(d.filename); installApp(fileSaveUrl) } else { //下载失败 plus.downloader.clear(); //清除下载任务 uni.showToast({ title: 'App下载失败!', icon: 'error' }) } }) let prg = 0 let showLoading = plus.nativeUI.showWaiting('正在下載') dtask.start() dtask.addEventListener('statechanged', (task) => { // 给下载任务设置一个监听 并根据状态 做操作 switch (task.state) { case 1: showLoading.setTitle("正在下载") break case 2: showLoading.setTitle("已连接到服务器") break case 3: { const downloaded = +task.downloadedSize; // 转为数字 const total = +task.totalSize; // 转为数字 prg = total > 0 ? Math.floor((downloaded / total) * 100) : 0; showLoading.setTitle(`正在下载 ${prg}%`); break; } case 4: plus.nativeUI.closeWaiting() //下载完成 break } }) } function installApp(tempFilePath : string) { // #ifdef APP-PLUS plus.runtime.install( tempFilePath, { force: true }, () => { uni.showModal({ title: '更新', content: '更新成功,请点击确认后重启', showCancel: false, success(res) { if (res.confirm) { plus.runtime.restart() } } }) }, () => uni.showToast({ title: '安装失败!', icon: 'error' }) ) // #endif } /** * 定位 */ export const getLocation = () => { const store = useAppStore() // 先尝试获取位置,失败时再回退 uni.getLocation({ type: 'wgs84', success: function (position) { // 成功获取位置后请求地理编码 uni.request({ url: 'http://api.tianditu.gov.cn/geocoder', method: 'GET', data: { postStr: JSON.stringify({ lon: position.longitude, lat: position.latitude, ver: 1 }), type: 'geocode', tk: '30fe0f0c1b2320e112bde797f3ddaff4' }, success: function (res : any) { let data = res.data; if (data.status == 0) { const obj = data.result.addressComponent store.setPosition(obj.city ? obj.city : obj.province) //市 store.setLocation(obj.city ? obj.province + obj.city + obj.county : obj.province + obj.county) //省市区 getWeather(position.latitude, position.longitude) } else { handleDefaultLocation() } }, fail: function (err) { // uni.showToast({ // title: '位置解析失败', // icon: 'error' // }) handleDefaultLocation() } }); }, fail: function (err) { // 根据不同错误码处理 // if (err.errCode === 2 || err.errCode === 12) { // // 2: 位置服务不可用, 12: 定位权限未开启 // uni.showToast({ // title: '请开启定位服务', // icon: 'error' // }) // } else { // uni.showToast({ // title: '定位获取失败', // icon: 'error' // }) // } handleDefaultLocation() } }); } const getWeather = (lat : number, lon : number) => { let params = { lat: lat, lon: lon } weatherRequest(params) } // 处理默认位置和天气 function handleDefaultLocation() { useAppStore().setPosition('濮阳市') weatherRequest({ q: '濮阳市' }) } function weatherRequest(params : { lat ?: number; lon ?: number; q ?: string }) { const store = useAppStore() uni.request({ url: 'http://api.openweathermap.org/data/2.5/weather', method: 'GET', data: { ...params, appid: '600a60694b0e453dfbaafa862f1d1482', lang: 'zh_cn' }, success: function (res : any) { if (res.data && res.data.main && res.data.weather) { store.setTemperature( Math.round(res.data.main.temp - 273.15) ) store.setWeather( res.data.weather[0].icon ) } else { // uni.showToast({ // title: '天气数据格式错误', // icon: 'error' // }) } }, // fail: function () { // uni.showToast({ // title: '天气获取失败', // icon: 'error' // }) // } }); } export const imgUrl = (url : string) => { return getEnvBaseUrl() + '/sys/common/static/' + `/${url}` } /** * 获取文件服务访问路径 * @param avatar * @param subStr * @returns {*} */ export function getFileAccessHttpUrl(avatar, subStr) { if (!subStr) subStr = 'http' if (avatar && avatar.startsWith(subStr)) { return avatar; } else { if (avatar && avatar.length > 0 && avatar.indexOf('[') == -1) { return getEnvBaseUrl() + "/sys/common/static/" + avatar; } } }