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

This commit is contained in:
sfmind 2022-04-20 03:08:59 +08:00
parent 671b5d343e
commit 93352b5386
12 changed files with 187 additions and 100 deletions

View File

@ -1,22 +1,31 @@
<script> <script>
export default { export default {
onLaunch: function() { onLaunch: function () {
console.log('App Launch') console.log('App Launch')
// #ifdef H5
//sessionStorage
if (sessionStorage.getItem('store')) {
this.$store.replaceState(Object.assign({}, this.$store.state, JSON.parse(sessionStorage.getItem('store'))))
}
//vuexsessionStorage
window.addEventListener('beforeunload', () => {
sessionStorage.setItem('store', JSON.stringify(this.$store.state))
})
// #endif
}, },
onShow: function() { onShow: function () {
console.log('App Show') console.log('App Show')
}, },
onHide: function() { onHide: function () {
console.log('App Hide') console.log('App Hide')
} }
} }
</script> </script>
<style lang="scss"> <style lang="scss">
/* 引入uView基础样式 */ /* 引入uView基础样式 */
@import "@/uni_modules/uview-ui/index.scss"; @import '@/uni_modules/uview-ui/index.scss';
/*每个页面公共scss */
@import "app.scss";
/*每个页面公共scss */
@import 'app.scss';
</style> </style>

View File

@ -2,12 +2,15 @@ const { http } = uni.$u
/* login */ /* login */
//使用手机 + 密码登录 //使用手机 + 密码登录
export const passwordLogin = params => http.post('/app-api/member/user/login', params) export const passwordLogin = params => http.post('/app-api/member/login', params)
//发送手机验证码 //发送手机验证码
export const sendSmsCode = params => http.post('/app-api/member/send-sms-code', params) export const sendSmsCode = params => http.post('/app-api/member/send-sms-code', params)
//使用手机 + 验证码登录 //使用手机 + 验证码登录
export const smsLogin = params => http.post('/app-api/member/sms-login', params) export const smsLogin = params => http.post('/app-api/member/sms-login', params)
//获取用户信息
export const getUserInfo = params => http.get('/app-api/member/user/get', params)
/* index */ /* index */
// 获取滚动图数据 // 获取滚动图数据
export const getBannerData = params => http.get('/app-api/index', params) export const getBannerData = params => http.get('/app-api/index', params)

View File

@ -1,3 +1,8 @@
module.exports = { module.exports = {
baseUrl: 'http://192.168.3.199:8086' //后端接口地址
baseUrl: 'http://127.0.0.1:48080',
header: {
//租户ID
'tenant-id': 1
}
} }

View File

@ -1,7 +1,5 @@
export default { export default {
data() { data() {
return { return {}
}
} }
} }

View File

@ -1,14 +1,16 @@
import Vue from 'vue' import Vue from 'vue'
import App from './App' import App from './App'
// 引入全局uView
import uView from '@/uni_modules/uview-ui'
// vuex // vuex
import store from './store' import store from './store'
Vue.config.productionTip = false Vue.config.productionTip = false
Vue.prototype.$store = store Vue.prototype.$store = store
// 引入全局uView
import uView from '@/uni_modules/uview-ui'
App.mpType = 'app' App.mpType = 'app'
Vue.use(uView) Vue.use(uView)

View File

@ -4,7 +4,7 @@
<u-empty mode="car" width="500rpx" height="500rpx" icon="/static/images/empty/cart.png"></u-empty> <u-empty mode="car" width="500rpx" height="500rpx" icon="/static/images/empty/cart.png"></u-empty>
</view> </view>
<view class="login-tips-box"> <view v-if="!hasLogin" class="login-tips-box">
<view class="login-tips"> <view class="login-tips">
<navigator url="/pages/login/login" open-type="navigate" hover-class="none"> <navigator url="/pages/login/login" open-type="navigate" hover-class="none">
<text class="login-link">登录</text> <text class="login-link">登录</text>
@ -23,7 +23,12 @@ export default {
} }
}, },
onLoad() {}, onLoad() {},
methods: {} methods: {},
computed: {
hasLogin() {
return this.$store.getters.hasLogin
}
}
} }
</script> </script>

View File

