对接修改个人信息接口,完成修改密码界面,完善请求拦截逻辑处理和登录处理,增加登录角色存储store

This commit is contained in:
Double-_-Z 2025-07-24 17:11:58 +08:00
parent 3ecb5d6466
commit a9aceb5f71
10 changed files with 369 additions and 83 deletions

View File

@ -4,9 +4,9 @@
scroll-with-animation @scroll="scroll" @refresherrefresh="refresh"> scroll-with-animation @scroll="scroll" @refresherrefresh="refresh">
<!-- #ifdef MP-WEIXIN --> <!-- #ifdef MP-WEIXIN -->
<Order ref="pageRef" :topLevel="topLevel" v-if="current===0" /> <Order ref="pageRef" :topLevel="topLevel" v-if="current===0" />
<Equipment ref="pageRef" :topLevel="topLevel" v-if="current===1" /> <Equipment ref="pageRef" :topLevel="topLevel" v-if="isPilot&&current===1" />
<Route ref="pageRef" :topLevel="topLevel" v-else-if="current===2" /> <Route ref="pageRef" :topLevel="topLevel" v-else-if="isPilot&&current===2" />
<My ref="pageRef" :topLevel="topLevel" :isLogin="isLogin" @userLogOut="isLogin=''" v-else-if="current===3" /> <My ref="pageRef" :topLevel="topLevel" :isLogin="isLogin" @userLogOut="isLogin=''" v-else-if="isPilot&&current===3||current===1" />
<!-- #endif --> <!-- #endif -->
<!-- #ifndef MP-WEIXIN --> <!-- #ifndef MP-WEIXIN -->
<component ref="pageRef" :topLevel="topLevel" :is="refs[current]" <component ref="pageRef" :topLevel="topLevel" :is="refs[current]"
@ -16,7 +16,7 @@
<view class="navigation"> <view class="navigation">
<view @click="changeCurrent(index)" class="nav-item" <view @click="changeCurrent(index)" class="nav-item"
:class="current===index?'nav-item-selected':''" :class="current===index?'nav-item-selected':''"
v-for="(item,index) in navicationList" :key="index"> v-for="(item,index) in isPilot?aNavicationList:bNavicationList" :key="index">
<image :src="fileUrl+(current===index?item.select:item.icon)"></image> <image :src="fileUrl+(current===index?item.select:item.icon)"></image>
<text>{{ item.name }}</text> <text>{{ item.name }}</text>
</view> </view>
@ -47,7 +47,7 @@ export default {
loading: false, loading: false,
fileUrl: configService.fileUrl + 'aerocraft/navigation/',// fileUrl: configService.fileUrl + 'aerocraft/navigation/',//
// //
navicationList:[ aNavicationList:[
{ {
name: '订单', name: '订单',
icon: 'order.png', icon: 'order.png',
@ -69,6 +69,18 @@ export default {
select: 'my-select.png' select: 'my-select.png'
} }
], ],
bNavicationList:[
{
name: '订单',
icon: 'order.png',
select: 'order-select.png'
},
{
name: '我的',
icon: 'my.png',
select: 'my-select.png'
}
],
topLevel: 0,// topLevel: 0,//
// //
scrollTop: 0, scrollTop: 0,
@ -77,12 +89,14 @@ export default {
refs: ['order','equipment','route','my'], refs: ['order','equipment','route','my'],
// //
isLogin: this.$store.state.vuex_token, isLogin: this.$store.state.vuex_token,
isPilot: this.$store.state.user_type == 1,
} }
}, },
onLoad(){ onLoad(){
let index = uni.getStorageSync('current'); let index = uni.getStorageSync('current');
this.current = index?index:0; this.current = index?index:0;
this.isLogin = this.$store.state.vuex_token; this.isLogin = this.$store.state.vuex_token;
this.isPilot = this.$store.state.user_type;
this.changeCurrent(this.current); this.changeCurrent(this.current);
}, },
onShow(){ onShow(){

View File

@ -42,7 +42,7 @@
<script> <script>
import lwTopnav from '@/components/lw-topnav/lw-topnav.vue'; import lwTopnav from '@/components/lw-topnav/lw-topnav.vue';
import configService from '@/common/config.service.js'; import configService from '@/common/config.service.js';
import { encrypt } from '@/utils/rsaEncrypt' import { encrypt } from '@/utils/rsaEncrypt';
export default { export default {
// #ifdef MP // #ifdef MP
options: { options: {
@ -62,30 +62,6 @@ export default {
username: '', username: '',
password: '' password: ''
}, },
//
loginRules: {
username: [
{
required: true,
message: '请输入手机号',
trigger: 'blur'
},
{
validator: (rule, value, callback) => {
return this.$u.test.mobile(value);
},
message: '手机号格式不正确',
trigger: ['blur']
}
],
password: [
{
required: true,
message: '请输入密码',
trigger: 'blur'
}
]
},
// //
dotLoading: false, dotLoading: false,
// //
@ -138,6 +114,7 @@ export default {
}else{ }else{
// //
uni.setStorageSync('loginMemory',JSON.stringify({...that.loginForm,timer: new Date()})); uni.setStorageSync('loginMemory',JSON.stringify({...that.loginForm,timer: new Date()}));
that.$u.vuex('user_type',that.currentLoginType);
that.$u.vuex('vuex_token', res.token); that.$u.vuex('vuex_token', res.token);
// that.$u.vuex('vuex_token', 'fbc545a91cc94fe89296828a25a7e08e@9085553879028596738'); // that.$u.vuex('vuex_token', 'fbc545a91cc94fe89296828a25a7e08e@9085553879028596738');
await that.$u.vuex('user_message', JSON.stringify(res.user.user)); await that.$u.vuex('user_message', JSON.stringify(res.user.user));

View File

@ -0,0 +1,111 @@
<!-- 修改密码 -->
<template>
<view class="aircraft-setting">
<view class="setting-item">
<text>原密码</text>
<u-input v-model.trim="form.oldPass" input-align="right" type="password"
placeholder="请输入原密码" :clearable="false" />
</view>
<view class="setting-item">
<text>新密码</text>
<u-input v-model.trim="form.newPass" input-align="right" type="password"
placeholder="请输入新密码" :clearable="false" />
</view>
<view class="setting-item">
<text>确认密码</text>
<u-input v-model.trim="form.comPass" input-align="right" type="password"
placeholder="请输入确认密码" :clearable="false" />
</view>
<view class="setting-save" @click="submit">保存</view>
<u-toast ref="uToast"></u-toast>
<Loading :show="loading" />
</view>
</template>
<script>
import { encrypt } from '@/utils/rsaEncrypt'
export default {
// #ifdef MP
options: {
styleIsolation: 'shared'
},
// #endif
data() {
return {
loading: false, //
form:{
oldPass: '',
newPass: '',
comPass: ''
},
isPilot: this.$store.state.user_type == 1,
}
},
methods:{
//
async submit(){
const { oldPass, newPass, comPass } = this.form;
if(!oldPass||!newPass||!comPass){
this.$refs.uToast.show({type: 'warning',title: "请完善信息!"});
}else if(newPass !== comPass){
this.$refs.uToast.show({type: 'warning',title: "新密码与确认密码不同!"});
}else{
try {
this.loading = true;
let res = await this.$api.aUpdatePass({
oldPass: encrypt(oldPass),
newPass: encrypt(newPass),
});
if(res.status&&res.status===400){
this.$refs.uToast.show({type: 'error',title: "密码修改失败!"});
}else{
this.$refs.uToast.show({type: 'success',title: "密码修改成功,请重新登录!"});
}
} catch (error) {
this.$refs.uToast.show({type: 'error',title: "密码修改失败!"});
} finally {
this.loading = false;
}
}
}
},
}
</script>
<style scoped lang="scss">
.aircraft-setting {
display: flex;
flex-direction: column;
min-height: 100vh;
.setting-item{
padding: 24rpx 0;
margin: 0 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 2rpx solid #EBEDF0;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 28rpx;
color: #000000;
}
.setting-save{
margin: auto 32rpx 52rpx;
border-radius: 40rpx;
background: #FBCB11;
display: flex;
align-items: center;
justify-content: center;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 28rpx;
color: #020202;
padding: 22rpx 0;
&:active{
margin: auto 42rpx 52rpx;
padding: 18rpx 0;
opacity: 0.8;
}
}
}
</style>

View File

@ -1,13 +1,42 @@
<!-- 个人信息 --> <!-- 个人信息 -->
<template> <template>
<view class="aircraft-setting"> <view class="aircraft-setting">
<view class="setting-item">
<text><text>*</text>姓名</text>
<u-input v-model.trim="form.name" input-align="right"
placeholder="请输入姓名" :clearable="false" />
</view>
<view class="setting-item">
<text><text>*</text>手机号码</text>
<u-input v-model.number="form.phone" input-align="right"
placeholder="请输入手机号码" type="number" :clearable="false" />
</view>
<view class="setting-item">
<text><text>*</text>区域</text>
<u-input v-model="form.areaName" input-align="right" @click="handleClickPick('区域')"
placeholder="请选择区域" type="select" :clearable="false" />
</view>
<view class="setting-item">
<text>景区</text>
<u-input v-model="form.scenicName" input-align="right" @click="handleClickPick('景区')"
placeholder="请选择景区" type="select" :clearable="false" />
</view>
<view class="setting-item">
<text>入职时间</text>
<u-input v-model="form.hireDate" input-align="right" @click="showTime=true"
placeholder="请选择入职时间" type="select" :clearable="false" />
</view>
<view class="setting-save" @click="submit">保存</view>
<u-picker mode="selector" v-model="show" :default-selector="getDefaultSelector" :range="pickTitle==='区域'?areas:scenics"
range-key="name" confirm-color="#f7c04d" :title="pickTitle+'选择'" @confirm="handleChangePick"></u-picker>
<u-picker mode="time" v-model="showTime" :params="params" confirm-color="#f7c04d" title="入职时间选择"
@confirm="handleChangeTime" :default-time="form.hireDate"></u-picker>
<u-toast ref="uToast"></u-toast> <u-toast ref="uToast"></u-toast>
<Loading :show="loading" /> <Loading :show="loading" />
</view> </view>
</template> </template>
<script> <script>
import configService from '@/common/config.service.js';
export default { export default {
// #ifdef MP // #ifdef MP
options: { options: {
@ -16,53 +45,134 @@ export default {
// #endif // #endif
data() { data() {
return { return {
// #ifdef MP
//
StatusBar: this.StatusBar || 0,
CustomBarHeight: this.Custom.height+(this.Custom.top-this.StatusBar)*2 || 0,
// #endif
loading: true, // loading: true, //
form:{
name: '',
phone: '',
areaId: '',
areaName: '',
scenicId: '',
scenicName: '',
hireDate: ''
},
//
params: {
year: true,
month: true,
day: true,
hour: true,
minute: true,
second: true
},
//
areas:[],
//
scenics: [],
//
pickTitle: '区域',
//
show: false,
//
showTime: false,
//
userMessage: this.$store.state.vuex_token === ''?{}:JSON.parse(this.$store.state.user_message),
isPilot: this.$store.state.user_type == 1,
} }
}, },
computed:{ computed:{
//
getDefaultSelector(){
const isArea = this.pickTitle === '区域';
const arr = isArea ? this.areas : this.scenics;
const index = this.form[isArea?'areaId':'scenicId'];
return index?[arr.findIndex(item=>item.id === index)]:[0];
}
},
created() {
this.$nextTick(()=>{
this.init();
});
}, },
methods: { methods: {
// //
back() { async init(){
uni.navigateBack(); let resp = await this.$api.aSelfDetail(this.userMessage.id);
let res = await this.$api.allAreas();
if(!res){
this.$refs.uToast.show({type: 'error',title: "区域获取失败!"});
}else{
this.areas = res || [];
}
if(!resp){
this.$refs.uToast.show({type: 'error',title: "个人信息获取失败!"});
}else{
this.form = resp;
if(resp.areaId){
let resx = await this.$api.allScenicsByAreaId({areaId: this.form.areaId});
this.scenics = resx || [];
}
}
},
//
handleChangeTime({year,month,day,hour,minute,second}){
this.form.hireDate = `${year}-${month}-${day} ${hour}:${minute}:${second}`;
},
//
async handleChangePick(index){
if(this.pickTitle === '区域'){
const val = this.areas[index[0]];
if(val.id === this.form.areaId) return;
this.form.areaId = val.id;
this.form.areaName = val.name;
this.form.scenicName = '';
this.form.scenicId = '';
let res = await this.$api.allScenicsByAreaId({areaId: val.id});
if(!res){
this.$refs.uToast.show({type: 'error',title: "景区获取失败!"});
}else{
this.scenics = res || [];
}
}else{
const val = this.scenics[index[0]];
this.form.scenicName = val.name;
this.form.scenicId = val.id;
}
},
//
handleClickPick(title){
if(title === '景区' && !this.form.areaId){
this.$refs.uToast.show({type: 'warning',title: "请选择区域!"});
return;
}
this.show = true;
this.pickTitle = title;
}, },
// //
async submit(e){ async submit(){
const { name, phone, areaId } = this.form;
if(!name){
this.$refs.uToast.show({type: 'warning',title: "请填写姓名!"});
return;
}else if(!phone||!this.$u.test.mobile(phone)){
this.$refs.uToast.show({type: 'warning',title: "手机号格式错误!"});
return;
}else if(!areaId){
this.$refs.uToast.show({type: 'warning',title: "请选择区域!"});
return;
}else{
try{
this.loading = true;
delete this.form.password;
let res = await this.$api.aEditSelf(this.form);
this.$refs.uToast.show({type: 'success',title: "个人信息修改成功!"});
this.init();
}catch(e){
this.$refs.uToast.show({type: 'error',title: "个人信息修改失败!"});
}finally{
this.loading = false;
}
}
}, },
//
logout(){
let that = this;
uni.showModal({
title: '注销',
content: '是否确认退出登录?',
confirmColor: '#94d500',
success: async(res) => {
if (res.confirm) {
that.$u.vuex('vuex_token', '');
that.$u.vuex('user_message', {});
that.form = {};
that.$api.logOut();
// that.$emit('userLogOut');
uni.navigateBack({complete() {
setTimeout(()=>{
uni.showToast({
icon: 'none',title: '退出登录成功!'
})
},300);
}})
}
}
})
}
}, },
onLoad(options) { onLoad(options) {
try{ try{
@ -78,5 +188,48 @@ export default {
<style scoped lang="scss"> <style scoped lang="scss">
.aircraft-setting { .aircraft-setting {
display: flex;
flex-direction: column;
min-height: 100vh;
.setting-item{
padding: 24rpx 0;
margin: 0 32rpx;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 2rpx solid #EBEDF0;
font-family: PingFang SC, PingFang SC;
font-weight: 400;
font-size: 28rpx;
color: #000000;
text{
text{
margin-bottom: -20rpx;
color: #FE020E;
font-size: 32rpx;
margin-right: 8rpx;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
}
}
}
.setting-save{
margin: auto 32rpx 52rpx;
border-radius: 40rpx;
background: #FBCB11;
display: flex;
align-items: center;
justify-content: center;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 30rpx;
color: #020202;
padding: 22rpx 0;
&:active{
margin: auto 42rpx 52rpx;
padding: 18rpx 0;
opacity: 0.8;
}
}
} }
</style> </style>

View File

@ -13,7 +13,8 @@
</view> </view>
<view class="function-list"> <view class="function-list">
<view class="functions"> <view class="functions">
<view class="function-item" v-for="(item,index) in functions" :key="index"> <view class="function-item" v-for="(item,index) in isPilot?functions:functions.slice(2)"
:key="index" @click="handleClickFunction(item)">
<view class="fi-left"><u-icon :name="fileUrl+item.icon" size="50" />{{ item.name }}</view> <view class="fi-left"><u-icon :name="fileUrl+item.icon" size="50" />{{ item.name }}</view>
<u-icon name="arrow-right" color="#ccc" size="30" /> <u-icon name="arrow-right" color="#ccc" size="30" />
</view> </view>
@ -61,12 +62,13 @@ export default {
},{ },{
name: '个人信息', name: '个人信息',
icon: 'self.png', icon: 'self.png',
url: '' url: '/aircraft/server/my/child_pages/setting'
},{ },{
name: '修改密码', name: '修改密码',
icon: 'password.png', icon: 'password.png',
url: '' url: '/aircraft/server/my/child_pages/reset-password'
}] }],
isPilot: this.$store.state.user_type == 1,
} }
}, },
computed:{ computed:{
@ -80,6 +82,11 @@ export default {
this.userMessage = {}; this.userMessage = {};
} }
}, },
//
handleClickFunction({url}){
if(url) uni.navigateTo({url: url})
},
// 退
loginout(){ loginout(){
let that = this; let that = this;
uni.showModal({ uni.showModal({

View File

@ -6,6 +6,13 @@ const install = (Vue, vm) => {
vm.$api.aLogin = async (params = {}) => await vm.$u.post('/auth/login/a', params);// 飞行员端登录 vm.$api.aLogin = async (params = {}) => await vm.$u.post('/auth/login/a', params);// 飞行员端登录
vm.$api.bLogin = async (params = {}) => await vm.$u.post('/auth/login/b', params);// 用户端登录 vm.$api.bLogin = async (params = {}) => await vm.$u.post('/auth/login/b', params);// 用户端登录
vm.$api.logout = async () => await vm.$u.delete('/auth/logout');// 用户登出 vm.$api.logout = async () => await vm.$u.delete('/auth/logout');// 用户登出
vm.$api.aSelfDetail = async (id) => await vm.$u.get(`/api/emEmployees/${id}`);// 查询飞行员详情
vm.$api.aEditSelf = async (params = {}) => await vm.$u.put(`/api/emEmployees`,params);// 修改飞行员信息
vm.$api.aUpdatePass = async (params = {}) => await vm.$u.post(`/api/emEmployees/updatePass`,params);// 修改飞行员密码
// 区域管理
vm.$api.allAreas = async () => await vm.$u.get('/emArea/all');// 获取全部区域
vm.$api.allScenicsByAreaId = async (params = {}) => await vm.$u.get('/emScenic/all',params);// 获取区域下全部景区
// 轮播图管理 // 轮播图管理
vm.$api.allBanners = async () => await vm.$u.get('/cpBanner/all');// 获取全部轮播图 vm.$api.allBanners = async () => await vm.$u.get('/cpBanner/all');// 获取全部轮播图

View File

@ -33,7 +33,7 @@ const install = (Vue, vm) => {
// uni.showToast({'title':'请先登录', 'icon':'none'}); // uni.showToast({'title':'请先登录', 'icon':'none'});
// return false; // return false;
// } // }
console.log('config,',config); // console.log('config,',config);
config.header.Authorization = vm.$store.state.vuex_token; config.header.Authorization = vm.$store.state.vuex_token;
// if (config.method == 'POST') { // if (config.method == 'POST') {
// config.data['__token__'] = vm.vuex__token__; // config.data['__token__'] = vm.vuex__token__;
@ -47,8 +47,7 @@ const install = (Vue, vm) => {
// vm.$u.vuex('vuex__token__', res.header.__token__); // vm.$u.vuex('vuex__token__', res.header.__token__);
// } // }
let result = res.data; let result = res.data;
console.log(res); switch (res.statusCode) {
switch (result.code) {
case 1: case 1:
case 0: case 0:
return result; return result;
@ -56,8 +55,14 @@ const install = (Vue, vm) => {
case 401: case 401:
//需要登录的接口当token 过期时,到登录页面 //需要登录的接口当token 过期时,到登录页面
vm.$u.vuex('vuex_token', ''); vm.$u.vuex('vuex_token', '');
// vm.$u.route('/pages/login/mobilelogin'); vm.$u.vuex('user_message', {});
uni.navigateTo({url:'/pages/login/login'}); vm.$u.vuex('user_type', '');
uni.navigateTo({url:`/aircraft/server/my/child_pages/login?nextUrl=/${getCurrentPages()[0].route}`,complete() {
setTimeout(()=>{
uni.showToast({title: vm.$store.state.vuex_token?'当前登录过期,请重新登录!':
'只有登录成功后才可访问',icon: 'none'});
},300);
}});
return result; return result;
break; break;
case 403: //没有权限访问 case 403: //没有权限访问
@ -71,7 +76,8 @@ const install = (Vue, vm) => {
if(result.errorMsg === '只有登录成功后才可访问'){ if(result.errorMsg === '只有登录成功后才可访问'){
vm.$u.vuex('vuex_token', ''); vm.$u.vuex('vuex_token', '');
vm.$u.vuex('user_message', {}); vm.$u.vuex('user_message', {});
uni.navigateTo({url:`/pages/mobile_web/my/child_pages/login?nextUrl=/${getCurrentPages()[0].route}`,complete() { vm.$u.vuex('user_type', '');
uni.navigateTo({url:`/aircraft/server/my/child_pages/login?nextUrl=/${getCurrentPages()[0].route}`,complete() {
setTimeout(()=>{ setTimeout(()=>{
uni.showToast({title: vm.$store.state.vuex_token?'当前登录过期,请重新登录!': uni.showToast({title: vm.$store.state.vuex_token?'当前登录过期,请重新登录!':
'只有登录成功后才可访问',icon: 'none'}); '只有登录成功后才可访问',icon: 'none'});

View File

@ -82,7 +82,7 @@
width: 100%; width: 100%;
height: 5px; height: 5px;
border-radius: 50%; border-radius: 50%;
background: #94d500; background: #a8f0ee;
opacity: 0.1; opacity: 0.1;
animation: animloaders .5s linear infinite; animation: animloaders .5s linear infinite;
} }
@ -95,7 +95,7 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
border-radius: 3px; border-radius: 3px;
background: linear-gradient(180deg, #96fe11 0%, #f0fdbf 100%); background: linear-gradient(180deg, #a8f0ee 0%, #f0fdbf 100%);
animation: animloader .5s linear infinite; animation: animloader .5s linear infinite;
} }
} }

View File

@ -61,10 +61,18 @@
"navigationBarTitleText": "历史订单" "navigationBarTitleText": "历史订单"
} }
}, },
{
"path": "my/child_pages/reset-password",
"style": {
"navigationBarTitleText": "修改密码",
"navigationStyle": "default"
}
},
{ {
"path": "my/child_pages/setting", "path": "my/child_pages/setting",
"style": { "style": {
"navigationBarTitleText": "个人信息" "navigationBarTitleText": "个人信息",
"navigationStyle": "default"
} }
}] }]
} }

View File

@ -12,7 +12,7 @@ try {
} }
// 需要永久存储且下次APP启动需要取出的在state中的变量名 // 需要永久存储且下次APP启动需要取出的在state中的变量名
let saveStateKeys = ['user_message', 'vuex_token']; let saveStateKeys = ['user_message', 'vuex_token', 'user_type'];
// 保存变量到本地存储中 // 保存变量到本地存储中
const saveLifeData = function(key, value) { const saveLifeData = function(key, value) {
@ -33,7 +33,10 @@ const store = new Vuex.Store({
// 加上vuex_前缀是防止变量名冲突也让人一目了然 // 加上vuex_前缀是防止变量名冲突也让人一目了然
// vuex_token: 'fbc545a91cc94fe89296828a25a7e08e@9085553879028596738', // vuex_token: 'fbc545a91cc94fe89296828a25a7e08e@9085553879028596738',
vuex_token: lifeData.vuex_token ? lifeData.vuex_token : '', vuex_token: lifeData.vuex_token ? lifeData.vuex_token : '',
// 用户信息
user_message:lifeData.user_message ? lifeData.user_message : {}, user_message:lifeData.user_message ? lifeData.user_message : {},
// 用户类型-1飞行员、0用户
user_type:lifeData.user_type ? lifeData.user_type : '',
}, },
mutations: { mutations: {
$uStore(state, payload) { $uStore(state, payload) {