Commit 93352b538617c04c77534cd03168231adb25ad4e

Authored by sfmind
1 parent 671b5d34

完善手机密码登录和Vuex状态管理

yudao-ui-app/App.vue
1 <script> 1 <script>
2 - export default {  
3 - onLaunch: function() {  
4 - console.log('App Launch')  
5 - },  
6 - onShow: function() {  
7 - console.log('App Show')  
8 - },  
9 - onHide: function() {  
10 - console.log('App Hide')  
11 - }  
12 - } 2 +export default {
  3 + onLaunch: function () {
  4 + console.log('App Launch')
  5 + // #ifdef H5
  6 + //在页面加载时读取sessionStorage里的状态信息
  7 + if (sessionStorage.getItem('store')) {
  8 + this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem('store'))))
  9 + }
  10 + //在页面刷新时将vuex里的信息保存到sessionStorage里
  11 + window.addEventListener('beforeunload', () => {
  12 + sessionStorage.setItem('store', JSON.stringify(this.$store.state))
  13 + })
  14 + // #endif
  15 + },
  16 + onShow: function () {
  17 + console.log('App Show')
  18 + },
  19 + onHide: function () {
  20 + console.log('App Hide')
  21 + }
  22 +}
13 </script> 23 </script>
14 24
15 <style lang="scss"> 25 <style lang="scss">
16 - /* 引入uView基础样式 */  
17 - @import "@/uni_modules/uview-ui/index.scss";  
18 -  
19 - /*每个页面公共scss */  
20 - @import "app.scss"; 26 +/* 引入uView基础样式 */
  27 +@import '@/uni_modules/uview-ui/index.scss';
21 28
  29 +/*每个页面公共scss */
  30 +@import 'app.scss';
22 </style> 31 </style>
yudao-ui-app/common/api.js
@@ -2,12 +2,15 @@ const { http } = uni.$u @@ -2,12 +2,15 @@ const { http } = uni.$u
2 2
3 /* login */ 3 /* login */
4 //使用手机 + 密码登录 4 //使用手机 + 密码登录
5 -export const passwordLogin = params => http.post('/app-api/member/user/login', params) 5 +export const passwordLogin = params => http.post('/app-api/member/login', params)
6 //发送手机验证码 6 //发送手机验证码
7 export const sendSmsCode = params => http.post('/app-api/member/send-sms-code', params) 7 export const sendSmsCode = params => http.post('/app-api/member/send-sms-code', params)
8 //使用手机 + 验证码登录 8 //使用手机 + 验证码登录
9 export const smsLogin = params => http.post('/app-api/member/sms-login', params) 9 export const smsLogin = params => http.post('/app-api/member/sms-login', params)
10 10
  11 +//获取用户信息
  12 +export const getUserInfo = params => http.get('/app-api/member/user/get', params)
  13 +
11 /* index */ 14 /* index */
12 // 获取滚动图数据 15 // 获取滚动图数据
13 export const getBannerData = params => http.get('/app-api/index', params) 16 export const getBannerData = params => http.get('/app-api/index', params)
yudao-ui-app/common/config.js
1 module.exports = { 1 module.exports = {
2 - baseUrl: 'http://192.168.3.199:8086' 2 + //后端接口地址
  3 + baseUrl: 'http://127.0.0.1:48080',
  4 + header: {
  5 + //租户ID
  6 + 'tenant-id': 1
  7 + }
3 } 8 }
yudao-ui-app/common/mixin.js
1 export default { 1 export default {
2 - data() {  
3 - return {  
4 -  
5 - }  
6 - } 2 + data() {
  3 + return {}
  4 + }
7 } 5 }
yudao-ui-app/main.js
1 import Vue from 'vue' 1 import Vue from 'vue'
2 import App from './App' 2 import App from './App'
3 3
  4 +// 引入全局uView
  5 +import uView from '@/uni_modules/uview-ui'
  6 +
