450 lines
11 KiB
TypeScript
450 lines
11 KiB
TypeScript
import Taro from "@tarojs/taro";
|
||
import httpService, { ApiResponse } from "./httpService";
|
||
import tokenManager from "../utils/tokenManager";
|
||
import { useUser } from "@/store/userStore";
|
||
|
||
// 微信用户信息接口
|
||
export interface WechatUserInfo {
|
||
id: string;
|
||
nickname: string;
|
||
avatar: string;
|
||
gender: number;
|
||
city: string;
|
||
province: string;
|
||
country: string;
|
||
}
|
||
|
||
// 登录响应接口
|
||
export interface LoginResponse {
|
||
success: boolean;
|
||
message: string;
|
||
token?: string;
|
||
user_info?: WechatUserInfo;
|
||
phone_update_status?: string;
|
||
existing_phone?: string;
|
||
}
|
||
|
||
// 发送短信响应接口
|
||
export interface SmsResponse {
|
||
success: boolean;
|
||
message: string;
|
||
}
|
||
|
||
// 验证验证码响应接口
|
||
export interface VerifyCodeResponse {
|
||
success: boolean;
|
||
message: string;
|
||
token?: string;
|
||
user_info?: WechatUserInfo;
|
||
}
|
||
// 用户详细信息
|
||
export interface UserStats {
|
||
followers_count: number;
|
||
following_count: number;
|
||
hosted_games_count: number;
|
||
participated_games_count: number;
|
||
}
|
||
|
||
// 手机号验证码登录接口参数
|
||
export interface PhoneLoginParams {
|
||
phone: string;
|
||
verification_code: string;
|
||
user_code: string;
|
||
}
|
||
|
||
export interface UserInfoType {
|
||
subscribe_time: string;
|
||
last_login_time: string;
|
||
create_time: string;
|
||
last_modify_time: string;
|
||
id: number;
|
||
openid: string;
|
||
user_code: string | null;
|
||
unionid: string;
|
||
session_key: string;
|
||
nickname: string;
|
||
ntrp_level: string;
|
||
occupation: string | null;
|
||
avatar_url: string;
|
||
gender: string;
|
||
country: string;
|
||
province: string;
|
||
city: string;
|
||
language: string;
|
||
phone: string;
|
||
personal_profile: string | null;
|
||
is_subscribed: string; // 如果只会是 "0" | "1",也可以写成字面量联合类型
|
||
latitude: number;
|
||
longitude: number;
|
||
stats: UserStats;
|
||
}
|
||
|
||
// 微信授权登录
|
||
export const wechat_auth_login = async (
|
||
phone_code?: string,
|
||
): Promise<LoginResponse> => {
|
||
try {
|
||
// 先进行微信登录获取code
|
||
const login_result = await Taro.login();
|
||
|
||
if (!login_result.code) {
|
||
return {
|
||
success: false,
|
||
message: "微信登录失败",
|
||
};
|
||
}
|
||
|
||
// 使用 httpService 调用微信授权接口,传递手机号code
|
||
const auth_response = await httpService.post("user/wx_auth", {
|
||
code: login_result.code,
|
||
phone_code: phone_code, // 传递手机号加密code
|
||
});
|
||
|
||
if (auth_response.code === 0) {
|
||
// 登录成功后,更新用户信息到 store
|
||
try {
|
||
await useUser.getState().fetchUserInfo();
|
||
} catch (error) {
|
||
console.error("更新用户信息到 store 失败:", error);
|
||
}
|
||
|
||
return {
|
||
success: true,
|
||
message: "微信登录成功",
|
||
token: auth_response.data?.token || "",
|
||
user_info: auth_response.data?.userInfo,
|
||
};
|
||
} else {
|
||
return {
|
||
success: false,
|
||
message: auth_response.message || "微信授权失败",
|
||
};
|
||
}
|
||
} catch (error) {
|
||
console.error("微信授权登录失败:", error);
|
||
return {
|
||
success: false,
|
||
message: "微信授权失败,请重试",
|
||
};
|
||
}
|
||
};
|
||
|
||
// 手机号验证码登录接口参数
|
||
export interface PhoneLoginParams {
|
||
phone: string;
|
||
verification_code: string;
|
||
user_code: string;
|
||
}
|
||
|
||
// 更新手机号接口参数
|
||
export interface ChangePhoneParams {
|
||
phone: string;
|
||
}
|
||
|
||
// 手机号验证码登录
|
||
export const phone_auth_login = async (
|
||
params: PhoneLoginParams,
|
||
): Promise<LoginResponse> => {
|
||
try {
|
||
// 使用 httpService 调用验证验证码接口
|
||
const verify_response = await httpService.post("user/sms/verify", {
|
||
phone: params.phone,
|
||
code: params.verification_code,
|
||
user_code: params.user_code,
|
||
});
|
||
|
||
if (verify_response.code === 0) {
|
||
// 登录成功后,更新用户信息到 store
|
||
try {
|
||
await useUser.getState().fetchUserInfo();
|
||
} catch (error) {
|
||
console.error("更新用户信息到 store 失败:", error);
|
||
}
|
||
|
||
return {
|
||
success: true,
|
||
message: "登录成功",
|
||
token: verify_response.data?.token,
|
||
user_info: verify_response.data?.userInfo,
|
||
phone_update_status: verify_response.data?.phone_update_status,
|
||
existing_phone: verify_response.data?.existing_phone,
|
||
};
|
||
} else {
|
||
return {
|
||
success: false,
|
||
message: verify_response.message || "验证码错误",
|
||
};
|
||
}
|
||
} catch (error) {
|
||
console.error("手机号登录失败:", error);
|
||
return {
|
||
success: false,
|
||
message: error.message,
|
||
};
|
||
}
|
||
};
|
||
|
||
// 发送短信验证码
|
||
export const send_sms_code = async (phone: string): Promise<SmsResponse> => {
|
||
try {
|
||
const response = await httpService.post("user/sms/send", {
|
||
phone: phone,
|
||
});
|
||
|
||
// 修复响应检查逻辑:检查 code === 0 或 success === true
|
||
if (response.code === 0 || response.success === true) {
|
||
return {
|
||
success: true,
|
||
message: "验证码发送成功",
|
||
};
|
||
} else {
|
||
return {
|
||
success: false,
|
||
message: response.message || "验证码发送失败",
|
||
};
|
||
}
|
||
} catch (error) {
|
||
console.error("发送短信失败:", error);
|
||
return {
|
||
success: false,
|
||
message: error.message,
|
||
};
|
||
}
|
||
};
|
||
|
||
// 验证短信验证码
|
||
export const verify_sms_code = async (
|
||
phone: string,
|
||
code: string,
|
||
): Promise<VerifyCodeResponse> => {
|
||
try {
|
||
const response = await httpService.post("user/sms/verify", {
|
||
phone: phone,
|
||
code: code,
|
||
});
|
||
|
||
return {
|
||
success: response.success,
|
||
message: response.message || "验证失败",
|
||
token: response.data?.token,
|
||
user_info: response.data?.userInfo,
|
||
};
|
||
} catch (error) {
|
||
console.error("验证验证码失败:", error);
|
||
return {
|
||
success: false,
|
||
message: error.message,
|
||
};
|
||
}
|
||
};
|
||
|
||
// 保存用户登录状态
|
||
export const save_login_state = (token: string, user_info: WechatUserInfo) => {
|
||
try {
|
||
// 使用 tokenManager 保存令牌信息,设置24小时过期
|
||
const expires_at = Date.now() + 24 * 60 * 60 * 1000; // 24小时后过期
|
||
tokenManager.setToken({
|
||
accessToken: token,
|
||
expiresAt: expires_at,
|
||
});
|
||
|
||
// 保存用户信息
|
||
Taro.setStorageSync("user_info", JSON.stringify(user_info));
|
||
Taro.setStorageSync("is_logged_in", true);
|
||
Taro.setStorageSync("login_time", Date.now());
|
||
} catch (error) {
|
||
console.error("保存登录状态失败:", error);
|
||
}
|
||
};
|
||
|
||
// 清除登录状态
|
||
export const clear_login_state = () => {
|
||
try {
|
||
// 使用 tokenManager 清除令牌
|
||
tokenManager.clearTokens();
|
||
|
||
// 清除其他登录状态
|
||
Taro.removeStorageSync("user_info");
|
||
Taro.removeStorageSync("is_logged_in");
|
||
Taro.removeStorageSync("login_time");
|
||
} catch (error) {
|
||
console.error("清除登录状态失败:", error);
|
||
}
|
||
};
|
||
|
||
// 检查是否已登录
|
||
export const check_login_status = (): boolean => {
|
||
try {
|
||
// 使用 tokenManager 检查令牌有效性
|
||
|
||
if (!tokenManager.hasValidToken()) {
|
||
clear_login_state();
|
||
return false;
|
||
}
|
||
|
||
const is_logged_in = Taro.getStorageSync("is_logged_in");
|
||
return !!is_logged_in;
|
||
} catch (error) {
|
||
return false;
|
||
}
|
||
};
|
||
|
||
// 检查令牌是否需要刷新(剩余时间少于1小时时)
|
||
export const should_refresh_token = (): boolean => {
|
||
try {
|
||
const remaining_time = tokenManager.getTokenRemainingTime();
|
||
const one_hour = 60 * 60 * 1000; // 1小时
|
||
return remaining_time > 0 && remaining_time < one_hour;
|
||
} catch (error) {
|
||
return false;
|
||
}
|
||
};
|
||
|
||
// 获取令牌状态信息
|
||
export const get_token_status = () => {
|
||
try {
|
||
const is_valid = tokenManager.hasValidToken();
|
||
const remaining_time = tokenManager.getTokenRemainingTime();
|
||
const is_expired = tokenManager.isTokenExpired();
|
||
|
||
return {
|
||
is_valid,
|
||
remaining_time,
|
||
is_expired,
|
||
expires_in_minutes: Math.floor(remaining_time / (60 * 1000)),
|
||
};
|
||
} catch (error) {
|
||
return {
|
||
is_valid: false,
|
||
remaining_time: 0,
|
||
is_expired: true,
|
||
expires_in_minutes: 0,
|
||
};
|
||
}
|
||
};
|
||
|
||
// 获取用户信息
|
||
export const get_user_info = (): WechatUserInfo | null => {
|
||
try {
|
||
let userinfo = Taro.getStorageSync("user_info");
|
||
if (userinfo) {
|
||
return JSON.parse(userinfo);
|
||
}
|
||
return null;
|
||
} catch (error) {
|
||
return null;
|
||
}
|
||
};
|
||
|
||
// 获取用户token
|
||
export const get_user_token = (): string | null => {
|
||
try {
|
||
// 使用 tokenManager 获取令牌
|
||
return tokenManager.getAccessToken();
|
||
} catch (error) {
|
||
return null;
|
||
}
|
||
};
|
||
|
||
// 检查微信登录状态
|
||
export const check_wechat_login = async (): Promise<boolean> => {
|
||
try {
|
||
const check_result = await Taro.checkSession();
|
||
// Taro.checkSession 返回的是 { errMsg: string }
|
||
return check_result.errMsg === "checkSession:ok";
|
||
} catch (error) {
|
||
return false;
|
||
}
|
||
};
|
||
|
||
// 刷新登录状态
|
||
export const refresh_login_status = async (): Promise<boolean> => {
|
||
try {
|
||
// 检查微信登录状态
|
||
const is_valid = await check_wechat_login();
|
||
|
||
if (!is_valid) {
|
||
// 微信登录已过期,需要重新登录
|
||
clear_login_state();
|
||
return false;
|
||
}
|
||
|
||
// 检查本地存储的登录状态
|
||
return check_login_status();
|
||
} catch (error) {
|
||
console.error("刷新登录状态失败:", error);
|
||
return false;
|
||
}
|
||
};
|
||
|
||
// 获取用户详细信息
|
||
export const fetchUserProfile = async (): Promise<
|
||
ApiResponse<UserInfoType>
|
||
> => {
|
||
try {
|
||
const response = await httpService.post("user/detail");
|
||
return response;
|
||
} catch (error) {
|
||
console.error("获取用户信息失败:", error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
// 更新用户信息
|
||
export const updateUserProfile = async (payload: Partial<UserInfoType>) => {
|
||
try {
|
||
const response = await httpService.post("/user/update", payload);
|
||
return response;
|
||
} catch (error) {
|
||
console.error("更新用户信息失败:", error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
// 更新用户手机号
|
||
export const updateUserPhone = async (payload: ChangePhoneParams) => {
|
||
try {
|
||
const response = await httpService.post("/user/update_phone", payload);
|
||
return response;
|
||
} catch (error) {
|
||
console.error("更新用户手机号失败:", error);
|
||
throw error;
|
||
}
|
||
}
|
||
// 获取指定用户信息
|
||
export const getUserInfoById = async (id) => {
|
||
try {
|
||
const response = await httpService.post("/user/detail_by_id", { id });
|
||
return response;
|
||
} catch (error) {
|
||
console.error("获取用户信息失败:", error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
// 关注用户
|
||
export const followUser = async (following_id) => {
|
||
try {
|
||
const response = await httpService.post("/wch_users/follow", {
|
||
following_id,
|
||
});
|
||
return response;
|
||
} catch (error) {
|
||
console.error("关注失败:", error);
|
||
throw error;
|
||
}
|
||
};
|
||
|
||
// 取消关注用户
|
||
export const unFollowUser = async (following_id) => {
|
||
try {
|
||
const response = await httpService.post("/wch_users/unfollow", {
|
||
following_id,
|
||
});
|
||
return response;
|
||
} catch (error) {
|
||
console.error("取消关注失败:", error);
|
||
throw error;
|
||
}
|
||
};
|