From 55ee2fcad7f1c5a30b4b747d8f4e48898f7766c6 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Thu, 25 Nov 2021 07:57:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=99=BB=E9=99=86=E7=95=8C?= =?UTF-8?q?=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-vue-ui/common/js/util.js | 47 +++ yudao-vue-ui/common/mixin/mixin.js | 96 ++++++ yudao-vue-ui/main.js | 26 ++ yudao-vue-ui/pages.json | 16 +- yudao-vue-ui/pages/auth/login.vue | 323 ++++++++++++++++++ yudao-vue-ui/pages/auth/mixin/login-app-wx.js | 73 ++++ yudao-vue-ui/pages/auth/mixin/login-apple.js | 83 +++++ yudao-vue-ui/pages/auth/mixin/login-mp-wx.js | 81 +++++ yudao-vue-ui/pages/set/userInfo.vue | 248 ++++++++++++++ yudao-vue-ui/pages/tabbar/user.vue | 2 +- yudao-vue-ui/store/index.js | 93 +++++ 11 files changed, 1086 insertions(+), 2 deletions(-) create mode 100644 yudao-vue-ui/common/js/util.js create mode 100644 yudao-vue-ui/common/mixin/mixin.js create mode 100644 yudao-vue-ui/pages/auth/login.vue create mode 100644 yudao-vue-ui/pages/auth/mixin/login-app-wx.js create mode 100644 yudao-vue-ui/pages/auth/mixin/login-apple.js create mode 100644 yudao-vue-ui/pages/auth/mixin/login-mp-wx.js create mode 100644 yudao-vue-ui/pages/set/userInfo.vue create mode 100644 yudao-vue-ui/store/index.js diff --git a/yudao-vue-ui/common/js/util.js b/yudao-vue-ui/common/js/util.js new file mode 100644 index 000000000..13ab716a9 --- /dev/null +++ b/yudao-vue-ui/common/js/util.js @@ -0,0 +1,47 @@ +let _debounceTimeout = null, + _throttleRunning = false + +/** + * 防抖 + * 参考文章 https://juejin.cn/post/6844903669389885453 + * + * @param {Function} 执行函数 + * @param {Number} delay 延时ms + */ +export const debounce = (fn, delay=500) => { + clearTimeout(_debounceTimeout); + _debounceTimeout = setTimeout(() => { + fn(); + }, delay); +} + +/** + * 节流 + * 参考文章 https://juejin.cn/post/6844903669389885453 + * + * @param {Function} 执行函数 + * @param {Number} delay 延时ms + */ +export const throttle = (fn, delay=500) => { + if(_throttleRunning){ + return; + } + _throttleRunning = true; + fn(); + setTimeout(() => { + _throttleRunning = false; + }, delay); +} + +/** + * toast + */ +export const msg = (title = '', param={}) => { + if(!title) return; + uni.showToast({ + title, + duration: param.duration || 1500, + mask: param.mask || false, + icon: param.icon || 'none' + }); +} \ No newline at end of file diff --git a/yudao-vue-ui/common/mixin/mixin.js b/yudao-vue-ui/common/mixin/mixin.js new file mode 100644 index 000000000..701d70222 --- /dev/null +++ b/yudao-vue-ui/common/mixin/mixin.js @@ -0,0 +1,96 @@ +// import {request} from '@/common/js/request' + +export default{ + data() { + return { + page: 0, // 页码 + pageNum: 6, // 每页加载数据量 + loadingType: 1, // 加载类型。0 加载前;1 加载中;2 没有更多 + isLoading: false, // 刷新数据 + loaded: false, // 加载完毕 + } + }, + methods: { + /** + * 打印日志,方便调试 + * + * @param {Object} data 数据 + */ + log(data) { + console.log(JSON.parse(JSON.stringify(data))) + }, + + /** + * navigatorTo 跳转页面 + * + * @param {String} url + * @param {Object} options 可选参数 + * @param {Boolean} options.login 是否检测登录 + */ + navTo(url, options={}) { + this.$util.throttle(() => { + if (!url) { + return; + } + // 如果需要登陆,并且未登陆,则跳转到登陆界面 + if ((~url.indexOf('login=1') || options.login) && !this.$store.getters.hasLogin){ + url = '/pages/auth/login'; + } + // 跳转到指定 url 地址 + uni.navigateTo({ + url + }) + }, 300) + }, + + /** + * $request云函数请求 TODO 芋艿:需要改成自己的 + * @param {String} module + * @param {String} operation + * @param {Boolean} data 请求参数 + * @param {Boolean} ext 附加参数 + * @param {Boolean} ext.showLoading 是否显示loading状态,默认不显示 + * @param {Boolean} ext.hideLoading 是否关闭loading状态,默认关闭 + * @param {Boolean} ext.login 未登录拦截 + * @param {Boolean} ext.setLoaded 加载完成是设置页面加载完毕 + */ + $request(module, operation, data={}, ext={}){ + if(ext.login && !this.$util.isLogin()){ + return; + } + if(ext.showLoading){ + this.isLoading = true; + } + return new Promise((resolve, reject)=> { + request(module, operation, data, ext).then(result => { + if(ext.hideLoading !== false){ + this.isLoading = false; + } + setTimeout(()=>{ + if(this.setLoaded !== false){ + this.loaded = true; + } + }, 100) + this.$refs.confirmBtn && this.$refs.confirmBtn.stop(); + resolve(result); + }).catch((err) => { + reject(err); + }) + }) + }, + imageOnLoad(data, key){ // TODO 芋艿:需要改成自己的 + setTimeout(()=>{ + this.$set(data, 'loaded', true); + }, 100) + }, + showPopup(key){ // TODO 芋艿:需要改成自己的 + this.$util.throttle(()=>{ + this.$refs[key].open(); + }, 200) + }, + hidePopup(key){ // TODO 芋艿:需要改成自己的 + this.$refs[key].close(); + }, + stopPrevent(){}, // TODO 芋艿:需要改成自己的 + }, +} \ No newline at end of file diff --git a/yudao-vue-ui/main.js b/yudao-vue-ui/main.js index afc6b0895..565d893ff 100644 --- a/yudao-vue-ui/main.js +++ b/yudao-vue-ui/main.js @@ -1,5 +1,31 @@ import App from './App' +// 全局 Mixin +import mixin from './common/mixin/mixin' +Vue.mixin(mixin) + +// 全局 Util +import { + msg, + isLogin, + debounce, + throttle, + prePage, + date +} from '@/common/js/util' +Vue.prototype.$util = { + msg, + isLogin, + debounce, + throttle, + prePage, + date +} + +// 全局 Store +import store from './store' +Vue.prototype.$store = store + // #ifndef VUE3 import Vue from 'vue' Vue.config.productionTip = false diff --git a/yudao-vue-ui/pages.json b/yudao-vue-ui/pages.json index 1f30ba509..4e14ef627 100644 --- a/yudao-vue-ui/pages.json +++ b/yudao-vue-ui/pages.json @@ -11,7 +11,21 @@ "navigationBarTitleText": "我的", "navigationStyle": "custom" } - } + }, { + "path": "pages/auth/login", + "style": { + "navigationBarTitleText": "登录", + "navigationStyle":"custom", + "app-plus": { + "animationType": "slide-in-bottom" + } + } + }, { + "path" : "pages/set/userInfo", + "style" : { + "navigationBarTitleText": "个人资料" + } + } ], "globalStyle": { "navigationBarTextStyle": "black", diff --git a/yudao-vue-ui/pages/auth/login.vue b/yudao-vue-ui/pages/auth/login.vue new file mode 100644 index 000000000..8667c0da1 --- /dev/null +++ b/yudao-vue-ui/pages/auth/login.vue @@ -0,0 +1,323 @@ + + + + + + diff --git a/yudao-vue-ui/pages/auth/mixin/login-app-wx.js b/yudao-vue-ui/pages/auth/mixin/login-app-wx.js new file mode 100644 index 000000000..834ff87ac --- /dev/null +++ b/yudao-vue-ui/pages/auth/mixin/login-app-wx.js @@ -0,0 +1,73 @@ +export default{ + // #ifdef APP-PLUS + methods: { + /** + * 微信App登录 + * "openId": "o0yywwGWxtBCvBuE8vH4Naof0cqU", + * "nickName": "S .", + * "gender": 1, + * "city": "临沂", + * "province": "山东", + * "country": "中国", + * "avatarUrl": "http://thirdwx.qlogo.cn/mmopen/vi_32/xqpCtHRBBmdlf201Fykhtx7P7JcicIbgV3Weic1oOvN6iaR3tEbuu74f2fkKQWXvzK3VDgNTZzgf0g8FqPvq8LCNQ/132", + * "unionId": "oYqy4wmMcs78x9P-tsyMeM3MQ1PU" + */ + loginByWxApp(userInfoData){ + if(!this.agreement){ + this.$util.msg('请阅读并同意用户服务及隐私协议'); + return; + } + this.$util.throttle(async ()=>{ + let [err, res] = await uni.login({ + provider: 'weixin' + }) + if(err){ + console.log(err); + return; + } + uni.getUserInfo({ + provider: 'weixin', + success: async res=>{ + const response = await this.$request('user', 'loginByWeixin', { + userInfo: res.userInfo, + }, { + showLoading: true + }); + if(response.status === 0){ + this.$util.msg(response.msg); + return; + } + if(response.hasBindMobile && response.data.token){ + this.loginSuccessCallBack({ + token: response.data.token, + tokenExpired: response.data.tokenExpired + }); + }else{ + this.navTo('/pages/auth/bindMobile?data='+JSON.stringify(response.data)) + } + plus.oauth.getServices(oauthRes=>{ + oauthRes[0].logout(logoutRes => { + console.log(logoutRes); + }, error => { + console.log(error); + }) + }) + }, + fail(err) { + console.log(err); + } + }) + }) + } + } + // #endif +} + + + + + + + + + diff --git a/yudao-vue-ui/pages/auth/mixin/login-apple.js b/yudao-vue-ui/pages/auth/mixin/login-apple.js new file mode 100644 index 000000000..c0c98d345 --- /dev/null +++ b/yudao-vue-ui/pages/auth/mixin/login-apple.js @@ -0,0 +1,83 @@ +export default{ + onLoad() { + if(this.systemInfo.platform !== 'ios'){ + return; + } + const systemVersion = +this.systemInfo.system.split('.')[0]; + if(systemVersion >= 13){ + this.canUseAppleLogin = true; + } + }, + methods: { + //苹果登录 + async loginByApple(){ + /* if(!this.canUseAppleLogin){ + this.$util.msg('系统版本过低,无法使用苹果登录'); + return; + } */ + if(!this.agreement){ + this.$util.msg('请阅读并同意用户服务及隐私协议'); + this.$refs.confirmBtn.stop(); + return; + } + uni.login({ + provider: 'apple', + success: loginRes=> { + // 登录成功 + uni.getUserInfo({ + provider: 'apple', + success: async userRes=> { + console.log(userRes); + const response = await this.$request('user', 'loginByApple', { + authorizationCode: userRes.userInfo.authorizationCode, + identityToken: userRes.userInfo.identityToken + }, { + showLoading: true + }); + console.log(response); + //注销苹果登录 + this.appleLogout(); + console.log(response); + if(response.status === 0){ + this.$util.msg(response.msg); + return; + } + if(response.hasBindMobile && response.data.token){ + this.loginSuccessCallBack({ + token: response.data.token, + tokenExpired: response.data.tokenExpired + }); + }else{ + this.navTo('/pages/auth/bindMobile?type=apple&data='+JSON.stringify(response.data)) + } + } + }) + }, + fail: err=> { + console.log(err); + this.$util.msg('登录失败'); + this.appleLogout(); + } + }) + }, + appleLogout(){ + plus.oauth.getServices(oauthRes=>{ + const oIndex = oauthRes.findIndex(oItem=> oItem.id === 'apple'); + oauthRes[oIndex].logout(loRes => { + console.log('appleLogout success=> ', loRes); + }, loErr => { + console.log('appleLogout error=> ', loErr); + }) + }) + } + } +} + + + + + + + + + diff --git a/yudao-vue-ui/pages/auth/mixin/login-mp-wx.js b/yudao-vue-ui/pages/auth/mixin/login-mp-wx.js new file mode 100644 index 000000000..1f4438a86 --- /dev/null +++ b/yudao-vue-ui/pages/auth/mixin/login-mp-wx.js @@ -0,0 +1,81 @@ +export default{ + // #ifdef MP-WEIXIN + data(){ + return { + mpCodeTimer: 0, + mpWxCode: '', + } + }, + computed: { + timerIdent(){ + return this.$store.state.timerIdent; + } + }, + watch: { + timerIdent(){ + this.mpCodeTimer ++; + if(this.mpCodeTimer % 30 === 0){ + this.getMpWxCode(); + } + } + }, + onShow(){ + this.getMpWxCode(); + }, + methods: { + //微信小程序登录 + mpWxGetUserInfo(){ + if(!this.agreement){ + this.$util.msg('请阅读并同意用户服务及隐私协议'); + return; + } + + this.$util.throttle(()=>{ + uni.getUserProfile({ + desc: '用于展示您的头像及昵称', + success: async profileRes=> { + const res = await this.$request('user', 'loginByWeixin', { + code: this.mpWxCode, + ...profileRes.userInfo + }, { + showLoading: true + }); + if(res.status === 0){ + this.$util.msg(res.msg); + return; + } + if(res.hasBindMobile && res.data.token){ + this.loginSuccessCallBack({ + token: res.data.token, + tokenExpired: res.data.tokenExpired + }); + }else{ + this.navTo('/pages/auth/bindMobile?data='+JSON.stringify(res.data)) + } + console.log(res) + } + }) + }) + }, + //获取code + getMpWxCode(){ + uni.login({ + provider: 'weixin', + success: res=> { + this.mpWxCode = res.code; + } + }) + }, + + } + // #endif +} + + + + + + + + + diff --git a/yudao-vue-ui/pages/set/userInfo.vue b/yudao-vue-ui/pages/set/userInfo.vue new file mode 100644 index 000000000..89dcd33a3 --- /dev/null +++ b/yudao-vue-ui/pages/set/userInfo.vue @@ -0,0 +1,248 @@ + + + + + diff --git a/yudao-vue-ui/pages/tabbar/user.vue b/yudao-vue-ui/pages/tabbar/user.vue index db0973537..8e72213bc 100644 --- a/yudao-vue-ui/pages/tabbar/user.vue +++ b/yudao-vue-ui/pages/tabbar/user.vue @@ -59,7 +59,7 @@ - + diff --git a/yudao-vue-ui/store/index.js b/yudao-vue-ui/store/index.js new file mode 100644 index 000000000..afcddc646 --- /dev/null +++ b/yudao-vue-ui/store/index.js @@ -0,0 +1,93 @@ +import Vue from 'vue' +import Vuex from 'vuex' +// import {request} from '@/common/js/request' + +Vue.use(Vuex) + +const store = new Vuex.Store({ + state: { + openExamine: false, // 是否开启审核状态。用于小程序、App 等审核时,关闭部分功能。TODO 芋艿:暂时没找到刷新的地方 + token: '', // 用户身份 Token + userInfo: {}, // 用户基本信息 + timerIdent: false, // 全局 1s 定时器,只在全局开启一个,所有需要定时执行的任务监听该值即可,无需额外开启 TODO 芋艿:需要看看 + orderCount: {}, // 订单数量 + }, + getters: { + hasLogin(state){ + return !!state.token; + } + }, + mutations: { + //更新state数据 + setStateAttr(state, param){ + if(param instanceof Array){ + for(let item of param){ + state[item.key] = item.val; + } + }else{ + state[param.key] = param.val; + } + }, + //更新token + setToken(state, data){ + const {token, tokenExpired} = data; + state.token = token; + uni.setStorageSync('uniIdToken', token); + uni.setStorageSync('tokenExpired', tokenExpired); + this.dispatch('getUserInfo'); //更新用户信息 + this.dispatch('getCartCount');//更新购物车数量 + uni.$emit('refreshCart');//刷新购物车 + this.dispatch('getOrderCount'); //更新订单数量 + }, + // 退出登录 + logout(state) { + state.token = ''; + uni.removeStorageSync('uniIdToken'); + this.dispatch('getCartCount');//更新购物车数量 + uni.$emit('refreshCart');//刷新购物车 + this.dispatch('getOrderCount'); //更新订单数量 + setTimeout(()=>{ + state.userInfo = {}; + }, 1100) + }, + }, + actions: { + //更新用户信息 + async getUserInfo({state, commit}){ + const res = await request('user', 'get', {}, { + checkAuthInvalid: false + }); + if(res.status === 1){ + const userInfo = res.data; + commit('setStateAttr', { + key: 'userInfo', + val: userInfo + }) + } + }, + //更新用户订单数量 + async getOrderCount({state, commit}){ + let data = { + c0: 0, + c1: 0, + c2: 0, + c3: 0 + } + if(state.token){ + try { + const res = await request('order', 'getOrderCount'); + data = res; + }catch (err){ + console.error('更新用户订单数量 => ', err); + } + } + commit('setStateAttr', { + key: 'orderCount', + val: data + }) + } + } +}) + + +export default store