4 // vuex 7 // vuex
5 import store from './store' 8 import store from './store'
6 9
7 Vue.config.productionTip = false 10 Vue.config.productionTip = false
8 Vue.prototype.$store = store 11 Vue.prototype.$store = store
9 12
10 -// 引入全局uView  
11 -import uView from '@/uni_modules/uview-ui' 13 +
12 14
13 App.mpType = 'app' 15 App.mpType = 'app'
14 Vue.use(uView) 16 Vue.use(uView)
yudao-ui-app/pages/cart/cart.vue
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 <u-empty mode="car" width="500rpx" height="500rpx" icon="/static/images/empty/cart.png"></u-empty> 4 <u-empty mode="car" width="500rpx" height="500rpx" icon="/static/images/empty/cart.png"></u-empty>
5 </view> 5 </view>
6 6
7 - <view class="login-tips-box"> 7 + <view v-if="!hasLogin" class="login-tips-box">
8 <view class="login-tips"> 8 <view class="login-tips">
9 <navigator url="/pages/login/login" open-type="navigate" hover-class="none"> 9 <navigator url="/pages/login/login" open-type="navigate" hover-class="none">
10 <text class="login-link">登录</text> 10 <text class="login-link">登录</text>
@@ -23,7 +23,12 @@ export default { @@ -23,7 +23,12 @@ export default {
23 } 23 }
24 }, 24 },
25 onLoad() {}, 25 onLoad() {},
26 - methods: {} 26 + methods: {},
  27 + computed: {
  28 + hasLogin() {
  29 + return this.$store.getters.hasLogin
  30 + }
  31 + }