@ -53,15 +53,13 @@ import { passwordLogin, sendSmsCode, smsLogin } from '../../common/api'
export default { export default {
data() { data() {
return { return {
//ID
agent: 1,
currentModeIndex: 0, currentModeIndex: 0,
loginModeList: ['密码登录', '验证码登录'], loginModeList: ['密码登录', '验证码登录'],
inputType: 'password', inputType: 'password',
codeDisabled: false, codeDisabled: false,
codeTips: '', codeTips: '',
formData: { formData: {
mobile: '15601691234', mobile: '',
password: '', password: '',
code: '' code: ''
}, },
@ -131,17 +129,17 @@ export default {
}) })
//scene:1 //scene:1
sendSmsCode({ agent: 1, mobile: mobile, scene: 1 }) sendSmsCode({ mobile: mobile, scene: 1 })
.then(res => { .then(res => {
//console.log(res) //console.log(res)
uni.hideLoading() uni.hideLoading()
if (res.data.code === 0) { if (res.code === 0) {
// this.start() // this.start()
uni.$u.toast('验证码已发送') uni.$u.toast('验证码已发送')
// //
this.$refs.uCode.start() this.$refs.uCode.start()
} else { } else {
uni.$u.toast(res.data.msg) uni.$u.toast(res.msg)
} }
}) })
.catch(err => { .catch(err => {
@ -153,24 +151,28 @@ export default {
}, },
handleSubmit() { handleSubmit() {
this.$refs.form.validate().then(res => { this.$refs.form.validate().then(res => {
uni.$u.toast('登录')
if (this.currentModeIndex === 0) { if (this.currentModeIndex === 0) {
passwordLogin({ agent: 1, mobile: this.formData.mobile, password: this.formData.password }) this.handleLoginPromise(passwordLogin({ mobile: this.formData.mobile, password: this.formData.password }))
} else if (this.currentModeIndex === 1) {
this.handleLoginPromise(smsLogin({ mobile: this.formData.mobile, code: this.formData.code }))
}
})
},
handleLoginPromise(promise) {
promise
.then(res => { .then(res => {
if (res.data.code === 0) { if (res.code === 0) {
this.$store.commit('setToken', res.data)
uni.$u.toast('登录成功') uni.$u.toast('登录成功')
// TODO toke setTimeout(() => {
this.navigateBack()
}, 1000)
} else { } else {
uni.$u.toast(res.data.msg) uni.$u.toast(res.msg)
// TODO
} }
}) })
.catch(err => { .catch(err => {
uni.$u.toast('服务器接口请求异常') uni.$u.toast('接口请求失败')
})
} else if (this.currentModeIndex === 1) {
smsLogin({ agent: 1, mobile: this.formData.mobile, code: this.formData.code })
}
}) })
}, },
navigateBack() { navigateBack() {
@ -200,8 +202,6 @@ export default {
} }
} }
.lk-group { .lk-group {
height: 40rpx; height: 40rpx;
margin-top: 40rpx; margin-top: 40rpx;

View File

@ -2,8 +2,8 @@
<view class="container"> <view class="container">
<view class="user-header"> <view class="user-header">
<view class="user-info" @click="loginOrJump('/pages/profile/profile')"> <view class="user-info" @click="loginOrJump('/pages/profile/profile')">
<u-avatar size="80" :src="avatar"></u-avatar> <u-avatar size="80" :src="userInfo.avatar"></u-avatar>
<text class="nick-name">{{ nickName }}</text> <text class="nick-name">{{ hasLogin ? userInfo.nickname || '游客' : '点击登录' }}</text>
</view> </view>
</view> </view>
@ -19,8 +19,8 @@
</view> </view>
<view class="order-status-box"> <view class="order-status-box">
<u-grid :border="false" :col="orderStatusList.length" <u-grid :border="false" :col="orderStatusList.length">
><u-grid-item v-for="(item, index) in orderStatusList" :key="index"> <u-grid-item v-for="(item, index) in orderStatusList" :key="index">
<u-icon :name="item.icon" :size="32"></u-icon> <u-icon :name="item.icon" :size="32"></u-icon>
<text class="grid-title">{{ item.title }}</text> <text class="grid-title">{{ item.title }}</text>
</u-grid-item> </u-grid-item>
@ -48,10 +48,9 @@
<u-cell class="fun-item" :border="false" icon="map" title="收货地址" @click="loginOrJump('/pages/address/list')" isLink></u-cell> <u-cell class="fun-item" :border="false" icon="map" title="收货地址" @click="loginOrJump('/pages/address/list')" isLink></u-cell>
</u-cell-group> </u-cell-group>
<view class="logout-btn"> <view v-if="hasLogin" class="logout-btn">
<u-button type="error" color="#ea322b" text="确定"></u-button> <u-button type="error" color="#ea322b" text="退出登录" @click="logout"></u-button>
</view> </view>
</view> </view>
</template> </template>
@ -59,8 +58,6 @@
export default { export default {
data() { data() {
return { return {
avatar: '',
nickName: '点击登录',
orderStatusList: [ orderStatusList: [
{ icon: 'rmb-circle', title: '待支付' }, { icon: 'rmb-circle', title: '待支付' },
{ icon: 'car', title: '代发货' }, { icon: 'car', title: '代发货' },
@ -76,13 +73,34 @@ export default {
}, },
onLoad() {}, onLoad() {},
methods: { methods: {
loginOrJump(pageUrl){ loginOrJump(pageUrl) {
// TODO if (!this.hasLogin) {
if (!uni.getStorageSync('token')) {
uni.$u.route('/pages/login/login') uni.$u.route('/pages/login/login')
} else { } else {
uni.$u.route(pageUrl) uni.$u.route(pageUrl)
} }
},
logout() {
uni.showModal({
title: '提示',
content: '您确定要退出登录吗',
success: res => {
if (res.confirm) {
console.log('用户点击确定')
this.$store.commit('logout')
} else if (res.cancel) {
console.log('用户点击取消')
}
}
})
}
},
computed: {
userInfo() {
return this.$store.state.userInfo
},
hasLogin() {
return this.$store.getters.hasLogin
} }
} }
} }

View File

@ -1,25 +1,63 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
import { getUserInfo } from '@/common/api'
Vue.use(Vuex) // vue的插件机制 Vue.use(Vuex) // vue的插件机制
// Vuex.Store 构造器选项 // Vuex.Store 构造器选项
const store = new Vuex.Store({ const store = new Vuex.Store({
// 为了不和页面或组件的data中的造成混淆state中的变量前面建议加上$符号
state: { state: {
// 用户信息 openExamine: false, // 是否开启审核状态。用于小程序、App 等审核时关闭部分功能。TODO 芋艿:暂时没找到刷新的地方
$userInfo: { token: uni.getStorageSync('token'), // 用户身份 Token
id: '' userInfo: {}, // 用户基本信息
timerIdent: false // 全局 1s 定时器,只在全局开启一个,所有需要定时执行的任务监听该值即可,无需额外开启 TODO 芋艿:需要看看
},
getters: {
hasLogin(state) {
return !!state.token
} }
}, },
mutations: { 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) {
// 设置 Token
const { token } = data
state.token = token
uni.setStorageSync('token', token)
// 加载用户信息
this.dispatch('obtainUserInfo')
},
// 退出登录
logout(state) {
// 清空 Token
state.token = ''
uni.removeStorageSync('token')
// 清空用户信息 TODO 芋艿:这里 setTimeout 的原因是,上面可能还有一些 request 请求。后续得优化下
setTimeout(() => {
state.userInfo = {}
}, 1100)
}
}, },
actions: { actions: {
// 获得用户基本信息
}, async obtainUserInfo({ state, commit }) {
getters:{ const res = await getUserInfo()
commit('setStateAttr', {
key: 'userInfo',
val: res.data
})
}
} }
}) })

View File

@ -4,6 +4,7 @@ import config from '@/common/config'
uni.$u.http.setConfig((defaultConfig) => { uni.$u.http.setConfig((defaultConfig) => {
/* defaultConfig 为默认全局配置 */ /* defaultConfig 为默认全局配置 */
defaultConfig.baseURL = config.baseUrl /* 根域名 */ defaultConfig.baseURL = config.baseUrl /* 根域名 */
defaultConfig.header = config.header
return defaultConfig return defaultConfig
}) })

View File

@ -2,13 +2,21 @@
* 请求拦截 * 请求拦截
* @param {Object} http * @param {Object} http
*/ */
module.exports = (vm) => { module.exports = vm => {
uni.$u.http.interceptors.request.use((config) => { // 可使用async await 做异步操作 uni.$u.http.interceptors.request.use(
config => {
// 可使用async await 做异步操作
// 初始化请求拦截器时会执行此方法此时data为undefined赋予默认{} // 初始化请求拦截器时会执行此方法此时data为undefined赋予默认{}
config.data = config.data || {} config.data = config.data || {}
// 可以在此通过vm引用vuex中的变量具体值在vm.$store.state中 // 可以在此通过vm引用vuex中的变量具体值在vm.$store.state中
// console.log(vm.$store.state); // console.log(vm.$store.state)
if (vm.$store.getters.hasLogin) {
config.header.authorization = 'Bearer ' + vm.$store.state.token
}
return config return config
}, (config) => // 可使用async await 做异步操作 },
Promise.reject(config)) (
config // 可使用async await 做异步操作
) => Promise.reject(config)
)
} }

View File

@ -2,16 +2,16 @@
* 响应拦截 * 响应拦截
* @param {Object} http * @param {Object} http
*/ */
module.exports = (vm) => { module.exports = vm => {
uni.$u.http.interceptors.response.use((res) => { uni.$u.http.interceptors.response.use(
/* 对响应成功做点什么 可使用async await 做异步操作*/ res => {
const data = res.data //对响应成功做点什么 可使用async await 做异步操作
/* //可以根据业务情况做相应的处理
可以根据业务情况做相应的处理 return res.data
*/ },
return res err => {
}, (err) => { //对响应错误做点什么 statusCode !== 200
/* 对响应错误做点什么 statusCode !== 200*/
return Promise.reject(err) return Promise.reject(err)
}) }
)
} }