增加个人信息的加载

This commit is contained in:
YunaiV 2021-11-26 09:47:23 +08:00
parent 86ef156de4
commit 2da6a746e4
13 changed files with 295 additions and 99 deletions

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.framework.security.core.util; package cn.iocoder.yudao.framework.security.core.util;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.LoginUser;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
@ -11,6 +12,7 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.Set; import java.util.Set;
/** /**
@ -100,7 +102,9 @@ public class SecurityFrameworkUtils {
WebFrameworkUtils.setLoginUserId(request, loginUser.getId()); WebFrameworkUtils.setLoginUserId(request, loginUser.getId());
WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType()); WebFrameworkUtils.setLoginUserType(request, loginUser.getUserType());
// TODO @jason使用 userId 会不会更合适哈 // TODO @jason使用 userId 会不会更合适哈
if (Objects.equals(UserTypeEnum.ADMIN.getValue(), loginUser.getUserType())) {
org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername()); org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(loginUser.getUsername());
} }
}
} }

View File

@ -1,11 +1,11 @@
### 请求 /system/user/profile/get 接口 => 没有权限 ### 请求 /member/user/profile/get 接口 => 没有权限
GET {{userServerUrl}}/system/user/profile/get GET {{userServerUrl}}/member/user/profile/get
Authorization: Bearer test245 Authorization: Bearer test245
### 请求 /system/user/profile/revise-nickname 接口 成功 ### 请求 /member/user/profile/revise-nickname 接口 成功
PUT {{userServerUrl}}/system/user/profile/update-nickname?nickName=yunai222 PUT {{userServerUrl}}/member/user/profile/update-nickname?nickName=yunai222
Authorization: Bearer test245 Authorization: Bearer test245
### 请求 /system/user/profile/get-user-info 接口 成功 ### 请求 /member/user/profile/get-user-info 接口 成功
GET {{userServerUrl}}/system/user/profile/get-user-info?id=245 GET {{userServerUrl}}/member/user/profile/get-user-info?id=245
Authorization: Bearer test245 Authorization: Bearer test245

View File

@ -27,7 +27,7 @@ import static cn.iocoder.yudao.userserver.modules.member.enums.MbrErrorCodeConst
@Api(tags = "用户个人中心") @Api(tags = "用户个人中心")
@RestController @RestController
@RequestMapping("/system/user/profile") @RequestMapping("/member/user/profile")
@Validated @Validated
@Slf4j @Slf4j
public class SysUserProfileController { public class SysUserProfileController {
@ -57,14 +57,13 @@ public class SysUserProfileController {
return success(avatar); return success(avatar);
} }
@GetMapping("/get-user-info") @GetMapping("/get")
@ApiOperation("取用户头像与昵称") @ApiOperation("得基本信息")
@PreAuthenticated @PreAuthenticated
public CommonResult<MbrUserInfoRespVO> getUserInfo() { public CommonResult<MbrUserInfoRespVO> getUserInfo() {
return success(userService.getUserInfo(getLoginUserId())); return success(userService.getUserInfo(getLoginUserId()));
} }
@PostMapping("/update-mobile") @PostMapping("/update-mobile")
@ApiOperation(value = "修改用户手机") @ApiOperation(value = "修改用户手机")
@PreAuthenticated @PreAuthenticated

View File

@ -65,6 +65,7 @@ public interface MbrUserService {
/** /**
* 根据用户id获取用户头像与昵称 * 根据用户id获取用户头像与昵称
*
* @param userId 用户id * @param userId 用户id
* @return 用户响应实体类 * @return 用户响应实体类
*/ */

View File

