Commit 93352b538617c04c77534cd03168231adb25ad4e

Authored by sfmind
1 parent 671b5d34

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

yudao-ui-app/App.vue
1 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 23 </script>
14 24  
15 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 31 </style>
... ...
yudao-ui-app/common/api.js
... ... @@ -2,12 +2,15 @@ const { http } = uni.$u
2 2  
3 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 7 export const sendSmsCode = params => http.post('/app-api/member/send-sms-code', params)
8 8 //使用手机 + 验证码登录
9 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 14 /* index */
12 15 // 获取滚动图数据
13 16 export const getBannerData = params => http.get('/app-api/index', params)
... ...
yudao-ui-app/common/config.js
1 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 1 export default {
2   - data() {
3   - return {
4   -
5   - }
6   - }
  2 + data() {
  3 + return {}
  4 + }
7 5 }
... ...
yudao-ui-app/main.js
1 1 import Vue from 'vue'
2 2 import App from './App'
3 3  
  4 +// 引入全局uView
  5 +import uView from '@/uni_modules/uview-ui'
  6 +
4 7 // vuex
5 8 import store from './store'
6 9  
7 10 Vue.config.productionTip = false
8 11 Vue.prototype.$store = store
9 12  
10   -// 引入全局uView
11   -import uView from '@/uni_modules/uview-ui'
  13 +
12 14  
13 15 App.mpType = 'app'
14 16 Vue.use(uView)
... ...
yudao-ui-app/pages/cart/cart.vue
... ... @@ -4,7 +4,7 @@
4 4 <u-empty mode="car" width="500rpx" height="500rpx" icon="/static/images/empty/cart.png"></u-empty>
5 5 </view>
6 6  
7   - <view class="login-tips-box">
  7 + <view v-if="!hasLogin" class="login-tips-box">
8 8 <view class="login-tips">
9 9 <navigator url="/pages/login/login" open-type="navigate" hover-class="none">
10 10 <text class="login-link">登录</text>
... ... @@ -23,7 +23,12 @@ export default {
23 23 }
24 24 },
25 25 onLoad() {},
26   - methods: {}
  26 + methods: {},
  27 + computed: {
  28 + hasLogin() {
  29 + return this.$store.getters.hasLogin
  30 + }
  31 + }
27 32 }
28 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 53 export default {
54 54 data() {
55 55 return {
56   - //租户ID
57   - agent: 1,
58 56 currentModeIndex: 0,
59 57 loginModeList: ['密码登录', '验证码登录'],
60 58 inputType: 'password',
61 59 codeDisabled: false,
62 60 codeTips: '',
63 61 formData: {
64   - mobile: '15601691234',
  62 + mobile: '',
65 63 password: '',
66 64 code: ''
67 65 },
... ... @@ -131,17 +129,17 @@ export default {
131 129 })
132 130  
133 131 //scene:1登陆获取验证码场景
134   - sendSmsCode({ agent: 1, mobile: mobile, scene: 1 })
  132 + sendSmsCode({ mobile: mobile, scene: 1 })
135 133 .then(res => {
136 134 //console.log(res)
137 135 uni.hideLoading()
138   - if (res.data.code === 0) {
  136 + if (res.code === 0) {
139 137 // 这里此提示会被this.start()方法中的提示覆盖
140 138 uni.$u.toast('验证码已发送')
141 139 // 通知验证码组件内部开始倒计时
142 140 this.$refs.uCode.start()
143 141 } else {
144   - uni.$u.toast(res.data.msg)
  142 + uni.$u.toast(res.msg)
145 143 }
146 144 })
147 145 .catch(err => {
... ... @@ -153,26 +151,30 @@ export default {
153 151 },
154 152 handleSubmit() {
155 153 this.$refs.form.validate().then(res => {
156   - uni.$u.toast('登录')
157 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 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 178 navigateBack() {
177 179 uni.navigateBack()
178 180 }
... ... @@ -200,8 +202,6 @@ export default {
200 202 }
201 203 }
202 204  
203   -
204   -
205 205 .lk-group {
206 206 height: 40rpx;
207 207 margin-top: 40rpx;
... ...
yudao-ui-app/pages/user/user.vue
... ... @@ -2,8 +2,8 @@
2 2 <view class="container">
3 3 <view class="user-header">
4 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 7 </view>
8 8 </view>
9 9  
... ... @@ -19,8 +19,8 @@
19 19 </view>
20 20  
21 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 24 <u-icon :name="item.icon" :size="32"></u-icon>
25 25 <text class="grid-title">{{ item.title }}</text>
26 26 </u-grid-item>
... ... @@ -45,13 +45,12 @@
45 45 <u-cell class="fun-item" :border="false" icon="gift" title="分销中心" isLink></u-cell>
46 46 <u-cell class="fun-item" :border="false" icon="tags" title="领券中心" isLink></u-cell>
47 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 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 53 </view>
54   -
55 54 </view>
56 55 </template>
57 56  
... ... @@ -59,8 +58,6 @@
59 58 export default {
60 59 data() {
61 60 return {
62   - avatar: '',
63   - nickName: '点击登录',
64 61 orderStatusList: [
65 62 { icon: 'rmb-circle', title: '待支付' },
66 63 { icon: 'car', title: '代发货' },
... ... @@ -76,13 +73,34 @@ export default {
76 73 },
77 74 onLoad() {},
78 75 methods: {
79   - loginOrJump(pageUrl){
80   - // TODO 判断是否已经登录逻辑
81   - if (!uni.getStorageSync('token')) {
  76 + loginOrJump(pageUrl) {
  77 + if (!this.hasLogin) {
82 78 uni.$u.route('/pages/login/login')
83 79 } else {
84 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 1 import Vue from 'vue'
2 2 import Vuex from 'vuex'
  3 +import { getUserInfo } from '@/common/api'
3 4  
4 5 Vue.use(Vuex) // vue的插件机制
5 6  
6 7 // Vuex.Store 构造器选项
7 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 64 export default store
... ...
yudao-ui-app/util/request/index.js
... ... @@ -4,6 +4,7 @@ import config from &#39;@/common/config&#39;
4 4 uni.$u.http.setConfig((defaultConfig) => {
5 5 /* defaultConfig 为默认全局配置 */
6 6 defaultConfig.baseURL = config.baseUrl /* 根域名 */
  7 + defaultConfig.header = config.header
7 8 return defaultConfig
8 9 })
9 10  
... ...
yudao-ui-app/util/request/requestInterceptors.js
... ... @@ -2,13 +2,21 @@
2 2 * 请求拦截
3 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 2 * 响应拦截
3 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 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 +}
... ...