27 } 32 }
28 </script> 33 </script>
29 34
yudao-ui-app/pages/login/login.vue
@@ -53,15 +53,13 @@ import { passwordLogin, sendSmsCode, smsLogin } from &#39;../../common/api&#39; @@ -53,15 +53,13 @@ import { passwordLogin, sendSmsCode, smsLogin } from &#39;../../common/api&#39;
53 export default { 53 export default {
54 data() { 54 data() {
55 return { 55 return {
56 - //租户ID  
57 - agent: 1,  
58 currentModeIndex: 0, 56 currentModeIndex: 0,
59 loginModeList: ['密码登录', '验证码登录'], 57 loginModeList: ['密码登录', '验证码登录'],
60 inputType: 'password', 58 inputType: 'password',
61 codeDisabled: false, 59 codeDisabled: false,
62 codeTips: '', 60 codeTips: '',
63 formData: { 61 formData: {
64 - mobile: '15601691234', 62 + mobile: '',
65 password: '', 63 password: '',
66 code: '' 64 code: ''
67 }, 65 },
@@ -131,17 +129,17 @@ export default { @@ -131,17 +129,17 @@ export default {
131 }) 129 })
132 130
133 //scene:1登陆获取验证码场景 131 //scene:1登陆获取验证码场景
134 - sendSmsCode({ agent: 1, mobile: mobile, scene: 1 }) 132 + sendSmsCode({ mobile: mobile, scene: 1 })
135 .then(res => { 133 .then(res => {
136 //console.log(res) 134 //console.log(res)
137 uni.hideLoading() 135 uni.hideLoading()
138 - if (res.data.code === 0) { 136 + if (res.code === 0) {
139 // 这里此提示会被this.start()方法中的提示覆盖 137 // 这里此提示会被this.start()方法中的提示覆盖
140 uni.$u.toast('验证码已发送') 138 uni.$u.toast('验证码已发送')
141 // 通知验证码组件内部开始倒计时 139 // 通知验证码组件内部开始倒计时
142 this.$refs.uCode.start() 140 this.$refs.uCode.start()
143 } else { 141 } else {
144 - uni.$u.toast(res.data.msg) 142 + uni.$u.toast(res.msg)
145 } 143 }
146 }) 144 })
147 .catch(err => { 145 .catch(err => {
@@ -153,26 +151,30 @@ export default { @@ -153,26 +151,30 @@ export default {
153 }, 151 },
154 handleSubmit() { 152 handleSubmit() {
155 this.$refs.form.validate().then(res => { 153 this.$refs.form.validate().then(res => {
156 - uni.$u.toast('登录')  
157 if (this.currentModeIndex === 0) { 154 if (this.currentModeIndex === 0) {
158 - passwordLogin({ agent: 1, mobile: this.formData.mobile, password: this.formData.password })  
159 - .then(res => {  
160 - if (res.data.code === 0) {  
161 - uni.$u.toast('登录成功')  
162 - // TODO 登录成功,保存toke  
163 - } else {  
164 - uni.$u.toast(res.data.msg)  
165 - // TODO 登录失败  
166 - }  
167 - })  
168 - .catch(err => {  
169 - uni.$u.toast('服务器接口请求异常')  
170 - }) 155 + this.handleLoginPromise(passwordLogin({ mobile: this.formData.mobile, password: this.formData.password }))
171 } else if (this.currentModeIndex === 1) { 156 } else if (this.currentModeIndex === 1) {
172 - smsLogin({ agent: 1, mobile: this.formData.mobile, code: this.formData.code }) 157 + this.handleLoginPromise(smsLogin({ mobile: this.formData.mobile, code: this.formData.code }))
173 } 158 }
174 }) 159 })
175 }, 160 },
  161 + handleLoginPromise(promise) {
  162 + promise
  163 + .then(res => {
  164 + if (res.code === 0) {
  165 + this.$store.commit('setToken', res.data)
  166 + uni.$u.toast('登录成功')
  167 + setTimeout(() => {
  168 + this.navigateBack()
  169 + }, 1000)
  170 + } else {
  171 + uni.$u.toast(res.msg)
  172 + }
  173 + })
  174 + .catch(err => {
  175 + uni.$u.toast('接口请求失败')
  176 + })
  177 + },
176 navigateBack() { 178 navigateBack() {
177 uni.navigateBack() 179 uni.navigateBack()
178 } 180 }
@@ -200,8 +202,6 @@ export default { @@ -200,8 +202,6 @@ export default {
200 } 202 }
201 } 203 }
202 204
203 -  
204 -  
205 .lk-group { 205 .lk-group {
206 height: 40rpx; 206 height: 40rpx;
207 margin-top: 40rpx; 207 margin-top: 40rpx;
yudao-ui-app/pages/user/user.vue
@@ -2,8 +2,8 @@ @@ -2,8 +2,8 @@
2 <view class="container"> 2 <view class="container">
3 <view class="user-header"> 3 <view class="user-header">
4 <view class="user-info" @click="loginOrJump('/pages/profile/profile')"> 4 <view class="user-info" @click="loginOrJump('/pages/profile/profile')">
5 - <u-avatar size="80" :src="avatar"></u-avatar>  
6 - <text class="nick-name">{{ nickName }}</text> 5 + <u-avatar size="80" :src="userInfo.avatar"></u-avatar>
  6 + <text class="nick-name">{{ hasLogin ? userInfo.nickname || '游客' : '点击登录' }}</text>
7 </view> 7 </view>
8 </view> 8 </view>
9 9
@@ -19,8 +19,8 @@ @@ -19,8 +19,8 @@
19 </view> 19 </view>
20 20
21 <view class="order-status-box"> 21 <view class="order-status-box">
22 - <u-grid :border="false" :col="orderStatusList.length"  
23 - ><u-grid-item v-for="(item, index) in orderStatusList" :key="index"> 22 + <u-grid :border="false" :col="orderStatusList.length">
  23 + <u-grid-item v-for="(item, index) in orderStatusList" :key="index">
24 <u-icon :name="item.icon" :size="32"></u-icon> 24 <u-icon :name="item.icon" :size="32"></u-icon>
25 <text class="grid-title">{{ item.title }}</text> 25 <text class="grid-title">{{ item.title }}</text>
26 </u-grid-item> 26 </u-grid-item>
@@ -45,13 +45,12 @@ @@ -45,13 +45,12 @@
45 <u-cell class="fun-item" :border="false" icon="gift" title="分销中心" isLink></u-cell> 45 <u-cell class="fun-item" :border="false" icon="gift" title="分销中心" isLink></u-cell>
46 <u-cell class="fun-item" :border="false" icon="tags" title="领券中心" isLink></u-cell> 46 <u-cell class="fun-item" :border="false" icon="tags" title="领券中心" isLink></u-cell>
47 <u-cell class="fun-item" :border="false" icon="coupon" title="我的优惠券" isLink></u-cell> 47 <u-cell class="fun-item" :border="false" icon="coupon" title="我的优惠券" isLink></u-cell>
48 - <u-cell class="fun-item" :border="false" icon="map" title="收货地址" @click="loginOrJump('/pages/address/list')" isLink></u-cell> 48 + <u-cell class="fun-item" :border="false" icon="map" title="收货地址" @click="loginOrJump('/pages/address/list')" isLink></u-cell>
49 </u-cell-group> 49 </u-cell-group>
50 50
51 - <view class="logout-btn">  
52 - <u-button type="error" color="#ea322b" text="确定"></u-button> 51 + <view v-if="hasLogin" class="logout-btn">
  52 + <u-button type="error" color="#ea322b" text="退出登录" @click="logout"></u-button>
53 </view> 53 </view>
54 -  
55 </view> 54 </view>
56 </template> 55 </template>
57 56
@@ -59,8 +58,6 @@ @@ -59,8 +58,6 @@
59 export default { 58 export default {
60 data() { 59 data() {
61 return { 60 return {
62 - avatar: '',  
63 - nickName: '点击登录',  
64 orderStatusList: [ 61 orderStatusList: [
65 { icon: 'rmb-circle', title: '待支付' }, 62 { icon: 'rmb-circle', title: '待支付' },
66 { icon: 'car', title: '代发货' }, 63 { icon: 'car', title: '代发货' },
@@ -76,13 +73,34 @@ export default { @@ -76,13 +73,34 @@ export default {
76 }, 73 },
77 onLoad() {}, 74 onLoad() {},
78 methods: { 75 methods: {
79 - loginOrJump(pageUrl){  
80 - // TODO 判断是否已经登录逻辑  
81 - if (!uni.getStorageSync('token')) { 76 + loginOrJump(pageUrl) {
  77 + if (!this.hasLogin) {
82 uni.$u.route('/pages/login/login') 78 uni.$u.route('/pages/login/login')
83 } else { 79 } else {
84 uni.$u.route(pageUrl) 80 uni.$u.route(pageUrl)
85 } 81 }
  82 + },
  83 + logout() {
  84 + uni.showModal({
  85 + title: '提示',
  86 + content: '您确定要退出登录吗',
  87 + success: res => {
  88 + if (res.confirm) {
  89 + console.log('用户点击确定')
  90 + this.$store.commit('logout')
  91 + } else if (res.cancel) {
  92 + console.log('用户点击取消')
  93 + }
  94 + }
  95 + })
  96 + }
  97 + },
  98 + computed: {
  99 + userInfo() {
  100 + return this.$store.state.userInfo
  101 + },
  102 + hasLogin() {
  103 + return this.$store.getters.hasLogin
86 } 104 }
87 } 105 }
88 } 106 }
yudao-ui-app/store/index.js
1 import Vue from 'vue' 1 import Vue from 'vue'
2 import Vuex from 'vuex' 2 import Vuex from 'vuex'
  3 +import { getUserInfo } from '@/common/api'
3 4
4 Vue.use(Vuex) // vue的插件机制 5 Vue.use(Vuex) // vue的插件机制
5 6
6 // Vuex.Store 构造器选项 7 // Vuex.Store 构造器选项
7 const store = new Vuex.Store({ 8 const store = new Vuex.Store({
8 - // 为了不和页面或组件的data中的造成混淆,state中的变量前面建议加上$符号  
9 - state: {  
10 - // 用户信息  
11 - $userInfo: {  
12 - id: '' 9 + state: {
  10 + openExamine: false, // 是否开启审核状态。用于小程序、App 等审核时,关闭部分功能。TODO 芋艿:暂时没找到刷新的地方
  11 + token: uni.getStorageSync('token'), // 用户身份 Token
  12 + userInfo: {}, // 用户基本信息
  13 + timerIdent: false // 全局 1s 定时器,只在全局开启一个,所有需要定时执行的任务监听该值即可,无需额外开启 TODO 芋艿:需要看看
  14 + },
  15 + getters: {
  16 + hasLogin(state) {
  17 + return !!state.token
  18 + }
  19 + },
  20 + mutations: {
  21 + // 更新 state 的通用方法
  22 + setStateAttr(state, param) {
  23 + if (param instanceof Array) {
  24 + for (let item of param) {
  25 + state[item.key] = item.val
13 } 26 }
  27 + } else {
  28 + state[param.key] = param.val
  29 + }
14 }, 30 },
15 - mutations: {  
16 -  
17 - },  
18 - actions: { 31 + // 更新token
  32 + setToken(state, data) {
  33 + // 设置 Token
  34 + const { token } = data
  35 + state.token = token
  36 + uni.setStorageSync('token', token)
19 37
  38 + // 加载用户信息
  39 + this.dispatch('obtainUserInfo')
20 }, 40 },
21 - getters:{  
22 - 41 + // 退出登录
  42 + logout(state) {
  43 + // 清空 Token
  44 + state.token = ''
  45 + uni.removeStorageSync('token')
  46 + // 清空用户信息 TODO 芋艿:这里 setTimeout 的原因是,上面可能还有一些 request 请求。后续得优化下
  47 + setTimeout(() => {
  48 + state.userInfo = {}
  49 + }, 1100)
  50 + }
  51 + },
  52 + actions: {
  53 + // 获得用户基本信息
  54 + async obtainUserInfo({ state, commit }) {
  55 + const res = await getUserInfo()
  56 + commit('setStateAttr', {
  57 + key: 'userInfo',
  58 + val: res.data
  59 + })
23 } 60 }
  61 + }
24 }) 62 })
25 63
26 export default store 64 export default store
yudao-ui-app/util/request/index.js
@@ -4,6 +4,7 @@ import config from &#39;@/common/config&#39; @@ -4,6 +4,7 @@ import config from &#39;@/common/config&#39;
4 uni.$u.http.setConfig((defaultConfig) => { 4 uni.$u.http.setConfig((defaultConfig) => {
5 /* defaultConfig 为默认全局配置 */ 5 /* defaultConfig 为默认全局配置 */
6 defaultConfig.baseURL = config.baseUrl /* 根域名 */ 6 defaultConfig.baseURL = config.baseUrl /* 根域名 */
  7 + defaultConfig.header = config.header
7 return defaultConfig 8 return defaultConfig
8 }) 9 })
9 10
yudao-ui-app/util/request/requestInterceptors.js
@@ -2,13 +2,21 @@ @@ -2,13 +2,21 @@
2 * 请求拦截 2 * 请求拦截
3 * @param {Object} http 3 * @param {Object} http
4 */ 4 */
5 -module.exports = (vm) => {  
6 - uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作  
7 - // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}  
8 - config.data = config.data || {}  
9 - // 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中  
10 - // console.log(vm.$store.state);  
11 - return config  
12 - }, (config) => // 可使用async await 做异步操作  
13 - Promise.reject(config)) 5 +module.exports = vm => {
  6 + uni.$u.http.interceptors.request.use(
  7 + config => {
  8 + // 可使用async await 做异步操作
  9 + // 初始化请求拦截器时,会执行此方法,此时data为undefined,赋予默认{}
  10 + config.data = config.data || {}
  11 + // 可以在此通过vm引用vuex中的变量,具体值在vm.$store.state中
  12 + // console.log(vm.$store.state)
  13 + if (vm.$store.getters.hasLogin) {
  14 + config.header.authorization = 'Bearer ' + vm.$store.state.token
  15 + }
  16 + return config
  17 + },
  18 + (
  19 + config // 可使用async await 做异步操作
  20 + ) => Promise.reject(config)
  21 + )
14 } 22 }
yudao-ui-app/util/request/responseInterceptors.js
@@ -2,16 +2,16 @@ @@ -2,16 +2,16 @@
2 * 响应拦截 2 * 响应拦截
3 * @param {Object} http 3 * @param {Object} http
4 */ 4 */
5 -module.exports = (vm) => {  
6 - uni.$u.http.interceptors.response.use((res) => {  
7 - /* 对响应成功做点什么 可使用async await 做异步操作*/  
8 - const data = res.data  
9 - /*  
10 - 可以根据业务情况做相应的处理  
11 - */  
12 - return res  
13 - }, (err) => {  
14 - /* 对响应错误做点什么 (statusCode !== 200)*/  
15 - return Promise.reject(err)  
16 - })  
17 -}  
18 \ No newline at end of file 5 \ No newline at end of file
  6 +module.exports = vm => {
  7 + uni.$u.http.interceptors.response.use(
  8 + res => {
  9 + //对响应成功做点什么 可使用async await 做异步操作
  10 + //可以根据业务情况做相应的处理
  11 + return res.data
  12 + },
  13 + err => {
  14 + //对响应错误做点什么 (statusCode !== 200)
  15 + return Promise.reject(err)
  16 + }
  17 + )
  18 +}