feat(user): 实现自动登录并优化用户相关功能
- 添加自动登录功能,通过 OpenID 实现一键登录 - 优化用户数据加载和保存逻辑,确保数据完整性 - 处理邀请关系,自动登录时建立邀请关系 - 更新订单统计钩子,增加用户身份检查 - 修复首页轮播图点击事件,实现跳转功能
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import {useEffect} from 'react'
|
import {useEffect} from 'react'
|
||||||
import {useUser} from "@/hooks/useUser";
|
import {useUser} from "@/hooks/useUser";
|
||||||
|
import {Empty} from '@nutui/nutui-react-taro';
|
||||||
import {Text} from '@tarojs/components';
|
import {Text} from '@tarojs/components';
|
||||||
|
|
||||||
function Admin() {
|
function Admin() {
|
||||||
@@ -12,7 +13,16 @@ function Admin() {
|
|||||||
|
|
||||||
if (!isAdmin()) {
|
if (!isAdmin()) {
|
||||||
return (
|
return (
|
||||||
<Text>您不是管理员</Text>
|
<Empty
|
||||||
|
description="您不是管理员"
|
||||||
|
imageSize={80}
|
||||||
|
style={{
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
height: 'calc(100vh - 200px)'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
|
||||||
|
</Empty>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ export const useOrderStats = () => {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
|
||||||
|
if(!Taro.getStorageSync('UserId')){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// TODO 读取订单数量
|
// TODO 读取订单数量
|
||||||
const pending = await pageShopOrder({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), statusFilter: 0})
|
const pending = await pageShopOrder({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), statusFilter: 0})
|
||||||
const paid = await pageShopOrder({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), statusFilter: 1})
|
const paid = await pageShopOrder({ page: 1, limit: 1, userId: Taro.getStorageSync('UserId'), statusFilter: 1})
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
import Taro from '@tarojs/taro';
|
import Taro from '@tarojs/taro';
|
||||||
import { User } from '@/api/system/user/model';
|
import { User } from '@/api/system/user/model';
|
||||||
import { getUserInfo, updateUserInfo } from '@/api/layout';
|
import { getUserInfo, updateUserInfo, loginByOpenId } from '@/api/layout';
|
||||||
|
import { TenantId } from '@/config/app';
|
||||||
|
import {getStoredInviteParams, handleInviteRelation} from '@/utils/invite';
|
||||||
|
|
||||||
// 用户Hook
|
// 用户Hook
|
||||||
export const useUser = () => {
|
export const useUser = () => {
|
||||||
@@ -9,8 +11,62 @@ export const useUser = () => {
|
|||||||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
// 自动登录(通过OpenID)
|
||||||
|
const autoLoginByOpenId = async () => {
|
||||||
|
try {
|
||||||
|
const res = await new Promise<any>((resolve, reject) => {
|
||||||
|
Taro.login({
|
||||||
|
success: (loginRes) => {
|
||||||
|
loginByOpenId({
|
||||||
|
code: loginRes.code,
|
||||||
|
tenantId: TenantId
|
||||||
|
}).then(async (data) => {
|
||||||
|
if (data) {
|
||||||
|
// 保存登录信息
|
||||||
|
saveUserToStorage(data.access_token, data.user);
|
||||||
|
setUser(data.user);
|
||||||
|
setIsLoggedIn(true);
|
||||||
|
|
||||||
|
// 处理邀请关系
|
||||||
|
if (data.user?.userId) {
|
||||||
|
try {
|
||||||
|
const inviteSuccess = await handleInviteRelation(data.user.userId);
|
||||||
|
if (inviteSuccess) {
|
||||||
|
console.log('自动登录时邀请关系建立成功');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('自动登录时处理邀请关系失败:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(data.user);
|
||||||
|
} else {
|
||||||
|
reject(new Error('自动登录失败'));
|
||||||
|
}
|
||||||
|
}).catch(_ => {
|
||||||
|
// 首次注册,跳转到邀请注册页面
|
||||||
|
const pages = Taro.getCurrentPages();
|
||||||
|
const currentPage = pages[pages.length - 1];
|
||||||
|
const inviteParams = getStoredInviteParams()
|
||||||
|
if (currentPage?.route !== 'dealer/apply/add' && inviteParams?.inviter) {
|
||||||
|
return Taro.navigateTo({
|
||||||
|
url: '/dealer/apply/add'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
fail: reject
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return res;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('自动登录失败:', error);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 从本地存储加载用户数据
|
// 从本地存储加载用户数据
|
||||||
const loadUserFromStorage = () => {
|
const loadUserFromStorage = async () => {
|
||||||
try {
|
try {
|
||||||
const token = Taro.getStorageSync('access_token');
|
const token = Taro.getStorageSync('access_token');
|
||||||
const userData = Taro.getStorageSync('User');
|
const userData = Taro.getStorageSync('User');
|
||||||
@@ -26,8 +82,13 @@ export const useUser = () => {
|
|||||||
setIsLoggedIn(true);
|
setIsLoggedIn(true);
|
||||||
setUser({ userId, tenantId } as User);
|
setUser({ userId, tenantId } as User);
|
||||||
} else {
|
} else {
|
||||||
setUser(null);
|
// 没有本地登录信息,尝试自动登录
|
||||||
setIsLoggedIn(false);
|
console.log('没有本地登录信息,尝试自动登录...');
|
||||||
|
const autoLoginResult = await autoLoginByOpenId();
|
||||||
|
if (!autoLoginResult) {
|
||||||
|
setUser(null);
|
||||||
|
setIsLoggedIn(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('加载用户数据失败:', error);
|
console.error('加载用户数据失败:', error);
|
||||||
@@ -43,9 +104,24 @@ export const useUser = () => {
|
|||||||
try {
|
try {
|
||||||
Taro.setStorageSync('access_token', token);
|
Taro.setStorageSync('access_token', token);
|
||||||
Taro.setStorageSync('User', userInfo);
|
Taro.setStorageSync('User', userInfo);
|
||||||
Taro.setStorageSync('UserId', userInfo.userId);
|
|
||||||
Taro.setStorageSync('TenantId', userInfo.tenantId);
|
// 确保关键字段不为空时才保存,避免覆盖现有数据
|
||||||
Taro.setStorageSync('Phone', userInfo.phone);
|
if (userInfo.userId) {
|
||||||
|
Taro.setStorageSync('UserId', userInfo.userId);
|
||||||
|
}
|
||||||
|
if (userInfo.tenantId) {
|
||||||
|
Taro.setStorageSync('TenantId', userInfo.tenantId);
|
||||||
|
}
|
||||||
|
if (userInfo.phone) {
|
||||||
|
Taro.setStorageSync('Phone', userInfo.phone);
|
||||||
|
}
|
||||||
|
// 保存头像和昵称信息
|
||||||
|
if (userInfo.avatar) {
|
||||||
|
Taro.setStorageSync('Avatar', userInfo.avatar);
|
||||||
|
}
|
||||||
|
if (userInfo.nickname) {
|
||||||
|
Taro.setStorageSync('Nickname', userInfo.nickname);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('保存用户数据失败:', error);
|
console.error('保存用户数据失败:', error);
|
||||||
}
|
}
|
||||||
@@ -114,9 +190,16 @@ export const useUser = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const updatedUser = { ...user, ...userData };
|
// 先获取最新的用户信息,确保我们有完整的数据
|
||||||
|
const latestUserInfo = await getUserInfo();
|
||||||
|
|
||||||
|
// 合并最新的用户信息和要更新的数据
|
||||||
|
const updatedUser = { ...latestUserInfo, ...userData };
|
||||||
|
|
||||||
|
// 调用API更新用户信息
|
||||||
await updateUserInfo(updatedUser);
|
await updateUserInfo(updatedUser);
|
||||||
|
|
||||||
|
// 更新本地状态
|
||||||
setUser(updatedUser);
|
setUser(updatedUser);
|
||||||
|
|
||||||
// 更新本地存储
|
// 更新本地存储
|
||||||
@@ -216,7 +299,10 @@ export const useUser = () => {
|
|||||||
|
|
||||||
// 初始化时加载用户数据
|
// 初始化时加载用户数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadUserFromStorage();
|
loadUserFromStorage().catch(error => {
|
||||||
|
console.error('初始化用户数据失败:', error);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -231,6 +317,7 @@ export const useUser = () => {
|
|||||||
fetchUserInfo,
|
fetchUserInfo,
|
||||||
updateUser,
|
updateUser,
|
||||||
loadUserFromStorage,
|
loadUserFromStorage,
|
||||||
|
autoLoginByOpenId,
|
||||||
|
|
||||||
// 工具方法
|
// 工具方法
|
||||||
hasPermission,
|
hasPermission,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Swiper } from '@nutui/nutui-react-taro'
|
|||||||
import {CmsAd} from "@/api/cms/cmsAd/model";
|
import {CmsAd} from "@/api/cms/cmsAd/model";
|
||||||
import {Image} from '@nutui/nutui-react-taro'
|
import {Image} from '@nutui/nutui-react-taro'
|
||||||
import {getCmsAd} from "@/api/cms/cmsAd";
|
import {getCmsAd} from "@/api/cms/cmsAd";
|
||||||
|
import navTo from "@/utils/common";
|
||||||
|
|
||||||
const MyPage = () => {
|
const MyPage = () => {
|
||||||
const [item, setItem] = useState<CmsAd>()
|
const [item, setItem] = useState<CmsAd>()
|
||||||
@@ -18,10 +19,10 @@ const MyPage = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Swiper defaultValue={0} height={item?.height} indicator style={{ height: item?.height + 'px', display: 'none' }}>
|
<Swiper defaultValue={0} height={item?.height} indicator style={{ height: item?.height + 'px' }}>
|
||||||
{item?.imageList?.map((item) => (
|
{item?.imageList?.map((item) => (
|
||||||
<Swiper.Item key={item}>
|
<Swiper.Item key={item}>
|
||||||
<Image width="100%" height="100%" src={item.url} mode={'scaleToFill'} lazyLoad={false} style={{ height: item.height + 'px' }} />
|
<Image width="100%" height="100%" src={item.url} mode={'scaleToFill'} onClick={() => navTo(`${item.path}`)} lazyLoad={false} style={{ height: item.height + 'px' }} />
|
||||||
</Swiper.Item>
|
</Swiper.Item>
|
||||||
))}
|
))}
|
||||||
</Swiper>
|
</Swiper>
|
||||||
|
|||||||
Reference in New Issue
Block a user