import Vue from 'vue' // import MpvueRouterPatch from 'mpvue-router-patch' // Vue.use(MpvueRouterPatch) import {getUserInfo, wxappAuth, wxappCheckAuth} from "@/api/user"; import store from "../store"; import dayjs from "dayjs"; import cookie from "@/utils/store/cookie"; import stringify from "@/utils/querystring"; import {VUE_APP_API_URL} from "@/config"; import {auth} from '@/libs/wechat' export function dataFormat(time, option) { time = +time * 1000; const d = new Date(time); const now = new Date().getTime(); const diff = (now - d) / 1000; if (diff < 30) { return "刚刚"; } else if (diff < 3600) { // less 1 hour return Math.ceil(diff / 60) + "分钟前"; } else if (diff < 3600 * 24) { return Math.ceil(diff / 3600) + "小时前"; } else if (diff < 3600 * 24 * 2) { return "1天前"; } if (option) { // return parseTime(time, option); } else { let timeStr = d.getFullYear() + "年" + (d.getMonth() + 1) + "月" + d.getDate() + "日" + d.getHours() + "时" + d .getMinutes() + "分" return timeStr } } export function dateFormatT(time) { time = +time * 1000; const d = new Date(time); return ( d.getFullYear() + "/" + (d.getMonth() + parseInt(1)) + "/" + d.getDate() ); } /* *格式化时间 * @param time {Number} 时间戳(毫秒) * @param format {String} 格式(例:yyyy-MM-dd) */ export function formatDateTime(time, format) { var t = new Date(time); var tf = function (i) { return (i < 10 ? "0" : "") + i; }; return format.replace(/yyyy|MM|dd|HH|mm|ss/g, function (a) { switch (a) { case "yyyy": return tf(t.getFullYear()); break; case "MM": return tf(t.getMonth() + 1); break; case "mm": return tf(t.getMinutes()); break; case "dd": return tf(t.getDate()); break; case "HH": return tf(t.getHours()); break; case "ss": return tf(t.getSeconds()); break; } }); } export function timeNow(updateTime) { if (updateTime === null) { return '' } let now = new Date().getTime() let second = Math.floor((now - updateTime) / (1000)) let minute = Math.floor(second / 60) let hour = Math.floor(minute / 60) let day = Math.floor(hour / 24) let month = Math.floor(day / 31) let year = Math.floor(month / 12) console.log(hour); console.log(minute); if (year > 0) { return year + '年前' } else if (month > 0) { return month + '月前' } else if (day > 0) { let ret = day + '天前' if (day >= 7 && day < 14) { ret = '1周前' } else if (day >= 14 && day < 21) { ret = '2周前' } else if (day >= 21 && day < 28) { ret = '3周前' } else if (day >= 28 && day < 31) { ret = '4周前' } return ret } else if (hour > 0) { return hour + '小时前' } else if (minute > 0) { return minute + '分钟前' } else if (second > 0) { return second + '秒前' } else { return '刚刚' } } export function diffDay(start, end) { var dateBegin = new Date(start.replace(/-/g, "/")); var dateEnd = new Date(end.replace(/-/g, "/")); var dateDiff = dateEnd.getTime() - dateBegin.getTime(); //时间差的毫秒数 return Math.floor(dateDiff / (24 * 3600 * 1000)); //计算出相差天数 } export function trim(str) { return String.prototype.trim.call(str); } export function isType(arg, type) { return Object.prototype.toString.call(arg) === "[object " + type + "]"; } export function isWeixin() { return false } export function isNullOrEmpty(value) { //是否为空 return value === null || value === "" || value === undefined ? true : false; } export function parseQuery() { var pages = getCurrentPages() //获取加载的页面 var currentPage = pages[pages.length - 1] //获取当前页面的对象 var url = currentPage.route //当前页面url var options = currentPage.options //如果要获取url中所带的参数可以查看options return options } /*获取当前页url*/ export function getCurrentPageUrl() { var pages = getCurrentPages() //获取加载的页面 var currentPage = pages[pages.length - 1] //获取当前页面的对象 var url = currentPage.route //当前页面url return url } /*获取当前页带参数的url*/ export function getCurrentPageUrlWithArgs() { var pages = getCurrentPages() //获取加载的页面 var currentPage = pages[pages.length - 1] //获取当前页面的对象 var url = currentPage.route //当前页面url var options = currentPage.options //如果要获取url中所带的参数可以查看options //拼接url的参数 var urlWithArgs = url + '?' for (var key in options) { var value = options[key] urlWithArgs += key + '=' + value + '&' } urlWithArgs = urlWithArgs.substring(0, urlWithArgs.length - 1) return urlWithArgs } // 复制到剪切板 export const copyClipboard = (data) => { uni.setClipboardData({ data: data, success: (res) => { uni.showToast({ title: '复制成功', icon: 'success', duration: 2000 }) } }) } export const getProvider = (service) => { return new Promise((resolve, reject) => { // 获取当前环境的服务商 uni.getProvider({ service: service || 'oauth', success: function (res) { // 此处可以排除h5 if (res.provider) { resolve(res.provider[0]) } }, fail() { reject('获取环境服务商失败') } }) }).catch(error => { }) } export const authorize = (authorizeStr) => { return new Promise((resolve, reject) => { uni.getSetting({ success(res) { if (res.authSetting[`scope.${authorizeStr}`]) { resolve(true) } else { reject(false) } }, fail() { reject(false) } }) }) } export const checkAuth = () => { return new Promise((resolve, reject) => { getProvider() .then(provider => { if (!provider) { reject(false) } // 调用登录接口 uni.login({ provider: provider, success: function (loginRes) { // 微信登录 let code = loginRes.code wxappCheckAuth({ code: code, }) .then(authRes => { var data = authRes.data; if (data != null) { var userInfo = { "nickName": data.wxProfile.nickname, "gender": data.wxProfile.sex, "language": data.wxProfile.language, "city": data.wxProfile.city, "province": data.wxProfile.province, "country": data.wxProfile.country, "avatarUrl": data.wxProfile.headimgurl }; resolve(userInfo); //reject(false); } else { reject(false); } }) .catch(error => { reject(false); }); }, fail() { reject(false) }, }) }) .catch(error => { reject(false) }) }) } export const login = loginInfo => { return new Promise((resolve, reject) => { if (Vue.prototype.$deviceType == 'weixin') { // 微信授权登录 const { code } = parseQuery() if (code) { auth(code) .then(() => { let redirect = cookie.get('redirect').replace(/\ /g, '') if (redirect) { redirect = redirect.split('/pages')[1] if (!redirect) { redirect = '/Loading/index' } reLaunch({ path: '/pages' + redirect, }) cookie.remove('redirect') } else { reLaunch({ path: '/pages/home/index', }) } }) .catch(() => { reject('当前运行环境为微信浏览器') reLaunch({ path: '/pages/home/index', }) }) } else { } return } if (Vue.prototype.$deviceType == 'weixinh5') { reject('当前运行环境为H5') return } if (Vue.prototype.$deviceType == 'app') { reject('当前运行环境为app') return } getProvider() .then(provider => { if (!provider) { reject() } // 调用登录接口 uni.login({ provider: provider, success: async function (loginRes) { // 微信登录 let code = loginRes.code cookie.set('wxLoginCode', loginRes.code) if (!uni.getUserProfile) { reject('用户未授权') return } if (uni.getUserProfile) { if (loginInfo) { wxappAuth({ encryptedData: loginInfo.encryptedData, iv: loginInfo.iv, userInfo: loginInfo.userInfo, code: code, spread: cookie.get('spread'), }) .then(({ data }) => { console.log("wxappAuth 326") uni.hideLoading() store.commit('login', data.token, dayjs(data.expires_time)) store.dispatch('userInfo', true) getUserInfo() .then(user => { uni.setStorageSync('uid', user.data.uid) store.dispatch('setUserInfo', user.data) resolve(user) }) .catch(error => { reject('获取用户信息失败') }) }) .catch(error => { reject('登录接口调用失败') }) } else { reject('用户未授权') return } } else { uni.getUserInfo({ provider: provider, success: function (user) { wxappAuth({ encryptedData: user.encryptedData, iv: user.iv, code: code, spread: cookie.get('spread'), }) .then(({ data }) => { console.log("wxappAuth 360") uni.hideLoading() store.commit('login', data.token, dayjs(data.expires_time)) store.dispatch('userInfo', true) getUserInfo() .then(user => { uni.setStorageSync('uid', user.data.uid) store.dispatch('setUserInfo', user.data) resolve(user) }) .catch(error => { reject('获取用户信息失败') }) }) .catch(error => { reject('登录接口调用失败') }) }, fail() { reject('获取用户信息失败') }, }) } }, fail() { reject('调用登录接口失败') }, }) }) .catch(error => { reject('获取环境服务商失败') }) }) } export const handleGetUserInfo = () => { getUserInfo().then(res => { store.dispatch('setUserInfo', res.data) var pages = getCurrentPages() //获取加载的页面 var currentPage = pages[pages.length - 1] //获取当前页面的对象 let url = "/pages/home/index" let query = {} if (currentPage) { const { redirect, ...querys } = currentPage.options // 获取到最后一个页面 if ( currentPage.route != 'pages/Loading/index' && currentPage.route != 'pages/user/Login/index' ) { url = currentPage.route query = { ...querys } } if (currentPage.route == 'pages/authorization/index') { url = redirect query = { ...querys } } } if (url == '/pages/home/index' || url == '/pages/shop/GoodsClass/index' || url == '/pages/cart' || url == '/pages/user/User/index') { switchTab({ path: `${url}`, query }); } else { // 为了防止返回上一页是授权页面,先重定向到首页,再跳转 reLaunch({ path: '/pages/home/index', // query }); setTimeout(() => { if (url.indexOf('/') == 0) { url = url.slice(1) } push({ path: `/${url}`, query }) }) // push({ // path: `${url}`, // query // }) } }) } export function parseUrl(location) { if (typeof location === 'string') return location const { path, query } = location const queryStr = stringify(query) if (!queryStr) { return path } return `${path}?${queryStr}` } export function parseRoute($mp) { const _$mp = $mp || {} const path = _$mp.page && _$mp.page.route return { path: `/${path}`, params: {}, query: _$mp.query || _$mp.page.options, hash: '', fullPath: parseUrl({ path: `/${path}`, query: _$mp.query || _$mp.page.options }), name: path && path.replace(/\/(\w)/g, ($0, $1) => $1.toUpperCase()) } } export function handleAuth() { /** * 如何判断权限? * 用户如果登录了系统,会留下两个东西,一个是token,一个是userInfo * token存在会过期的问题,如果长时间没有打开小程序,会导致登录失效,出现打开一个页面瞬间跳转到授权页面的问题 * 解决办法,保存token的时候加上过期时间,每次请求都取一下缓存里的token * userInfo只是用来限时用户信息,作用并不是很大 * ps:只需要判断 token 是否存在即可 */ if (cookie.get('login_status')) { return true } return false } export const handleLoginStatus = (location, complete, fail, success) => { // 不登录可访问的页面 let page = [{ path: '/pages/Loading/index', name: 'loading页面' }, { path: '/pages/home/index', name: '首页' }, { path: '/pages/user/Login/index', name: '登录页面' }, { path: '/pages/authorization/index', name: '授权页面' }, { path: '/pagesInn/inn/innHome', name: '店铺首页' } ] // 是否可以访问 let isAuth = false // 从 location 中获取当前url,location typeof string || object let path = '' if (typeof location === 'string') { path = location } else { path = location.path } // 判断用户是否有token if (!handleAuth()) { page.map((item) => { if (item.path == path) { isAuth = true } }) } else { isAuth = true } return new Promise((resolve, reject) => { resolve({ url: parseUrl(location), complete, fail, success, }) // if (isAuth) { // // 有token // if (path == '/pages/home/index' || path == '/pages/shop/GoodsClass/index' || path == '/pages/cart' || path == '/pages/user/User/index') { // // switchTab({ // // path: parseUrl(location), // // }) // // return // } // resolve({ // url: parseUrl(location), // complete, // fail, // success // }) // } else { // // 没有token,先校验用户是否授权,如果授权了,进行自动登录 // routerPermissions(parseUrl(location)) // reject() // } }).catch(error => { }) } // export function checkPermissions(){ // } export async function routerPermissions(url, type) { let path = url if (!path) { path = '/' + getCurrentPageUrlWithArgs() } if (Vue.prototype.$deviceType === 'routine') { // 如果是微信小程序,跳转到授权页 // 先校验用户是否授权,如果授权了,进行自动登录 //authorize('userInfo')因为小程序登录和授权接口的修改基本废了 //所以这里不能再用它来判断用户是否同意过授权,要么就是用uni.login获取到code去调用服务器 //接口,看用户是否授权过用户信息,如果有直接返回;如果没有,才跳转到授权页进行授权弹窗获取 //这里的逻辑要改一下 //检查授权信息 let authUserInfo = await checkAuth().catch(err => { }); if (authUserInfo) { var loginInfo = { userInfo: authUserInfo, iv: '', encryptedData: '' } // 自动登录 login(loginInfo).then(res => { // 登录成功,跳转到需要跳转的页面 store.commit("updateAuthorizationPage", false); if (path == '/pages/cart' || path == '/pages/user/User/index') { return } if (type == 'reLaunch') { reLaunch({ path, }) return } if (type == 'replace') { replace({ path, }) return } { push({ path, }) } }).catch(error => { uni.showToast({ title: error, icon: "none", duration: 2000 }); reLaunch({ path: '/pages/authorization/index', }) cookie.set('redirect', path) }) } else { // 跳转到登录页面或者授权页面 // path == '/pages/cart' || if ( path == '/pages/user/User/index') { switchTab({ path, }) store.commit("updateAuthorizationPage", false); return } reLaunch({ path: '/pages/authorization/index', }) cookie.set('redirect', path) } } else { // 如果不是小程序跳转到登录页 push({ path: '/pages/user/Login/index', }) cookie.set('redirect', path) } } export function push(location, complete, fail, success) { handleLoginStatus(location, complete, fail, success).then(params => { uni.navigateTo(params) }).catch(error => { // 没有权限 }) } export function replace(location, complete, fail, success) { handleLoginStatus(location, complete, fail, success).then(params => { uni.redirectTo(params) }).catch(error => { // 没有权限 }) } export function reLaunch(location, complete, fail, success) { handleLoginStatus(location, complete, fail, success).then(params => { uni.reLaunch(params) }).catch(error => { // 没有权限 }) } export function go(delta) { uni.navigateBack({ delta }) } export function back() { uni.navigateBack({ delta: 1, success: function (e) { }, fail: function (e) { } }) } export function switchTab(location, complete, fail, success) { handleLoginStatus(location, complete, fail, success).then(params => { uni.switchTab(params) }).catch(error => { // 没有权限 }) } export const _router = { mode: 'history', switchTab, push, replace, go, back, reLaunch } export function handleQrCode() { try { var urlSpread = parseQuery()["q"]; if (urlSpread) { if (urlSpread.indexOf('%3F') != -1) { // 通过海报二维码进来 urlSpread = urlSpread .split("%3F")[1] .replace(/%3D/g, ":") .replace(/%26/g, ",") .split(",") .map((item, index) => { item = item.split(":"); return `"${item[0]}":"${item[1]}"`; }) .join(","); urlSpread = JSON.parse("{" + urlSpread + "}"); return urlSpread } else { return handleUrlParam(urlSpread) } } return null } catch { return null } } export function handleUrlParam(path) { var url = path.split('?')[1] //获取url中"?"符后的字串 var theRequest = new Object() if (path.includes('?')) { var url = path.split('?')[1] //获取url中"?"符后的字串 let strs = url.split('&') for (var i = 0; i < strs.length; i++) { theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1]) } } return theRequest } const getImageInfo = (images) => { return new Promise((resolve, reject) => { let imageAry = {} images.map((item, index) => { uni.getImageInfo({ src: item, fail: function (res) { imageAry[index] = null if (imageAry.length == images.length) { resolve(imageAry) } }, success: function (res) { imageAry[index] = res if (Object.keys(imageAry).length == images.length) { resolve(imageAry) } } }) }) }) } /** * 获取分享海报 * @param array store 海报素材 * @param string store_name 素材文字 * @param string price 价格 * @param function successFn 回调函数 * * */ export const PosterCanvas = (store, successCallBack) => { uni.showLoading({ title: '海报生成中', mask: true }); getImageInfo([store.image, store.code]).then(res => { let contentHh = 48 * 1.3 const ctx = uni.createCanvasContext('myCanvas') ctx.clearRect(0, 0, 0, 0); const WIDTH = 747 const HEIGHT = 1326; ctx.fillStyle = "#FFFFFF"; ctx.fillRect(0, 0, WIDTH, HEIGHT); ctx.drawImage(res[0].path, 0, 0, WIDTH, WIDTH); ctx.drawImage(res[1].path, 40, 1064, 200, 200); ctx.save(); let r = 90; let d = r * 2; let cx = 40; let cy = 990; ctx.arc(cx + r, cy + r, r, 0, 2 * Math.PI); ctx.clip(); ctx.restore(); ctx.setTextAlign('center'); ctx.setFontSize(48); ctx.setFillStyle('#000'); ctx.fillText(store.title, WIDTH / 2, 810 + contentHh); ctx.setTextAlign('center') ctx.setFontSize(32); ctx.setFillStyle('red'); ctx.fillText('¥' + store.price, WIDTH / 2, 985); ctx.setTextAlign('center') ctx.setFontSize(22); ctx.setFillStyle('#333333'); ctx.fillText('长按识别二维码立即购买', WIDTH / 2, 1167); ctx.save(); ctx.draw(true, () => { uni.canvasToTempFilePath({ canvasId: 'myCanvas', fileType: 'png', destWidth: WIDTH, destHeight: HEIGHT, success: function (res) { uni.hideLoading(); successCallBack && successCallBack(res.tempFilePath); }, fail: function (error) { }, }) }); }) // uni.getImageInfo({ // src: store.image, // fail: function (res) { // uni.showToast({ // title: '海报生成失败', // icon: "none", // duration: 2000 // }); // }, // success: function (res) { // } // }) } export const handleLoginFailure = () => { store.commit("logout"); store.commit("updateAuthorization", false); let currentPageUrl = getCurrentPageUrl() // token 失效 // 判断当前是不是已经在登录页面或者授权页,防止二次跳转 if (store.getters.isAuthorizationPage || getCurrentPageUrl() == '/pages/user/Login/index') { return } store.commit("updateAuthorizationPage", true); let path = '/' + getCurrentPageUrlWithArgs() let qrCode = handleQrCode() if (qrCode) { // 当前是通过海报扫描进入的 // 判断是不是拼团进来的 if (currentPageUrl == 'pages/activity/GroupRule/index') { if (qrCode.pinkId) { path = parseUrl({ path: `/${currentPageUrl}`, query: { id: qrCode.pinkId, }, }) if (qrCode.spread) { cookie.set('spread', qrCode.spread || 0) } } else { handleNoParameters() } } // 判断是不是扫描的砍价海报进来的 if (currentPageUrl == 'pages/activity/DargainDetails/index') { if (qrCode.bargainId) { path = parseUrl({ path: `/${currentPageUrl}`, query: { id: qrCode.bargainId, partake: qrCode.uid, }, }) if (qrCode.spread) { cookie.set('spread', qrCode.spread || 0) } } else { handleNoParameters() } } if (currentPageUrl == 'pages/shop/GoodsCon/index') { if (qrCode.productId) { path = parseUrl({ path: `/${currentPageUrl}`, query: { id: qrCode.productId, }, }) if (qrCode.spread) { cookie.set('spread', qrCode.spread || 0) } } else { handleNoParameters() } } } routerPermissions(path, 'reLaunch') } const handleNoParameters = () => { uni.showToast({ title: '未获取到必要参数,即将跳转首页', icon: 'success', duration: 2000 }) setTimeout(() => { clearTimeout() switchTab({ path: '/pages/home/index', }); }, 1500) } export function chooseImage(callback) { uni.chooseImage({ count: 1, //sourceType: ["album"], success: res => { uni.getImageInfo({ src: res.tempFilePaths[0], success: image => { uni.showLoading({ title: "图片上传中", mask: true }); uni.uploadFile({ url: `${VUE_APP_API_URL}/api/upload`, file: image, filePath: image.path, header: { Authorization: "Bearer " + store.getters.token }, name: "file", success: res => { if (callback) { callback(JSON.parse(res.data).link) } }, fail: err => { uni.showToast({ title: "上传图片失败" + err, icon: "none", duration: 2000 }); }, complete: res => { uni.hideLoading() } }); }, fail: err => { uni.showToast({ title: "获取图片信息失败", icon: "none", duration: 2000 }); } }); } }); } export function chooseVideoToUpload(callback) { uni.chooseVideo({ count: 1, sourceType: ['album', 'camera'], success: res => { const { tempFilePath, size } = res if (size / 1024 / 1024 > 30) { uni.showToast({ title: '视频文件超过30MB', icon: 'none', duration: 2000 }) return } uni.showLoading({ title: '视频上传中', mask: true }) uni.uploadFile({ url: `${VUE_APP_API_URL}/api/upload`, filePath: tempFilePath, header: { Authorization: 'Bearer ' + store.getters.token }, name: 'file', success: response => { if (callback) { callback(JSON.parse(response.data).link) } }, fail: err => { uni.showToast({ title: '上传视频失败' + err, icon: 'none', duration: 2000 }) }, complete: () => { uni.hideLoading() } }) } }) } export function moreImage(count, callback) { uni.chooseImage({ count, success: res => { let total = res.tempFilePaths.length; for (let i = 0; i < res.tempFilePaths.length; i++) { uni.getImageInfo({ src: res.tempFilePaths[i], success: image => { uni.showLoading({ title: "图片上传中", mask: true }); uni.uploadFile({ url: `${VUE_APP_API_URL}/api/upload`, file: image, filePath: image.path, header: { Authorization: "Bearer " + store.getters.token }, name: "file", success: res => { if (callback) { callback(JSON.parse(res.data).link, total) } }, fail: err => { uni.showToast({ title: "上传图片失败" + err, icon: "none", duration: 2000 }); }, complete: () => { if (i + 1 === total) { uni.hideLoading(); } } }); }, fail: () => { uni.showToast({ title: "获取图片信息失败", icon: "none", duration: 2000 }); } }) } } }); } export function uploadImage(imgPath, callback) { uni.getImageInfo({ src: imgPath, success: image => { uni.showLoading({ title: "图片上传中", mask: true }); uni.uploadFile({ url: `${VUE_APP_API_URL}/api/upload`, file: image, filePath: image.path, header: { Authorization: "Bearer " + store.getters.token }, name: "file", success: res => { if (callback) { callback(JSON.parse(res.data).link) } }, fail: err => { uni.showToast({ title: "上传图片失败" + err, icon: "none", duration: 2000 }); }, complete: res => { uni.hideLoading() } }); }, fail: err => { uni.showToast({ title: "获取图片信息失败", icon: "none", duration: 2000 }); } }); }