@ -40,7 +40,6 @@ public class SysAuthController {
@Resource @Resource
private SysSocialService socialService; private SysSocialService socialService;
@PostMapping("/login") @PostMapping("/login")
@ApiOperation("使用手机 + 密码登录") @ApiOperation("使用手机 + 密码登录")
public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) { public CommonResult<SysAuthLoginRespVO> login(@RequestBody @Valid SysAuthLoginReqVO reqVO) {

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,9 @@
import { request } from '@/common/js/request.js'
// 获得用户的基本信息
export function getUserInfo() {
return request({
url: 'member/user/profile/get',
method: 'get'
})
}

View File

@ -0,0 +1,27 @@
import { request } from '@/common/js/request.js'
// 手机号 + 密码登陆
export function login(mobile, password) {
const data = {
mobile,
password
}
return request({
url: 'login',
method: 'post',
data: data
})
}
// 手机号 + 验证码登陆
export function smsLogin(mobile, code) {
const data = {
mobile,
code
}
return request({
url: 'sms-login',
method: 'post',
data: data
})
}

View File

@ -1,18 +1,18 @@
const BASE_URL = 'http://127.0.0.1:28080/api/'; const BASE_URL = 'http://127.0.0.1:28080/api/';
import { msg } from './util' import { msg, getAuthToken } from './util'
export const request = (options) => { export const request = (options) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 发起请求 // 发起请求
const authToken = getAuthToken();
uni.request({ uni.request({
url: BASE_URL + options.url, url: BASE_URL + options.url,
method: options.method || 'GET', method: options.method || 'GET',
data: options.data || {}, data: options.data || {},
header: { header: {
'Authorization': '' // TODO 芋艿:带 token 'Authorization': authToken ? `Bearer ${authToken}` : ''
} }
}).then(res => { }).then(res => {
debugger
res = res[1]; res = res[1];
const statusCode = res.statusCode; const statusCode = res.statusCode;
if (statusCode !== 200) { if (statusCode !== 200) {

View File

@ -34,14 +34,103 @@ export const throttle = (fn, delay=500) => {
} }
/** /**
* toast * toast 提示
*
* @param {String} title 标题
* @param {Object} param 拓展参数
* @param {Integer} param.duration 持续时间
* @param {Boolean} param.mask 是否遮罩
* @param {Boolean} param.icon 图标
*/ */
export const msg = (title = '', param={}) => { export const msg = (title = '', param={}) => {
if(!title) return; if (!title) {
return;
}
uni.showToast({ uni.showToast({
title, title,
duration: param.duration || 1500, duration: param.duration || 1500,
mask: param.mask || false, mask: param.mask || false,
icon: param.icon || 'none' icon: param.icon || 'none' // TODO 芋艿:是否要区分下 error 的提示,或者专门的封装
}); });
} }
/**
* 检查登录
*
* @param {Boolean} options.nav 如果未登陆是否跳转到登陆页默认为 true
* @return {Boolean} 是否登陆
*/
export const isLogin = (options = {}) => {
const token = this.getAuthToken();
if (token) {
return true;
}
// 若 nav 不为 false则进行跳转登陆页
if (options.nav !== false) {
uni.navigateTo({
url: '/pages/auth/login'
})
}
return false;
}
/**
* 获得认证 Token
*
* @return 认证 Token
*/
export const getAuthToken = () => {
return uni.getStorageSync('token');
}
/**
* 校验参数
*
* @param {String} 字符串
* @param {String} 数据的类型例如说 mobile 手机号tel 座机 TODO 芋艿是否组件里解决
*/
export const checkStr = (str, type) => {
switch (type) {
case 'mobile': //手机号码
return /^1[3|4|5|6|7|8|9][0-9]{9}$/.test(str);
case 'tel': //座机
return /^(0\d{2,3}-\d{7,8})(-\d{1,4})?$/.test(str);
case 'card': //身份证
return /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/.test(str);
case 'mobileCode': //6位数字验证码
return /^[0-9]{6}$/.test(str)
case 'pwd': //密码以字母开头长度在6~18之间只能包含字母、数字和下划线
return /^([a-zA-Z0-9_]){6,18}$/.test(str)
case 'payPwd': //支付密码 6位纯数字
return /^[0-9]{6}$/.test(str)
case 'postal': //邮政编码
return /[1-9]\d{5}(?!\d)/.test(str);
case 'QQ': //QQ号
return /^[1-9][0-9]{4,9}$/.test(str);
case 'email': //邮箱
return /^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+$/.test(str);
case 'money': //金额(小数点2位)
return /^\d*(?:\.\d{0,2})?$/.test(str);
case 'URL': //网址
return /(http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?/.test(str)
case 'IP': //IP
return /((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))/.test(str);
case 'date': //日期时间
return /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2})(?:\:\d{2}|:(\d{2}):(\d{2}))$/.test(str) || /^(\d{4})\-(\d{2})\-(\d{2})$/
.test(str)
case 'number': //数字
return /^[0-9]$/.test(str);
case 'english': //英文
return /^[a-zA-Z]+$/.test(str);
case 'chinese': //中文
return /^[\\u4E00-\\u9FA5]+$/.test(str);
case 'lower': //小写
return /^[a-z]+$/.test(str);
case 'upper': //大写
return /^[A-Z]+$/.test(str);
case 'HTML': //HTML标记
return /<("[^"]*"|'[^']*'|[^'">])*>/.test(str);
default:
return true;
}
}

View File

@ -42,7 +42,7 @@
placeholder="请输入密码" placeholder-style="color: #909399"/> placeholder="请输入密码" placeholder-style="color: #909399"/>
</view> </view>
</view> </view>
<mix-button ref="confirmBtn" text="立即登录" marginTop="60rpx" @onConfirm="login"></mix-button> <mix-button ref="confirmBtn" text="立即登录" marginTop="60rpx" @onConfirm="mobileLogin"></mix-button>
<!-- 切换登陆 --> <!-- 切换登陆 -->
<view class="login-type" v-if="loginType == 'code'" @click="setLoginType('password')">账号密码登录</view> <view class="login-type" v-if="loginType == 'code'" @click="setLoginType('password')">账号密码登录</view>
<view class="login-type" v-else @click="setLoginType('code')">免密登录</view> <view class="login-type" v-else @click="setLoginType('code')">免密登录</view>
@ -79,8 +79,10 @@
<script> <script>
import { checkStr } from '@/common/js/util' import { checkStr } from '@/common/js/util'
import { login, smsLogin } from '@/api/system/auth.js'
import loginMpWx from './mixin/login-mp-wx.js' import loginMpWx from './mixin/login-mp-wx.js'
import loginAppWx from './mixin/login-app-wx.js' import loginAppWx from './mixin/login-app-wx.js'
export default{ export default{
mixins: [loginMpWx, loginAppWx], mixins: [loginMpWx, loginAppWx],
data(){ data(){
@ -95,16 +97,9 @@
onLoad() { onLoad() {
}, },
methods: { methods: {
loginSuccessCallBack(data){
this.$util.msg('登录成功');
this.$store.commit('setToken', data);
setTimeout(()=>{
uni.navigateBack();
}, 1000)
},
// //
async login(){ async mobileLogin() {
// // TODO
if (!this.agreement) { if (!this.agreement) {
this.$util.msg('请阅读并同意用户服务及隐私协议'); this.$util.msg('请阅读并同意用户服务及隐私协议');
this.$refs.confirmBtn.stop(); this.$refs.confirmBtn.stop();
@ -116,22 +111,36 @@
this.$refs.confirmBtn.stop(); this.$refs.confirmBtn.stop();
return; return;
} }
if (!checkStr(code, 'mobileCode')) { if (this.loginType === 'code' && !checkStr(code, 'mobileCode')) {
this.$util.msg('验证码错误'); this.$util.msg('验证码格式错误');
this.$refs.confirmBtn.stop();
return;
}
if (this.loginType === 'password' && !checkStr(password, 'pwd')) {
this.$util.msg('密码格式错误');
this.$refs.confirmBtn.stop(); this.$refs.confirmBtn.stop();
return; return;
} }
// //
const res = await this.$request('user', 'login', {mobile,code}); try {
const data = this.loginType === 'code' ? await smsLogin(mobile, code)
: await login(mobile, password);
//
this.loginSuccessCallBack(data);
} finally {
this.$refs.confirmBtn.stop(); this.$refs.confirmBtn.stop();
if (res.status === 1){
this.loginSuccessCallBack(res.data);
} else{
this.$util.msg(res.msg);
} }
}, },
//
loginSuccessCallBack(data){
this.$util.msg('登录成功');
this.$store.commit('setToken', data);
// TODO
setTimeout(()=>{
uni.navigateBack();
}, 1000)
},
navBack() { navBack() {
uni.navigateBack(); uni.navigateBack();
}, },

View File

@ -82,7 +82,8 @@
}; };
}, },
onShow() { onShow() {
// TODO //
this.$store.dispatch('obtainUserInfo');
// TODO // TODO
} }
} }

View File

@ -1,6 +1,7 @@
import Vue from 'vue' import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
// import {request} from '@/common/js/request' // import {request} from '@/common/js/request'
import { getUserInfo } from '@/api/member/userProfile.js'
Vue.use(Vuex) Vue.use(Vuex)
@ -10,7 +11,6 @@ const store = new Vuex.Store({
token: '', // 用户身份 Token token: '', // 用户身份 Token
userInfo: {}, // 用户基本信息 userInfo: {}, // 用户基本信息
timerIdent: false, // 全局 1s 定时器,只在全局开启一个,所有需要定时执行的任务监听该值即可,无需额外开启 TODO 芋艿:需要看看 timerIdent: false, // 全局 1s 定时器,只在全局开启一个,所有需要定时执行的任务监听该值即可,无需额外开启 TODO 芋艿:需要看看
orderCount: {}, // 订单数量
}, },
getters: { getters: {
hasLogin(state){ hasLogin(state){
@ -18,7 +18,7 @@ const store = new Vuex.Store({
} }
}, },
mutations: { mutations: {
//更新state数据 // 更新 state 的通用方法
setStateAttr(state, param) { setStateAttr(state, param) {
if (param instanceof Array) { if (param instanceof Array) {
for(let item of param){ for(let item of param){
@ -30,61 +30,33 @@ const store = new Vuex.Store({
}, },
// 更新token // 更新token
setToken(state, data) { setToken(state, data) {
const {token, tokenExpired} = data; // 设置 Token
const { token } = data;
state.token = token; state.token = token;
uni.setStorageSync('uniIdToken', token); uni.setStorageSync('token', token);
uni.setStorageSync('tokenExpired', tokenExpired);
this.dispatch('getUserInfo'); //更新用户信息 // 加载用户信息
this.dispatch('getCartCount');//更新购物车数量 this.dispatch('obtainUserInfo');
uni.$emit('refreshCart');//刷新购物车
this.dispatch('getOrderCount'); //更新订单数量
}, },
// 退出登录 // 退出登录
logout(state) { logout(state) {
// 清空 Token
state.token = ''; state.token = '';
uni.removeStorageSync('uniIdToken'); uni.removeStorageSync('token');
this.dispatch('getCartCount');//更新购物车数量 // 清空用户信息 TODO 芋艿:这里 setTimeout 的原因是,上面可能还有一些 request 请求。后续得优化下
uni.$emit('refreshCart');//刷新购物车
this.dispatch('getOrderCount'); //更新订单数量
setTimeout(()=>{ setTimeout(()=>{
state.userInfo = {}; state.userInfo = {};
}, 1100) }, 1100)
}, },
}, },
actions: { actions: {
//更新用户信息 // 获得用户基本信息
async getUserInfo({state, commit}){ async obtainUserInfo({state, commit}) {
const res = await request('user', 'get', {}, { const data = await getUserInfo();
checkAuthInvalid: false
});
if(res.status === 1){
const userInfo = res.data;
commit('setStateAttr', { commit('setStateAttr', {
key: 'userInfo', key: 'userInfo',
val: userInfo
})
}
},
//更新用户订单数量
async getOrderCount({state, commit}){
let data = {
c0: 0,
c1: 0,
c2: 0,
c3: 0
}
if(state.token){
try {
const res = await request('order', 'getOrderCount');
data = res;
}catch (err){
console.error('更新用户订单数量 => ', err);
}
}
commit('setStateAttr', {
key: 'orderCount',
val: data val: data
}) });
} }
} }
}) })