- 第一阶段的登录虽然也算完成了,但是并不是最优的登陆方式
- 后面有了新的思路可以在路由守卫里面进行操作
- 下面先记录一下思路,回顾一下
1.重构一下router模块
在router模块下面有一个index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import store from '@/store'
import homeRouter from './modules/home'
import clientRouter from './modules/client'
import couponRouter from './modules/coupon'
import seaRouter from './modules/sea'
import projectRouter from './modules/project'
import userRouter from './modules/user'
import { axUrl, appid } from '@/utils/api_env'
import { getToken, setToken, removeToken } from '@/utils/auth'
// 导入组件
const Login = () => import('@/views/Login/Login.vue')
const WeChatLogin = () => import('@/views/Login/WeChatLogin.vue')
const Layout = () => import('@/views/Layout/Layout.vue')
const Home = () => import('@/views/Home/Home.vue')
const User = () => import('@/views/User/User.vue')
const HighSea = () => import('@/views/HighSea/index.vue')
const Client = () => import('@/views/Client/index.vue')
const Project = () => import('@/views/Project/index.vue')
const Data = () => import('@/views/Data/index.vue')
Vue.use(VueRouter)
const routes = [
// 登录组件的路由规则
{ path: '/login', component: Login, name: 'login' },
{ path: '/weChatLogin', component: WeChatLogin, name: 'weChatLogin' },
{
path: '/',
component: Layout,
// redirect: '/home',
children: [
// 默认子路由
{ path: '/home', component: Home, name: 'home' },
{ path: '/user', component: User, name: 'user' },
{ path: '/highSea', component: HighSea, name: 'highSea' },
{ path: '/client', component: Client, name: 'client' },
{ path: '/project', component: Project, name: 'project' },
{ path: '/data', component: Data, name: 'data' },
],
},
...homeRouter,
...clientRouter,
...couponRouter,
...seaRouter,
...projectRouter,
...userRouter
]
const router = new VueRouter({
routes,
})
function isIos () {
const u = navigator.userAgent
return u.indexOf('iPhone') > -1 || u.indexOf('Mac OS') > -1
}
// 获取真实有效微信签名URL encodeURIComponent
function getWechatSignUrl (to) {
if (!isIos()) {
return axUrl + '#' + to.path
} else {
// 此处$appHost需要自行处理
return axUrl + '#' + to.path
}
}
const getQuery = name => {
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
var r = window.location.search.substr(1).match(reg)
if (r != null) {
return unescape(r[2])
}
return null
}
const pathNext = (to, next) => {
if (to.path === '/') {
store.commit('setWechatSignUrl/setWechatSignUrl', getWechatSignUrl(to))
next('/home')
} else {
store.commit('setWechatSignUrl/setWechatSignUrl', getWechatSignUrl(to))
next()
}
}
let suite_access_token = null
let open_userid = null
let user_ticket = null
let userToken = null
// 路由守卫
router.beforeEach(async (to, from, next) => {
if (to.meta.title) {
document.title = to.meta.title
}
window.console.log('我是无感授权第60版', 1)
if (to.path === '/login') {
next()
} else {
userToken = getToken()
if (!userToken) {
window.console.log('Token', userToken)
if (!store.state.setWechatSignUrl.wechatOptions.userid) {
// 第一次获取code
if (getQuery('code')) {
const { data, code } = await store.dispatch('setWechatSignUrl/getAuth', {
code: getQuery('code')
})
window.console.log('我是无感授权第60版', 2, data, code)
suite_access_token = data.suite_access_token
if (code == 200) {
const { data, code } = await store.dispatch('setWechatSignUrl/getUserInfo', {
code: getQuery('code'),
suite_access_token: suite_access_token
})
// 在授权账户没有绑定手机号时候,先设置一下数据
store.commit('setWechatSignUrl/SET_USER_INFO', data)
window.console.log('我是无感授权第60版', 3, data, code)
open_userid = data.open_userid
user_ticket = data.user_ticket
if (code == 200) {
const { data, code } = await store.dispatch('setWechatSignUrl/getUserCheck', open_userid)
window.console.log('我是无感授权第60版code', 4, data, code)
userToken = data.userToken
// const ErrCode = 10003 // TODO:这里测试完要删掉的 和request里面的要关联起来
if (code == 10003) {
window.console.log('我是哪个,code,data', data, code);
next('/login')
} else {
store.commit('setWechatSignUrl/SET_TOKEN', userToken)
setToken(userToken)
const { data, code } = await store.dispatch('setWechatSignUrl/getUserDetail', {
suite_access_token: suite_access_token,
user_ticket: user_ticket
})
window.console.log('userInfoData', data, code);
store.commit('setWechatSignUrl/SET_USER_INFO', data)
}
}
}
pathNext(to, next)
window.console.log('我走了login2');
} else {
const { data: res} = await store.dispatch('setWechatSignUrl/getCode')
window.console.log('我是无感授权第60版', 5, res)
window.location.href = res.redirectUrl
}
} else {
pathNext(to, next)
}
} else {
pathNext(to, next)
}
}
})
export default router
2.在utils/api_env
里面定义一下我们的环境
const baseApiEnv = () => {
switch (process.env.NODE_ENV) {
case 'development':
return {
baseUrl: '/api', // 填写开发环境代理地址
axUrl: 'https://xxxxxx.cn/', // 域名
appid: 'wwxxxx' // xx
}
case 'production':
return {
baseUrl: '/prod-api', // 填写生产环境代理地址
axUrl: 'https://tesxxxx.cn/', // 域名
appid: 'ww2xxx7' // xx
}
case 'test':
return {
baseUrl: '/prod-api', // 填写测试环境代理地址
axUrl: 'https://testxxx.cn/', // 域名
appid: 'wwxxxx' // x
}
default:
return {
baseUrl: '',
axUrl: '',
appid: ''
}
}
}
export const { baseUrl, axUrl, appid } = baseApiEnv()
3.在utils/auth
里面定义一下我们的token设置和获取
- 注意这里需要去下载cookie依赖
import Cookies from 'js-cookie'
const TokenKey = 'userToken'
export function getToken() {
return Cookies.get(TokenKey)
}
export function setToken(token) {
// return Cookies.set(TokenKey, token)
Cookies.set(TokenKey, token)
}
export function removeToken() {
Cookies.remove(TokenKey)
}
4.在utils/request
里面重构一下我们的响应拦截器和请求拦截器
import axios from 'axios'
import store from '@/store/index'
import JSONbig from 'json-bigint'
import router from '@/router/index'
import { Toast, Dialog} from 'vant';
import { baseUrl, axUrl, appid } from '@/utils/api_env'
import { getToken, removeToken } from '@/utils/auth'
// 处理大数问题
const transBigInt = data => {
if (!data) return ''
try {
return JSONbig.parse(data)
} catch {
return JSON.parse(data)
}
}
const instance = axios.create({
// 请求根路径
baseURL: process.env.VUE_APP_BASE_API,
transformResponse: [transBigInt],
// 设置超时时间
timeout: 10000,
headers: {
'Cache-Control': 'no-cache'
}
})
// post请求的时候,我们需要加上一个请求头,所以可以在这里进行一个默认的设置
// 即设置post的请求头为application/x-www-form-urlencoded;charset=UTF-8
instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
let toast = null
// 请求拦截器
instance.interceptors.request.use(
(config) => {
// 获取 token 值
const token = getToken()
// const token = store.state.setWechatSignUrl.token ? store.state.setWechatSignUrl.token : false
if (token) config.headers['userToken'] = token
if (config.headers.loading !== false) {
toast = Toast.loading({
duration: 3000, // 持续展示 toast
message: '加载中...',
forbidClick: true,
loadingType: 'spinner'
})
}
if (config.method === 'get') {
config.params = {
...config.params,
_t: Date.parse(new Date()) / 1000,
}
}
return config
},
function(error) {
toast && toast.clear()
return Promise.reject(error)
}
)
// 响应拦截器
instance.interceptors.response.use(
res => {
toast && toast.clear()
// const ErrCode = 10003
// if (ErrCode == 10003) { // TODO:这里测试完要删掉的 和route里面的要关联起来
if (res.data.code == 10003) {
removeToken()
store.commit('setWechatSignUrl/SET_USER_INFO', {})
// 清除token
router.push({
path: '/login',
})
} else if (res.data.code == 500) {
errorMsg(res.data.msg)
} else {
if (res.data.code != 200) {
Dialog.confirm({
title: '提示',
message: '请重新授权'
})
.then(() => {
// on confirm
// token失效,清除本地token, 跳转授权重新取code
store.dispatch('setWechatSignUrl/clearToken')
removeToken()
const wechatUrl = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxxxxx&redirect_uri=https%3A%2F%2F你的地址.xxx.cn&response_type=code&scope=snsapi_privateinfo&state=STATE#wechat_redirect`
window.location.href = wechatUrl
})
.catch(() => {
console.log('取消操作')
})
} else {
return Promise.resolve(res.data || {})
}
}
},
(error) => {
// 服务器返回不是 2 开头的情况,会进入这个回调
// 可以根据后端返回的状态码进行不同的操作
const responseCode = error.response.status
switch (responseCode) {
// 401:未登录
case 401:
// 跳转登录页
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath,
},
})
break
// 403: token过期
case 403:
// 弹出错误信息
// errorMsg("登录信息过期,请重新登录");
// 清除token
localStorage.removeItem('token')
// 跳转登录页面,并将要浏览的页面fullPath传过去,登录成功后跳转需要访问的页面
setTimeout(() => {
router.replace({
path: '/login',
query: {
redirect: router.currentRoute.fullPath,
},
})
}, 1000)
break
// 404请求不存在
case 404:
errorMsg('网络请求不存在')
break
// 500:yuangongbu9cunzai
case 500:
errorMsg(error.response.data.msg)
break
// 其他错误,直接抛出错误提示
default:
errorMsg(error.response.data.msg)
}
return Promise.reject(error.data || error)
}
)
const errorMsg = (msg) => {
const dom = document.getElementsByClassName('el-message--error') // TODO:要改的提示信息
if (dom.length <= 0) {
Toast({
message: msg || '网络异常',
type: 'error',
})
}
}
export default instance
5.在store/index.js
里面重构一下我们的Vuex
import Vue from 'vue'
import Vuex from 'vuex'
import getters from './getters'
Vue.use(Vuex)
const modulesFiles = require.context('./modules', true, /\.js$/)
// it will auto require all vuex module from modules file
const modules = modulesFiles.keys().reduce((modules, modulePath) => {
// set './xx.js' => 'xx'
const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')
const value = modulesFiles(modulePath)
modules[moduleName] = value.default
return modules
}, {})
const store = new Vuex.Store({
modules,
getters
})
export default store
- 设置modules
定义一个setWechatSignUrl.js
import {getLogin, getSuiteAccessToken, getCompanyUserInfo, userCheck, getCompanyUserDetail, bindMobileByCode} from '@/api/wechat'
import { getToken, setToken, removeToken } from '@/utils/auth'
// 全局判断是否IOS方法
function isIos () {
const u = navigator.userAgent
return u.indexOf('iPhone') > -1 || u.indexOf('Mac OS') > -1
}
const state = {
wechatOptions: {
corpid: '',
userid: '',
name: '',
gender: '',
avatar: '',
qr_code: ''
},
token: '',
wechatSignUrl: '',
isAndroid:
navigator.userAgent.indexOf('Android') > -1 ||
navigator.userAgent.indexOf('Linux') > -1,
isIOS: !!navigator.userAgent.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/) // ios终端
}
const mutations = {
setWechatSignUrl: (state, wxSignUrl) => {
// 关键点
// IOS仅记录第一次进入页面时的URL
// IOS微信切换路由实际URL不变,只能使用第一进入页面的URL进行签名
// if (isIos() && state.wechatSignUrl !== '') {
// return
// }
state.wechatSignUrl = wxSignUrl
},
SET_USER_INFO: (state, params) => {
state.wechatOptions = Object.assign({}, state.wechatOptions, params)
},
SET_TOKEN: (state, params) => {
state.token = params
},
CLEAR_USER: state => {
state.wechatOptions = {}
}
}
const actions = {
// 1.获取授权链接
getCode ({ commit, state, dispatch }, params) {
return getLogin(params)
},
// 2.授权token
getAuth ({ commit, state, dispatch }, params) {
return getSuiteAccessToken(params)
},
// 3.获取信息
getUserInfo({ commit, state, dispatch }, params) {
return getCompanyUserInfo({params})
},
// 4.user login userCheck
getUserCheck({ commit }, userInfo) {
const open_userid = userInfo
return userCheck({open_userid})
},
// 5.获取访问用户敏感信息
getUserDetail({ commit, state, dispatch }, params) {
return getCompanyUserDetail({params})
},
// 6.如果是没有绑定过手机号就走这里 user wechatlogin
wechatLogin({ commit, state, dispatch }, userInfo) {
return bindMobileByCode(userInfo)
},
}
export default {
namespaced: true,
state,
mutations,
actions
}
- 然后为了便捷操作设置
getters.js
const getters = {
sidebar: state => state.app.sidebar,
device: state => state.app.device,
token: state => state.user.token,
avatar: state => state.user.avatar,
name: state => state.user.user_name,
part_id: state => state.user.part_id,
btnName: state => state.app.btnName,
user_id: state => state.user.id,
pre_path: state => state.path.pre_path,
getWechatUrl: state => state.setWechatSignUrl.wechatSignUrl,
wechattoken: state => state.setWechatSignUrl.token,
wechatOptions: state => state.setWechatSignUrl.wechatOptions
}
export default getters