- 将应用名称从"时里院子市集"更新为"通源堂健康生态平台" - 修改了config/env.ts中的生产环境应用名称配置 - 更新了src/cms/category/index.tsx中的分享标题引用 - 调整了src/admin/components/UserCell.tsx中的导航路径从/dealer/index到/doctor/index
336 lines
8.9 KiB
TypeScript
336 lines
8.9 KiB
TypeScript
import { useState, useEffect } from 'react';
|
||
import Taro from '@tarojs/taro';
|
||
import { User } from '@/api/system/user/model';
|
||
import { getUserInfo, updateUserInfo, loginByOpenId } from '@/api/layout';
|
||
import { TenantId } from '@/config/app';
|
||
import {getStoredInviteParams, handleInviteRelation} from '@/utils/invite';
|
||
|
||
// 用户Hook
|
||
export const useUser = () => {
|
||
const [user, setUser] = useState<User | null>(null);
|
||
const [isLoggedIn, setIsLoggedIn] = useState(false);
|
||
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: '/doctor/apply/add'
|
||
});
|
||
}
|
||
});
|
||
},
|
||
fail: reject
|
||
});
|
||
});
|
||
return res;
|
||
} catch (error) {
|
||
console.error('自动登录失败:', error);
|
||
return null;
|
||
}
|
||
};
|
||
|
||
// 从本地存储加载用户数据
|
||
const loadUserFromStorage = async () => {
|
||
try {
|
||
const token = Taro.getStorageSync('access_token');
|
||
const userData = Taro.getStorageSync('User');
|
||
const userId = Taro.getStorageSync('UserId');
|
||
const tenantId = Taro.getStorageSync('TenantId');
|
||
|
||
if (token && userData) {
|
||
const userInfo = typeof userData === 'string' ? JSON.parse(userData) : userData;
|
||
setUser(userInfo);
|
||
setIsLoggedIn(true);
|
||
} else if (token && userId) {
|
||
// 如果有token和userId但没有完整用户信息,标记为已登录但需要获取用户信息
|
||
setIsLoggedIn(true);
|
||
setUser({ userId, tenantId } as User);
|
||
} else {
|
||
// 没有本地登录信息,尝试自动登录
|
||
console.log('没有本地登录信息,尝试自动登录...');
|
||
const autoLoginResult = await autoLoginByOpenId();
|
||
if (!autoLoginResult) {
|
||
setUser(null);
|
||
setIsLoggedIn(false);
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('加载用户数据失败:', error);
|
||
setUser(null);
|
||
setIsLoggedIn(false);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
// 保存用户数据到本地存储
|
||
const saveUserToStorage = (token: string, userInfo: User) => {
|
||
try {
|
||
Taro.setStorageSync('access_token', token);
|
||
Taro.setStorageSync('User', userInfo);
|
||
|
||
// 确保关键字段不为空时才保存,避免覆盖现有数据
|
||
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) {
|
||
console.error('保存用户数据失败:', error);
|
||
}
|
||
};
|
||
|
||
// 登录用户
|
||
const loginUser = (token: string, userInfo: User) => {
|
||
setUser(userInfo);
|
||
setIsLoggedIn(true);
|
||
saveUserToStorage(token, userInfo);
|
||
};
|
||
|
||
// 退出登录
|
||
const logoutUser = () => {
|
||
setUser(null);
|
||
setIsLoggedIn(false);
|
||
|
||
// 清除本地存储
|
||
try {
|
||
Taro.removeStorageSync('access_token');
|
||
Taro.removeStorageSync('User');
|
||
Taro.removeStorageSync('UserId');
|
||
Taro.removeStorageSync('TenantId');
|
||
Taro.removeStorageSync('Phone');
|
||
Taro.removeStorageSync('userInfo');
|
||
} catch (error) {
|
||
console.error('清除用户数据失败:', error);
|
||
}
|
||
};
|
||
|
||
// 从服务器获取最新用户信息
|
||
const fetchUserInfo = async () => {
|
||
if (!isLoggedIn) {
|
||
return null;
|
||
}
|
||
|
||
try {
|
||
setLoading(true);
|
||
const userInfo = await getUserInfo();
|
||
setUser(userInfo);
|
||
|
||
// 更新本地存储
|
||
const token = Taro.getStorageSync('access_token');
|
||
if (token) {
|
||
saveUserToStorage(token, userInfo);
|
||
}
|
||
|
||
return userInfo;
|
||
} catch (error) {
|
||
console.error('获取用户信息失败:', error);
|
||
// 如果获取失败,可能是token过期,清除登录状态
|
||
const errorMessage = error instanceof Error ? error.message : String(error);
|
||
if (errorMessage?.includes('401') || errorMessage?.includes('未授权')) {
|
||
logoutUser();
|
||
}
|
||
return null;
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
// 更新用户信息
|
||
const updateUser = async (userData: Partial<User>) => {
|
||
if (!user) {
|
||
throw new Error('用户未登录');
|
||
}
|
||
|
||
try {
|
||
// 先获取最新的用户信息,确保我们有完整的数据
|
||
const latestUserInfo = await getUserInfo();
|
||
|
||
// 合并最新的用户信息和要更新的数据
|
||
const updatedUser = { ...latestUserInfo, ...userData };
|
||
|
||
// 调用API更新用户信息
|
||
await updateUserInfo(updatedUser);
|
||
|
||
// 更新本地状态
|
||
setUser(updatedUser);
|
||
|
||
// 更新本地存储
|
||
const token = Taro.getStorageSync('access_token');
|
||
if (token) {
|
||
saveUserToStorage(token, updatedUser);
|
||
}
|
||
|
||
Taro.showToast({
|
||
title: '更新成功',
|
||
icon: 'success',
|
||
duration: 1500
|
||
});
|
||
|
||
return updatedUser;
|
||
} catch (error) {
|
||
console.error('更新用户信息失败:', error);
|
||
Taro.showToast({
|
||
title: '更新失败',
|
||
icon: 'error',
|
||
duration: 1500
|
||
});
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
// 检查是否有特定权限
|
||
const hasPermission = (permission: string) => {
|
||
if (!user || !user.authorities) {
|
||
return false;
|
||
}
|
||
return user.authorities.some(auth => auth.authority === permission);
|
||
};
|
||
|
||
// 检查是否有特定角色
|
||
const hasRole = (roleCode: string) => {
|
||
if (!user || !user.roles) {
|
||
return false;
|
||
}
|
||
return user.roles.some(role => role.roleCode === roleCode);
|
||
};
|
||
|
||
// 获取用户头像URL
|
||
const getAvatarUrl = () => {
|
||
return user?.avatar || user?.avatarUrl || '';
|
||
};
|
||
|
||
const getUserId = () => {
|
||
return user?.userId;
|
||
};
|
||
|
||
// 获取用户显示名称
|
||
const getDisplayName = () => {
|
||
return user?.nickname || user?.realName || user?.username || '未登录';
|
||
};
|
||
|
||
// 获取用户显示的角色(同步版本)
|
||
const getRoleName = () => {
|
||
if(hasRole('superAdmin')){
|
||
return '超级管理员';
|
||
}
|
||
if(hasRole('admin')){
|
||
return '管理员';
|
||
}
|
||
if(hasRole('staff')){
|
||
return '员工';
|
||
}
|
||
if(hasRole('vip')){
|
||
return 'VIP会员';
|
||
}
|
||
return '注册用户';
|
||
}
|
||
|
||
// 检查用户是否已实名认证
|
||
const isCertified = () => {
|
||
return user?.certification === true;
|
||
};
|
||
|
||
// 检查用户是否是管理员
|
||
const isAdmin = () => {
|
||
return user?.isAdmin === true;
|
||
};
|
||
|
||
const isSuperAdmin = () => {
|
||
return user?.isSuperAdmin === true;
|
||
};
|
||
|
||
// 获取用户余额
|
||
const getBalance = () => {
|
||
return user?.balance || 0;
|
||
};
|
||
|
||
// 获取用户积分
|
||
const getPoints = () => {
|
||
return user?.points || 0;
|
||
};
|
||
|
||
// 初始化时加载用户数据
|
||
useEffect(() => {
|
||
loadUserFromStorage().catch(error => {
|
||
console.error('初始化用户数据失败:', error);
|
||
setLoading(false);
|
||
});
|
||
}, []);
|
||
|
||
return {
|
||
// 状态
|
||
user,
|
||
isLoggedIn,
|
||
loading,
|
||
|
||
// 方法
|
||
loginUser,
|
||
logoutUser,
|
||
fetchUserInfo,
|
||
updateUser,
|
||
loadUserFromStorage,
|
||
autoLoginByOpenId,
|
||
|
||
// 工具方法
|
||
hasPermission,
|
||
hasRole,
|
||
getAvatarUrl,
|
||
getDisplayName,
|
||
getRoleName,
|
||
isCertified,
|
||
isAdmin,
|
||
getBalance,
|
||
getPoints,
|
||
getUserId,
|
||
isSuperAdmin
|
||
};
|
||
};
|