diff --git a/App.vue b/App.vue index 0262afd..02c7786 100644 --- a/App.vue +++ b/App.vue @@ -1,13 +1,13 @@ diff --git a/config/api/user.js b/config/api/user.js new file mode 100644 index 0000000..64da98b --- /dev/null +++ b/config/api/user.js @@ -0,0 +1,4 @@ +const proxyUrl = '/tall/v1.0'; + +// 登录api +export const SIGN_IN = `${proxyUrl}/users/signin`; diff --git a/config/config.default.js b/config/config.default.js new file mode 100644 index 0000000..86530ce --- /dev/null +++ b/config/config.default.js @@ -0,0 +1 @@ +export const ERR_CODE = 200; diff --git a/config/config.user.js b/config/config.user.js new file mode 100644 index 0000000..34c05d9 --- /dev/null +++ b/config/config.user.js @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2020. + * author: wally + * email: 18603454788@163.com + */ + +// 用户登录client +export const SIGN_IN_CLIENTS = { mp: 0, h5: 1, android: 2, ios: 3 }; + +// 用户登录类型 +export const SIGN_IN_TYPES = { + mp: 0, + phone: 1, + email: 2, + username: 3, + wx: 4, + wx_web: 5, + wb: 6, +}; diff --git a/main.js b/main.js index f0cc62c..484f4dc 100644 --- a/main.js +++ b/main.js @@ -2,19 +2,20 @@ import Vue from 'vue'; import moment from 'moment'; import { http } from 'plugins/request/index'; import App from './App'; -// import store from './store'; +import store from './store'; Vue.config.productionTip = false; Vue.prototype.$http = http; Vue.prototype.$moment = moment; + +moment.locale('zh-cn'); + Vue.prototype.goHome = () => { uni.reLaunch({ url: '/pages/index/index', }); }; -moment.locale('zh-cn'); - /** * 打开某个页面 * @param {string} path 页面完成路径 @@ -28,7 +29,7 @@ Vue.prototype.openPage = function(path, query = '') { App.mpType = 'app'; const app = new Vue({ - // store, + store, ...App, }); app.$mount(); diff --git a/pages/sign/sign.vue b/pages/sign/sign.vue index 96b5cce..7d69e59 100644 --- a/pages/sign/sign.vue +++ b/pages/sign/sign.vue @@ -59,8 +59,8 @@ export default { } } catch (error) { console.log('error: ', error); - if (error.data) { - uni.showToast({ title: error.data.msg || '打卡失败', icon: 'none' }); + if (error.msg) { + uni.showToast({ title: error.msg || '打卡失败', icon: 'none' }); } } }, diff --git a/plugins/request/index.js b/plugins/request/index.js index 05f7582..8da73a3 100755 --- a/plugins/request/index.js +++ b/plugins/request/index.js @@ -1,93 +1,105 @@ -import { BASE_URL, ERR_CODE } from 'api/base'; +import { BASE_URL, ERR_CODE } from 'api/base'; import Request from './request'; -const test = new Request(); - -/** - * 获取token - * @return {string} 本地保存的token - */ +const test = new Request(); + +/** + * 获取token + * @return {string} 本地保存的token + */ export const getToken = () => uni.getStorageSync('token'); -test.setConfig((config) => { /* 设置全局配置 */ - config.baseUrl = BASE_URL; +test.setConfig(config => { + /* 设置全局配置 */ + config.baseUrl = BASE_URL; config.header = { ...config.header, - } - return config -}) + }; + return config; +}); -test.interceptor.request((config, cancel) => { /* 请求之前拦截器 */ +test.interceptor.request((config, cancel) => { + /* 请求之前拦截器 */ config.header = { ...config.header, - } + }; /* if (!token) { // 如果token不存在,调用cancel 会取消本次请求,但是该函数的catch() 仍会执行 cancel('token 不存在') // 接收一个参数,会传给catch((err) => {}) err.errMsg === 'token 不存在' } */ - return config -}) + return config; +}); /** * 自定义验证器,如果返回true 则进入响应拦截器的响应成功函数(resolve),否则进入响应拦截器的响应错误函数(reject) * @param { Number } statusCode - 请求响应体statusCode(只读) * @return { Boolean } 如果为true,则 resolve, 否则 reject */ -test.validateStatus = (statusCode) => { - return statusCode === ERR_CODE -} +test.validateStatus = statusCode => { + return statusCode === ERR_CODE; +}; -test.interceptor.response((response) => { /* 请求之后拦截器 */ - return response -}, (response) => { // 请求错误做点什么 - return response -}) +test.interceptor.response( + response => { + /* 请求之后拦截器 */ + return response; + }, + response => { + // 请求错误做点什么 + return response; + }, +); -const http = new Request() +const http = new Request(); -http.setConfig((config) => { // 设置全局配置 - config.baseUrl = BASE_URL; // 根域名不同 - - config.header = { - ...config.header, +http.setConfig(config => { + // 设置全局配置 + config.baseUrl = BASE_URL; // 根域名不同 + + config.header = { + ...config.header, }; - return config -}) + return config; +}); /** * 自定义验证器,如果返回true 则进入响应拦截器的响应成功函数(resolve),否则进入响应拦截器的响应错误函数(reject) * @param { Number } statusCode - 请求响应体statusCode(只读) * @return { Boolean } 如果为true,则 resolve, 否则 reject */ -http.validateStatus = (statusCode) => { - return statusCode === ERR_CODE -} +http.validateStatus = statusCode => { + return statusCode === ERR_CODE; +}; -http.interceptor.request((config, cancel) => { /* 请求之前拦截器 */ - const token = getToken() ? { Authorization: `Bearer ${getToken()}` } : {}; +http.interceptor.request((config, cancel) => { + /* 请求之前拦截器 */ + const token = getToken() ? { Authorization: `Bearer ${getToken()}` } : {}; config.header = { ...config.header, ...token, - } + }; /* if (!token) { // 如果token不存在,调用cancel 会取消本次请求,但是该函数的catch() 仍会执行 cancel('token 不存在') // 接收一个参数,会传给catch((err) => {}) err.errMsg === 'token 不存在' } */ - return config -}) + return config; +}); -http.interceptor.response((response) => { /* 请求之后拦截器 */ - if (response.data.code !== ERR_CODE) { // 服务端返回的状态码不等于200,则reject() - return Promise.reject(response) - } - return response -}, (response) => { // 请求错误做点什么 - return response -}) +http.interceptor.response( + response => { + /* 请求之后拦截器 */ + if (response.data.code !== ERR_CODE) { + // 服务端返回的状态码不等于200,则reject() + return Promise.reject(response.data); + } + return response; + }, + response => { + // 请求错误做点什么 + return response; + }, +); -export { - http, - test -} +export { http, test }; diff --git a/store/index.js b/store/index.js index e69de29..dead1fe 100644 --- a/store/index.js +++ b/store/index.js @@ -0,0 +1,10 @@ +import Vue from 'vue'; +import Vuex from 'vuex'; +import user from './modules/user/index'; + +Vue.use(Vuex); +const store = new Vuex.Store({ + modules: { user }, +}); + +export default store; diff --git a/store/modules/user/actions.js b/store/modules/user/actions.js new file mode 100644 index 0000000..c0f1623 --- /dev/null +++ b/store/modules/user/actions.js @@ -0,0 +1,39 @@ +import { showModal } from 'utils/ui'; +import { mpLogin, signIn } from 'utils/user'; + +const actions = { + // 登录 + login({ commit }) { + return new Promise((resolve, reject) => { + // #ifdef MP-WEIXIN + mpLogin() + .then(params => signIn(params)) + .then(data => { + commit('setToken', data.token); + commit('setUser', data); + resolve(data); + }) + .catch(err => { + showModal(err.msg || '登录失败'); + reject(err); + }); + // #endif + }); + }, + + /** + * signIn 提交登录信息 + * @param {any} commit + * @param {string} params 登录提交的参数 + */ + signIn({ commit }, params) { + return signIn(params) + .then(data => { + commit('setToken', data.token); + commit('setUser', data); + }) + .catch(err => showModal(err)); + }, +}; + +export default actions; diff --git a/store/modules/user/index.js b/store/modules/user/index.js new file mode 100644 index 0000000..e67cdeb --- /dev/null +++ b/store/modules/user/index.js @@ -0,0 +1,5 @@ +import state from './state'; +import mutations from './mutations'; +import actions from './actions.js'; + +export default { namespaced: true, state, actions, mutations }; diff --git a/store/modules/user/mutations.js b/store/modules/user/mutations.js new file mode 100644 index 0000000..8d4ae24 --- /dev/null +++ b/store/modules/user/mutations.js @@ -0,0 +1,39 @@ +const mutations = { + /** + * 设置存储token + * @param {object} state + * @param {string} token + */ + setToken(state, token) { + if (!token) return; + state.token = token; + uni.setStorageSync('token', token); + }, + + /** + * 设置user数据 + * @param {object} state + * @param {object} user + */ + setUser(state, user) { + if (!user) return; + state.user = { ...user }; + uni.setStorageSync('user', JSON.stringify(user)); + }, + + /** + * 更新手机号 + * @param {*} state + * @param {object} option + * @param {string} option.type 修改的数据的key + * @param {any} option.value 新数据的值 + */ + updateUser(state, { type, value }) { + const { user } = state; + user[type] = value; + state.user = { ...user }; + uni.setStorageSync('user', JSON.stringify(user)); + }, +}; + +export default mutations; diff --git a/store/modules/user/state.js b/store/modules/user/state.js new file mode 100644 index 0000000..82c9f22 --- /dev/null +++ b/store/modules/user/state.js @@ -0,0 +1,6 @@ +const state = { + token: '', + user: null, +}; + +export default state; diff --git a/utils/ui.js b/utils/ui.js new file mode 100644 index 0000000..378b1dc --- /dev/null +++ b/utils/ui.js @@ -0,0 +1,31 @@ +/** + * 显示模态框 + * @param {string} msg + * @param {boolean} showCancel + * @param {string} confirmText + */ +export const showModal = (msg, showCancel = false, confirmText = '知道了') => + uni.showModal({ + title: '提示', + content: msg, + showCancel, + confirmText, + confirmColor: '#1890ff', + }); + +/** + * 显示toast + * @param {string} msg + */ +export const showToast = msg => + uni.showToast({ + title: msg, + icon: 'none', + duration: 3000, + }); + +// 显示加载动画 +export const showLoading = (msg = '努力加载中...') => uni.showLoading({ title: msg }); + +// 隐藏加载动画 +export const hideLoading = () => uni.hideLoading(); diff --git a/utils/user.js b/utils/user.js new file mode 100644 index 0000000..88871ae --- /dev/null +++ b/utils/user.js @@ -0,0 +1,110 @@ +import { SIGN_IN } from 'api/user'; +import { ERR_CODE } from 'config/config.default'; +import { http as axios } from 'plugins/request/index'; +import { SIGN_IN_CLIENTS, SIGN_IN_TYPES } from 'config/config.user'; + +/** + * 保存token + * @param {string} token 服务端返回的token数据 + */ +export const setToken = token => { + uni.setStorageSync('anyringToken', token); +}; + +/** + * 获取token + * @return {string} 本地保存的token + */ +export const getToken = () => uni.getStorageSync('anyringToken'); + +/** + * 提交登录信息 + * @param {object} params 提交的参数 + */ +export const signIn = params => { + return new Promise((resolve, reject) => { + axios + .post(SIGN_IN, params) + .then(res => { + const { success, code, data, msg } = res.data; + if (success && code === ERR_CODE) { + if (!data || !data.token) { + reject('服务端返回数据不正确'); + } else { + resolve(data); + } + } else { + reject(`登录请求失败 ${msg}`); + } + }) + .catch(err => { + reject(err); + }); + }); +}; + +// 微信登录 +export const wxLogin = () => { + return new Promise((resolve, reject) => { + uni.login({ + provider: 'weixin', + success(response) { + if (response.code) { + const params = { + client: SIGN_IN_CLIENTS['mp'], + type: SIGN_IN_TYPES['mp'], + data: { identifier: response.code }, + redirect: 'https://test.tall.wiki/gateway/health/initMsg', + }; + resolve(params); + } else { + reject(response.errMsg); + } + }, + fail() { + console.log('fail'); + reject('微信登录失败'); + }, + }); + }); +}; + +// 微信登录 +export const wxWorkLogin = () => { + return new Promise((resolve, reject) => { + wx.qy.login({ + provider: 'weixin', + success(response) { + if (response.code) { + const params = { + client: SIGN_IN_CLIENTS['mp'], + type: SIGN_IN_TYPES['mp'], + data: { identifier: response.code }, + redirect: 'https://test.tall.wiki/gateway/health/initMsg', + }; + resolve(params); + } else { + reject(response.errMsg); + } + }, + fail() { + console.log('fail'); + reject('微信登录失败'); + }, + }); + }); +}; + +// 小程序登录 +export const mpLogin = () => { + try { + const res = uni.getSystemInfoSync(); + if (res.environment === 'wxwork') { + return wxWorkLogin(); + } else { + return wxLogin(); + } + } catch (err) { + console.log('err: ', err); + } +};