30 账户安全功能页面(各种账号绑定操作)
30 账户安全功能页面
一 修改账号与安全页面
ps:原有的账号与安全选项只是修改密码,现在可以绑定其他的第三方手机号修改密码等等。
效果图:
代码:
<template>
<view>
<uni-list-item :title="item.name"
v-for="(item,index) in list"
:key="index">
<view class="flex align-center text-right text-light-muted"
slot="right">
{{item.data}}
</view>
</uni-list-item>
</view>
</template>
<script>
import uniListItem from '@/components/uni-ui/uni-list-item/uni-list-item.vue';
export default {
components: {
uniListItem
},
data() {
return {
list:[
{
name:"手机号",
data:"未绑定",
},
{
name:"登录密码",
data:"未设置"
},
{
name:"邮箱绑定",
data:"未绑定"
},
{
name:"微信账号",
data:"未绑定",
},
{
name:"微博账号",
data:"未绑定",
},
{
name:"QQ账号",
data:"未绑定",
}
]
}
},
methods: {
}
}
</script>
<style>
</style>
二 绑定手机
效果图:
思路:
1 修改手机号这种操作一定是已经登录过token了,所以重新封装request.js使得可以动态获得token
2 然后绑定手机的业务逻辑而已了
3 然后修改state的user信息,然后重新存储一下user信息。
code: 重装request.js(关注验证token部分)
import $C from '@/common/config.js'
import $store from '@/store/index.js'
export default {
common:{
method:'GET',
header:{
"content-type":"application/json"
},
data:{}
},
request(options = {}){
options.url = $C.webUrl + options.url
options.method = options.method || this.common.method
options.header = options.header || this.common.header
// 验证权限token 写到了这里!!!!!!!
if (options.token) {
options.header.token = $store.state.token
if (!options.header.token){
return uni.showToast({
title:'非法token,请重新登录',
icon:'none'
});
}
}
// 该有的参数传入进去,返回了一个promise对象可以直接.then使用了就。
// ps:之前不写成promise对象是因为,之前没有使用success,fail回掉函数,uniapp自动封装为promise对象。
// 现在使用了success、fail 所以要自己定制一个promise对象
return new Promise((resolve,reject)=>{
uni.request({
// 类似于python的** 打散
...options,
success: (result) => {
// console.log('####',result)
// 返回原始数据
if (options.native){
return resolve(result)
}
// 服务器传来非200 状态码
if (result.statusCode !== 200){
uni.showToast({
title:result.data.msg || '请求失败',
icon:'none'
})
return reject(result.data)
}
// 正常返回 服务器返回正常数据,直接取到了服务器传来的data
resolve(result.data.data)
},
// 请求发送失败
fail:(error) => {
uni.showToast({
title:error.errMsg || '请求失败',
icon:'none'
})
return reject()
}
})
})
},
get(url, data={}, options={}){
options.url = url
options.data = data
options.method = 'GET'
return this.request(options)
},
post(url, data={}, options={}){
options.url = url
options.data = data
options.method = 'POST'
return this.request(options)
},
}
// ---------------正确的返回方式 success的result--------------
// {
// "data": {
// "msg": "获取成功",
// "data": {
// "list": [{
// "id": 1,
// "classname": "关注"
// }, {
// "id": 2,
// "classname": "推荐"
// }, {
// "id": 3,
// "classname": "体育"
// }, {
// "id": 4,
// "classname": "热点"
// }, {
// "id": 5,
// "classname": "财经"
// }, {
// "id": 6,
// "classname": "娱乐"
// }]
// }
// },
// "statusCode": 200,
// "header": {
// "X-Android-Sent-Millis": "1587476693145",
// "Content-Type": "application/json; charset=utf-8",
// "_": "HTTP/1.1 200 OK",
// "X-Powered-By": "PHP/7.2.13",
// "X-Android-Selected-Protocol": "http/1.1",
// "Date": "Tue, 21 Apr 2020 13:44:49 GMT",
// "Server": "nginx",
// "Transfer-Encoding": "chunked",
// "X-Android-Response-Source": "NETWORK 200",
// "Connection": "keep-alive",
// "X-Android-Received-Millis": "1587476693348"
// },
// "errMsg": "request:ok"
// }
// -------------错误的返回方式 success的result---------------
// {
// "data": {
// "msg": "服务器异常",
// "errorCode": "999"
// },
// "statusCode": 500,
// "header": {
// "X-Android-Sent-Millis": "1587476568046",
// "Content-Type": "application/json; charset=utf-8",
// "_": "HTTP/1.1 500 Internal Server Error",
// "X-Powered-By": "PHP/7.2.13",
// "X-Android-Selected-Protocol": "http/1.1",
// "Date": "Tue, 21 Apr 2020 13:42:44 GMT",
// "Server": "nginx",
// "Transfer-Encoding": "chunked",
// "X-Android-Response-Source": "NETWORK 500",
// "Connection": "keep-alive",
// "X-Android-Received-Millis": "1587476568104"
// },
// "errMsg": "request:ok"
// }
code: 更新index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state:{
loginStatus:false,
token:false,
user:{
// "id": 400,
// "username": "17621868045",
// "userpic": null,
// "password": false,
// "phone": "17621868045",
// "email": null,
// "status": 1,
// "create_time": 1587717384,
// "logintype": "phone",
// "token": "3e80c968d8b5610b9fda2341fd0ba43b39c59a40",
// "userinfo": {
// "id": 390,
// "user_id": 400,
// "age": 0,
// "sex": 2,
// "qg": 0,
// "job": null,
// "path": null,
// "birthday": null
// }
}
},
mutations:{
// 登录
login(state,user){
// 更改state中的变量要在这里更改。
state.loginStatus = true
state.user = user
// 登录成功记录一下token
state.token = state.user.token
// 永久存储
uni.setStorageSync('user',JSON.stringify(user));
},
// 初始化用户登录状态
initUser(state){
let user = uni.getStorageSync('user');
if (user){
state.user = JSON.parse(user)
state.loginStatus = true
// 初始化用户信息记录一下token。
state.token = state.user.token
}
},
// 退出登录
logout(state){
state.loginStatus = false
state.user = {}
state.token = false
uni.removeStorageSync('user')
},
// 修改用户信息
editUserInfo(state,{key,value}){
// console.log(key,value)
state.user[key] = value
uni.setStorageSync('user',JSON.stringify(state.user))
}
}
})
code: user-phone.vue
<template>
<view>
<view class="px-4">
<!-- 手机号 -->
<view class="flex align-center border-bottom" style="margin-top:100rpx">
<view class="flex align-center justify-center font-weight-bold font-md">
+86
</view>
<input class="font-md p-3" type="text"
value="" placeholder="手机号"
v-model="phone"/>
<!-- <view class="flex align-center justify-center font-weight-bold bg-main">
+86
</view> -->
</view>
<!-- 验证码 -->
<!-- align-stretch直接保证了各个元素高度的统一,就不只是剧中对齐了 -->
<view class="flex align-center border-bottom ">
<input class="flex-1 font-md p-3" type="text"
value="" placeholder="请输入验证码"
v-model="code"/>
<view class="text-white rounded flex font-md p-1 align-center justify-center bg-main " style="width: 180rpx;"
@click="getCode"
:class="codeTime>0 ?'bg-main-disabled':'bg-main'">
{{codeTime>0 ? codeTime: '获取验证码'}}
</view>
</view>
</view>
<!-- 登录按钮 -->
<view class="px-3 " style="padding-top:60rpx">
<button class=" text-white" style="border-radius: 50rpx;border: 0;" type="primary"
:disabled="disabled"
:class="disabled?'bg-main-disabled':'bg-main'"
@click="submit"
:loading="loading">设置</button>
<!-- 这个loading bool一旦为true 会显示旋转加载状态并且不可点击 -->
</view>
</view>
</template>
<script>
export default {
data() {
return {
phone:"",
code:"",
codeTime:0,
loading:false
}
},
computed:{
disabled(){
if (this.phone===""||this.code===""){
return true
}
return false
}
},
methods: {
// 获取验证码
getCode(){
// 防止重复获取
if (this.codeTime>0){
return;
}
// 验证手机号
if (!this.validate()) return;
// 请求数据
this.$H.post('/user/sendcode',{
phone:this.phone
},{
// 这样原生数据就会传输过来
native:true
}).then(res=>{
// console.log(res)
uni.showToast({
title:res.data.msg,
icon:'none'
})
}).catch(err=>{
// console.log(err)
})
// 倒计时
this.codeTime = 5
// 箭头函数可以直接拿到外面的this的内容
let timer = setInterval(()=>{
if (this.codeTime >= 1){
this.codeTime--
} else{
clearInterval(timer)
}
},1000)
},
// 表单验证
validate(){
//手机号正则 只是针对验证码的手机号字段,其他并未做兼容。
var mPattern = /^1[34578]\d{9}$/;
if (!mPattern.test(this.phone)) {
uni.showToast({
title: '手机号格式不正确',
icon: 'none'
});
return false
}
// ...更多验证
return true
},
submit(){
this.loading = '设置中...'
// 表单验证
if(!this.status){
if (!this.validate()) return;
}
this.$H.post('/user/bindphone',{
phone:this.phone,
code:this.code
},{
token:true
}).then(res=>{
// console.log(res)
this.$store.commit('editUserInfo',{
key:'phone',
value:this.phone
})
uni.navigateBack({
delta:1
});
uni.showToast({
title:'绑定成功',
icon:'none'
})
this.loading = false
}).catch(err=>{
this.loading = false
})
}
}
}
</script>
<style>
</style>