获取昵称修改状态、优化昵称修改逻辑
This commit is contained in:
@@ -33,7 +33,6 @@ const EditModal: React.FC<EditModalProps> = ({
|
|||||||
const [isValid, setIsValid] = useState(true);
|
const [isValid, setIsValid] = useState(true);
|
||||||
const [isIllegal, setIsIllegal] = useState(false);
|
const [isIllegal, setIsIllegal] = useState(false);
|
||||||
const [hasIllegal, setHasIllegal] = useState(false);
|
const [hasIllegal, setHasIllegal] = useState(false);
|
||||||
const [canEdit, setCanEdit] = useState(true);
|
|
||||||
// 使用全局键盘状态
|
// 使用全局键盘状态
|
||||||
const {
|
const {
|
||||||
keyboardHeight,
|
keyboardHeight,
|
||||||
@@ -89,15 +88,11 @@ const EditModal: React.FC<EditModalProps> = ({
|
|||||||
value.length >= 2 &&
|
value.length >= 2 &&
|
||||||
value.length <= maxLength &&
|
value.length <= maxLength &&
|
||||||
!hasIllegal &&
|
!hasIllegal &&
|
||||||
!isIllegal &&
|
!isIllegal;
|
||||||
canEdit;
|
|
||||||
setIsValid(valid);
|
setIsValid(valid);
|
||||||
}, [
|
}, [value, hasIllegal, isIllegal]);
|
||||||
value, hasIllegal, isIllegal, canEdit
|
|
||||||
])
|
|
||||||
|
|
||||||
const handle_save = () => {
|
const handle_save = () => {
|
||||||
console.log("savexxxxxxx", isIllegal, hasIllegal, !isValid)
|
|
||||||
if (isIllegal) {
|
if (isIllegal) {
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: "输入的字符非法",
|
title: "输入的字符非法",
|
||||||
@@ -106,7 +101,6 @@ const EditModal: React.FC<EditModalProps> = ({
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
} else if (hasIllegal) {
|
} else if (hasIllegal) {
|
||||||
console.log("hasIllegal")
|
|
||||||
Taro.showToast({
|
Taro.showToast({
|
||||||
title: "内容不能包含@<>/等无效字符",
|
title: "内容不能包含@<>/等无效字符",
|
||||||
icon: "none",
|
icon: "none",
|
||||||
@@ -128,7 +122,6 @@ const EditModal: React.FC<EditModalProps> = ({
|
|||||||
setValue(initialValue);
|
setValue(initialValue);
|
||||||
setHasIllegal(false);
|
setHasIllegal(false);
|
||||||
setIsIllegal(false);
|
setIsIllegal(false);
|
||||||
setCanEdit(true);
|
|
||||||
onCancel();
|
onCancel();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -176,12 +169,15 @@ const EditModal: React.FC<EditModalProps> = ({
|
|||||||
confirmType="done"
|
confirmType="done"
|
||||||
// autoFocus={true}
|
// autoFocus={true}
|
||||||
onConfirm={handle_save}
|
onConfirm={handle_save}
|
||||||
onBlur={(e) => { e.preventDefault() }}
|
onBlur={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<View className="char_count">
|
<View className="char_count">
|
||||||
<Text
|
<Text
|
||||||
className={`count_text ${value.length > maxLength && "un-valid"
|
className={`count_text ${
|
||||||
}`}
|
value.length > maxLength && "un-valid"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{value.length}/{maxLength}
|
{value.length}/{maxLength}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -208,8 +204,9 @@ const EditModal: React.FC<EditModalProps> = ({
|
|||||||
/>
|
/>
|
||||||
<View className="char_count">
|
<View className="char_count">
|
||||||
<Text
|
<Text
|
||||||
className={`count_text ${value.length > maxLength && "un-valid"
|
className={`count_text ${
|
||||||
}`}
|
value.length > maxLength && "un-valid"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
{value.length}/{maxLength}
|
{value.length}/{maxLength}
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import "./index.scss";
|
|||||||
import { EditModal } from "@/components";
|
import { EditModal } from "@/components";
|
||||||
import { UserService, PickerOption } from "@/services/userService";
|
import { UserService, PickerOption } from "@/services/userService";
|
||||||
import { PopupPicker } from "@/components/Picker/index";
|
import { PopupPicker } from "@/components/Picker/index";
|
||||||
import { useUserActions } from "@/store/userStore";
|
import { useUserActions, useNicknameChangeStatus } from "@/store/userStore";
|
||||||
import { UserInfoType } from "@/services/userService";
|
import { UserInfoType } from "@/services/userService";
|
||||||
import { useCities, useProfessions } from "@/store/pickerOptionsStore";
|
import { useCities, useProfessions } from "@/store/pickerOptionsStore";
|
||||||
import { formatNtrpDisplay } from "@/utils/helper";
|
import { formatNtrpDisplay } from "@/utils/helper";
|
||||||
@@ -77,8 +77,9 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
|
|||||||
set_user_info,
|
set_user_info,
|
||||||
onTab,
|
onTab,
|
||||||
}) => {
|
}) => {
|
||||||
|
const nickname_change_status = useNicknameChangeStatus();
|
||||||
const { setShowGuideBar } = useGlobalState();
|
const { setShowGuideBar } = useGlobalState();
|
||||||
const { updateUserInfo } = useUserActions();
|
const { updateUserInfo, updateNickname } = useUserActions();
|
||||||
const [ntrpTested, setNtrpTested] = useState(false);
|
const [ntrpTested, setNtrpTested] = useState(false);
|
||||||
|
|
||||||
// 使用 useRef 记录上一次的 user_info,只在真正变化时打印
|
// 使用 useRef 记录上一次的 user_info,只在真正变化时打印
|
||||||
@@ -185,6 +186,13 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
|
|||||||
}
|
}
|
||||||
if (field === "nickname") {
|
if (field === "nickname") {
|
||||||
if (!is_current_user) return;
|
if (!is_current_user) return;
|
||||||
|
if (!nickname_change_status.can_change) {
|
||||||
|
return Taro.showToast({
|
||||||
|
title: `30天内仅可修改4次昵称,${nickname_change_status.next_period_start_time}后可修改`,
|
||||||
|
icon: "none",
|
||||||
|
duration: 2000,
|
||||||
|
});
|
||||||
|
}
|
||||||
// 手动输入
|
// 手动输入
|
||||||
setShowGuideBar(false);
|
setShowGuideBar(false);
|
||||||
setEditingField(field);
|
setEditingField(field);
|
||||||
@@ -200,10 +208,10 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
|
|||||||
try {
|
try {
|
||||||
// 调用更新用户信息接口,只传递修改的字段
|
// 调用更新用户信息接口,只传递修改的字段
|
||||||
const update_data = { [editing_field]: value };
|
const update_data = { [editing_field]: value };
|
||||||
await UserService.update_user_info(update_data);
|
// await UserService.update_user_info(update_data);
|
||||||
|
editing_field === "nickname"
|
||||||
await updateUserInfo({ [editing_field]: value });
|
? await updateNickname(value)
|
||||||
|
: await updateUserInfo(update_data);
|
||||||
set_form_data((prev) => {
|
set_form_data((prev) => {
|
||||||
return { ...prev, ...update_data };
|
return { ...prev, ...update_data };
|
||||||
});
|
});
|
||||||
@@ -607,7 +615,7 @@ const UserInfoCardComponent: React.FC<UserInfoCardProps> = ({
|
|||||||
onCancel={handle_edit_modal_cancel}
|
onCancel={handle_edit_modal_cancel}
|
||||||
validationMessage={
|
validationMessage={
|
||||||
editing_field === "nickname"
|
editing_field === "nickname"
|
||||||
? "请填写 2-24 个字符,不包括 @<>/等无效字符。30 天内可修改 4 次昵称,12.5 前还可修改 4 次。"
|
? `请填写 2-24 个字符,不包括 @<>/等无效字符。30 天内可修改 4 次昵称,${nickname_change_status.next_period_start_time} 前还可修改 ${nickname_change_status.remaining_count} 次。`
|
||||||
: "请填写 2-100 个字符"
|
: "请填写 2-100 个字符"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -1,44 +1,42 @@
|
|||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from "react";
|
||||||
import { View, } from '@tarojs/components';
|
import { View } from "@tarojs/components";
|
||||||
import { silentLogin } from '@/services/loginService';
|
import { silentLogin } from "@/services/loginService";
|
||||||
import { useUserActions } from '@/store/userStore';
|
import { useUserActions } from "@/store/userStore";
|
||||||
import Taro from '@tarojs/taro';
|
import Taro from "@tarojs/taro";
|
||||||
import "./index.scss";
|
import "./index.scss";
|
||||||
const HomePage: React.FC = () => {
|
const HomePage: React.FC = () => {
|
||||||
const { fetchUserInfo } = useUserActions();
|
const { fetchUserInfo, checkNicknameChangeStatus } = useUserActions();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleLoginRedirect = async () => {
|
||||||
|
// 先执行静默登录,然后再跳转
|
||||||
|
try {
|
||||||
|
console.log("开始静默登录...");
|
||||||
|
const loginResult = await silentLogin();
|
||||||
|
console.log("静默登录结果:", loginResult);
|
||||||
|
if (loginResult.success) {
|
||||||
|
// 静默登录成功,获取用户信息
|
||||||
|
fetchUserInfo().catch((error) => {
|
||||||
|
console.error("获取用户信息失败:", error);
|
||||||
|
});
|
||||||
|
checkNicknameChangeStatus().catch((error) => {
|
||||||
|
console.error("检查昵称变更状态失败:", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("静默登录失败:", error);
|
||||||
|
// 静默登录失败不影响使用
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
// 无论静默登录是否成功,都跳转到主页面
|
||||||
const handleLoginRedirect = async () => {
|
Taro.redirectTo({ url: "/main_pages/index" });
|
||||||
// 先执行静默登录,然后再跳转
|
};
|
||||||
try {
|
|
||||||
console.log('开始静默登录...');
|
|
||||||
const loginResult = await silentLogin();
|
|
||||||
console.log('静默登录结果:', loginResult);
|
|
||||||
if (loginResult.success) {
|
|
||||||
// 静默登录成功,获取用户信息
|
|
||||||
fetchUserInfo().catch((error) => {
|
|
||||||
console.error('获取用户信息失败:', error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('静默登录失败:', error);
|
|
||||||
// 静默登录失败不影响使用
|
|
||||||
}
|
|
||||||
|
|
||||||
// 无论静默登录是否成功,都跳转到主页面
|
handleLoginRedirect();
|
||||||
Taro.redirectTo({ url: '/main_pages/index' });
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
};
|
}, []); // fetchUserInfo 是稳定的函数引用,不需要加入依赖项
|
||||||
|
|
||||||
handleLoginRedirect();
|
return <View className="home_page"></View>;
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
};
|
||||||
}, []); // fetchUserInfo 是稳定的函数引用,不需要加入依赖项
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View className="home_page">
|
|
||||||
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HomePage;
|
export default HomePage;
|
||||||
@@ -90,6 +90,14 @@ export interface UserInfoType {
|
|||||||
ongoing_games?: string[];
|
ongoing_games?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface NicknameChangeStatus {
|
||||||
|
can_change: boolean;
|
||||||
|
remaining_count: number;
|
||||||
|
period_start_time: string;
|
||||||
|
next_period_start_time: string;
|
||||||
|
days_until_next_period: number;
|
||||||
|
}
|
||||||
|
|
||||||
// 后端球局数据接口
|
// 后端球局数据接口
|
||||||
interface BackendGameData {
|
interface BackendGameData {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -681,6 +689,33 @@ export const fetchUserProfile = async (): Promise<
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取昵称修改状态
|
||||||
|
export const checkNicknameChangeStatus = async (): Promise<
|
||||||
|
ApiResponse<NicknameChangeStatus>
|
||||||
|
> => {
|
||||||
|
try {
|
||||||
|
const response = await httpService.post(
|
||||||
|
"/user/check_nickname_change_status"
|
||||||
|
);
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("获取昵称修改状态失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// 修改昵称
|
||||||
|
export const updateNickname = async (nickname: string) => {
|
||||||
|
try {
|
||||||
|
const response = await httpService.post("/user/update_nickname", {
|
||||||
|
nickname,
|
||||||
|
});
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("昵称修改失败:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// 更新用户信息
|
// 更新用户信息
|
||||||
export const updateUserProfile = async (payload: Partial<UserInfoType>) => {
|
export const updateUserProfile = async (payload: Partial<UserInfoType>) => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -3,12 +3,18 @@ import {
|
|||||||
fetchUserProfile,
|
fetchUserProfile,
|
||||||
updateUserProfile,
|
updateUserProfile,
|
||||||
UserInfoType,
|
UserInfoType,
|
||||||
|
checkNicknameChangeStatus as checkNicknameChangeStatusApi,
|
||||||
|
NicknameChangeStatus,
|
||||||
|
updateNickname as updateNicknameApi,
|
||||||
} from "@/services/userService";
|
} from "@/services/userService";
|
||||||
|
|
||||||
export interface UserState {
|
export interface UserState {
|
||||||
user: UserInfoType | {};
|
user: UserInfoType | {};
|
||||||
fetchUserInfo: () => Promise<UserInfoType | undefined>;
|
fetchUserInfo: () => Promise<UserInfoType | undefined>;
|
||||||
updateUserInfo: (userInfo: Partial<UserInfoType>) => void;
|
updateUserInfo: (userInfo: Partial<UserInfoType>) => void;
|
||||||
|
nicknameChangeStatus: Partial<NicknameChangeStatus>;
|
||||||
|
checkNicknameChangeStatus: () => void;
|
||||||
|
updateNickname: (nickname: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 请求锁,防止重复请求
|
// 请求锁,防止重复请求
|
||||||
@@ -58,12 +64,36 @@ export const useUser = create<UserState>()((set) => ({
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
nicknameChangeStatus: {},
|
||||||
|
checkNicknameChangeStatus: async () => {
|
||||||
|
try {
|
||||||
|
const res = await checkNicknameChangeStatusApi();
|
||||||
|
set({ nicknameChangeStatus: res.data });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("检查昵称变更状态失败:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateNickname: async (nickname) => {
|
||||||
|
try {
|
||||||
|
await updateNicknameApi(nickname);
|
||||||
|
await useUser.getState().checkNicknameChangeStatus();
|
||||||
|
set((state) => ({
|
||||||
|
user: { ...state.user, nickname },
|
||||||
|
}));
|
||||||
|
} catch (error) {
|
||||||
|
console.error("更新用户昵称失败:", error);
|
||||||
|
}
|
||||||
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const useUserInfo = () => useUser((state) => state.user);
|
export const useUserInfo = () => useUser((state) => state.user);
|
||||||
|
export const useNicknameChangeStatus = () =>
|
||||||
|
useUser((state) => state.nicknameChangeStatus);
|
||||||
|
|
||||||
export const useUserActions = () =>
|
export const useUserActions = () =>
|
||||||
useUser((state) => ({
|
useUser((state) => ({
|
||||||
fetchUserInfo: state.fetchUserInfo,
|
fetchUserInfo: state.fetchUserInfo,
|
||||||
updateUserInfo: state.updateUserInfo,
|
updateUserInfo: state.updateUserInfo,
|
||||||
|
checkNicknameChangeStatus: state.checkNicknameChangeStatus,
|
||||||
|
updateNickname: state.updateNickname,
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -9,16 +9,21 @@ import { convert_db_gender_to_display } from "@/utils/genderUtils";
|
|||||||
import { EditModal, GeneralNavbar } from "@/components";
|
import { EditModal, GeneralNavbar } from "@/components";
|
||||||
// import img from "@/config/images";
|
// import img from "@/config/images";
|
||||||
import CommonDialog from "@/components/CommonDialog";
|
import CommonDialog from "@/components/CommonDialog";
|
||||||
import { useUserActions, useUserInfo } from "@/store/userStore";
|
import {
|
||||||
|
useUserActions,
|
||||||
|
useUserInfo,
|
||||||
|
useNicknameChangeStatus,
|
||||||
|
} from "@/store/userStore";
|
||||||
import { UserInfoType } from "@/services/userService";
|
import { UserInfoType } from "@/services/userService";
|
||||||
import { useCities, useProfessions } from "@/store/pickerOptionsStore";
|
import { useCities, useProfessions } from "@/store/pickerOptionsStore";
|
||||||
import { handleCustomerService } from "@/services/userService";
|
import { handleCustomerService } from "@/services/userService";
|
||||||
import evaluateService from "@/services/evaluateService";
|
import evaluateService from "@/services/evaluateService";
|
||||||
|
|
||||||
const EditProfilePage: React.FC = () => {
|
const EditProfilePage: React.FC = () => {
|
||||||
const { updateUserInfo } = useUserActions();
|
const { updateUserInfo, updateNickname } = useUserActions();
|
||||||
// 直接从store获取用户信息,确保响应式更新
|
// 直接从store获取用户信息,确保响应式更新
|
||||||
const user_info = useUserInfo();
|
const user_info = useUserInfo();
|
||||||
|
const nickname_change_status = useNicknameChangeStatus();
|
||||||
|
|
||||||
// 表单状态,基于store中的用户信息初始化
|
// 表单状态,基于store中的用户信息初始化
|
||||||
const getInitialFormData = () => {
|
const getInitialFormData = () => {
|
||||||
@@ -190,6 +195,13 @@ const EditProfilePage: React.FC = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (field === "nickname") {
|
if (field === "nickname") {
|
||||||
|
if (!nickname_change_status.can_change) {
|
||||||
|
return Taro.showToast({
|
||||||
|
title: `30天内仅可修改4次昵称,${nickname_change_status.next_period_start_time}后可修改`,
|
||||||
|
icon: "none",
|
||||||
|
duration: 2000,
|
||||||
|
});
|
||||||
|
}
|
||||||
// 手动输入
|
// 手动输入
|
||||||
setEditingField(field);
|
setEditingField(field);
|
||||||
setEditModalVisible(true);
|
setEditModalVisible(true);
|
||||||
@@ -211,8 +223,9 @@ const EditProfilePage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
// 调用更新用户信息接口,只传递修改的字段
|
// 调用更新用户信息接口,只传递修改的字段
|
||||||
const update_data = { [editing_field]: value };
|
const update_data = { [editing_field]: value };
|
||||||
await updateUserInfo(update_data);
|
editing_field === "nickname"
|
||||||
|
? await updateNickname(value)
|
||||||
|
: await updateUserInfo(update_data);
|
||||||
// 更新表单状态(store会自动更新)
|
// 更新表单状态(store会自动更新)
|
||||||
setFormData((prev) => ({ ...prev, [editing_field]: value }));
|
setFormData((prev) => ({ ...prev, [editing_field]: value }));
|
||||||
|
|
||||||
@@ -811,7 +824,7 @@ const EditProfilePage: React.FC = () => {
|
|||||||
onCancel={handle_edit_modal_cancel}
|
onCancel={handle_edit_modal_cancel}
|
||||||
validationMessage={
|
validationMessage={
|
||||||
editing_field === "nickname"
|
editing_field === "nickname"
|
||||||
? "请填写 2-24 个字符,不包括 @<>/等无效字符。30 天内可修改 4 次昵称,12.5 前还可修改 4 次。"
|
? `请填写 2-24 个字符,不包括 @<>/等无效字符。30 天内可修改 4 次昵称,${nickname_change_status.next_period_start_time} 前还可修改 ${nickname_change_status.remaining_count} 次。`
|
||||||
: "请填写 2-100 个字符"
|
: "请填写 2-100 个字符"
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user