diff --git a/src/components/EditModal/index.tsx b/src/components/EditModal/index.tsx index 99086d0..b05f3e0 100644 --- a/src/components/EditModal/index.tsx +++ b/src/components/EditModal/index.tsx @@ -1,8 +1,8 @@ -import React, { useState, useEffect } from 'react'; -import { View, Text, Textarea, Input, Picker } from '@tarojs/components'; -import Taro from '@tarojs/taro'; -import './EditModal.scss'; -import { useKeyboardHeight } from '@/store/keyboardStore' +import React, { useState, useEffect } from "react"; +import { View, Text, Textarea, Input, Picker } from "@tarojs/components"; +import Taro from "@tarojs/taro"; +import "./EditModal.scss"; +import { useKeyboardHeight } from "@/store/keyboardStore"; interface EditModalProps { visible: boolean; @@ -11,6 +11,7 @@ interface EditModalProps { placeholder: string; initialValue: string; maxLength: number; + invalidCharacters: string; onSave: (value: string) => void; onCancel: () => void; validationMessage?: string; @@ -23,46 +24,69 @@ const EditModal: React.FC = ({ placeholder, initialValue, maxLength, + invalidCharacters = "", onSave, onCancel, - validationMessage + validationMessage, }) => { const [value, setValue] = useState(initialValue); const [isValid, setIsValid] = useState(true); const [isIllegal, setIsIllegal] = useState(false); // 使用全局键盘状态 - const { keyboardHeight, isKeyboardVisible, addListener, initializeKeyboardListener } = useKeyboardHeight() + const { + keyboardHeight, + isKeyboardVisible, + addListener, + initializeKeyboardListener, + } = useKeyboardHeight(); // 使用全局键盘状态监听 useEffect(() => { // 初始化全局键盘监听器 - initializeKeyboardListener() + initializeKeyboardListener(); // 添加本地监听器 const removeListener = addListener((height, visible) => { - console.log('AiImportPopup 收到键盘变化:', height, visible) - }) + console.log("AiImportPopup 收到键盘变化:", height, visible); + }); return () => { - removeListener() - } - }, [initializeKeyboardListener, addListener]) + removeListener(); + }; + }, [initializeKeyboardListener, addListener]); useEffect(() => { if (visible) { setValue(initialValue); - const valid = initialValue.length >= 2 && initialValue.length <= maxLength; + const valid = + initialValue.length >= 2 && initialValue.length <= maxLength; setIsValid(valid); } }, [visible, initialValue]); + const createExcludeRegex = (chars: string) => { + // 转义正则表达式特殊字符 + const escapedChars = chars.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + + // 构建负向字符类正则表达式 + // ^[^...]*$ 匹配不包含任何指定字符的完整字符串 + const pattern = `[${escapedChars}]`; + + return new RegExp(pattern); + }; const handle_input_change = (e: any) => { const new_value = e.detail.value; setValue(new_value); - const illegal = /\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|EXEC|DECLARE)\b|('|--|\/\*|\*\/|;|#)|(=|'|"|`|\\|\|\|&&)|\bOR\s+['"]?[\w]+['"]?\s*=\s*['"]?[\w]+['"]?|\bUNION\s+SELECT\b|\bDROP\s+TABLE\b|\bINSERT\s+INTO\b|\bUPDATE\s+[\w]+\s+SET\b|\bDELETE\s+FROM\b/i.test(new_value) - setIsIllegal(illegal) + const illegal = + /\b(SELECT|INSERT|UPDATE|DELETE|DROP|UNION|ALTER|CREATE|EXEC|DECLARE)\b|('|--|\/\*|\*\/|;|#)|(=|'|"|`|\\|\|\|&&)|\bOR\s+['"]?[\w]+['"]?\s*=\s*['"]?[\w]+['"]?|\bUNION\s+SELECT\b|\bDROP\s+TABLE\b|\bINSERT\s+INTO\b|\bUPDATE\s+[\w]+\s+SET\b|\bDELETE\s+FROM\b/i.test( + new_value + ); + setIsIllegal(illegal); // 验证输入 - const valid = new_value.length >= 2 && new_value.length <= maxLength; + const valid = + new_value.length >= 2 && + new_value.length <= maxLength && + !createExcludeRegex(invalidCharacters).test(new_value); setIsValid(valid); }; @@ -70,16 +94,16 @@ const EditModal: React.FC = ({ if (!isValid) { Taro.showToast({ title: validationMessage || `请填写 2-${maxLength} 个字符`, - icon: 'none', - duration: 2000 + icon: "none", + duration: 2000, }); return; } if (isIllegal) { Taro.showToast({ title: "输入的字符非法", - icon: 'none', - duration: 2000 + icon: "none", + duration: 2000, }); return; } @@ -97,7 +121,16 @@ const EditModal: React.FC = ({ return ( - + {/* 标题栏 */} {title} @@ -113,8 +146,7 @@ const EditModal: React.FC = ({ {/* 文本输入区域 */} - - {type === 'nickname' ? ( + {type === "nickname" ? ( <> = ({ autoFocus={true} /> - maxLength && "un-valid"}`}>{value.length}/{maxLength} + maxLength && "un-valid" + }`} + > + {value.length}/{maxLength} + ) : ( @@ -143,33 +181,40 @@ const EditModal: React.FC = ({ adjustPosition={false} /> - maxLength && "un-valid"}`}>{value.length}/{maxLength} + maxLength && "un-valid" + }`} + > + {value.length}/{maxLength} + )} {/* 验证提示 */} - { - isIllegal ? + {isIllegal ? ( + + 输入的字符非法 + + ) : ( + !isValid && ( - - 输入的字符非法 + + {validationMessage || `请填写 2-${maxLength} 个字符`} - : - !isValid && ( - - - {validationMessage || `请填写 2-${maxLength} 个字符`} - - - ) - } + + ) + )} {/* 底部按钮 */} - + 保存 @@ -178,4 +223,4 @@ const EditModal: React.FC = ({ ); }; -export default EditModal; \ No newline at end of file +export default EditModal; diff --git a/src/components/UserInfo/index.tsx b/src/components/UserInfo/index.tsx index a2375c4..b13c188 100644 --- a/src/components/UserInfo/index.tsx +++ b/src/components/UserInfo/index.tsx @@ -76,7 +76,6 @@ const UserInfoCardComponent: React.FC = ({ set_user_info, onTab, }) => { - const { setShowGuideBar } = useGlobalState(); const { updateUserInfo } = useUserActions(); @@ -383,7 +382,14 @@ const UserInfoCardComponent: React.FC = ({ {/* 统计数据 */} - + handle_stats_click("following")} @@ -461,121 +467,118 @@ const UserInfoCardComponent: React.FC = ({ {/* 标签和简介 */} - { - !collapseProfile ? - - - {user_info.gender && user_info.gender !== "2" ? ( - - {user_info.gender === "0" && ( - { - editable && handle_open_edit_modal("gender"); - }} - /> - )} - {user_info.gender === "1" && ( - { - editable && handle_open_edit_modal("gender"); - }} - /> - )} - - ) : is_current_user && user_info.gender !== "2" ? ( - { - handle_open_edit_modal("gender"); - }} - > - 选择性别 - - ) : null} - {user_info.ntrp_level !== "" ? ( - { - editable && handle_open_edit_modal("ntrp_level"); - }} - > - {`NTRP ${formatNtrpDisplay( - user_info.ntrp_level - )}`} - + {!collapseProfile ? ( + + + {user_info.gender && user_info.gender !== "2" ? ( + + {user_info.gender === "0" && ( + { + editable && handle_open_edit_modal("gender"); + }} + /> + )} + {user_info.gender === "1" && ( + { + editable && handle_open_edit_modal("gender"); + }} + /> + )} + + ) : is_current_user && user_info.gender !== "2" ? ( + { + handle_open_edit_modal("gender"); + }} + > + 选择性别 + + ) : null} + {user_info.ntrp_level !== "" ? ( + { + editable && handle_open_edit_modal("ntrp_level"); + }} + > + {`NTRP ${formatNtrpDisplay( + user_info.ntrp_level + )}`} + + ) : is_current_user ? ( + { + handle_open_edit_modal("ntrp_level"); + }} + > + 测测你的NTRP水平 + + ) : null} + {user_info.occupation ? ( + { + editable && handle_open_edit_modal("occupation"); + }} + > + + {user_info.occupation.split(" ")[2]} + + + ) : is_current_user ? ( + { + handle_open_edit_modal("occupation"); + }} + > + 选择职业 + + ) : null} + {user_info.country || user_info.province || user_info.city ? ( + editable && handle_open_edit_modal("location")} + > + {`${user_info.province}${user_info.city}`} + + ) : is_current_user ? ( + handle_open_edit_modal("location")} + > + 选择地区 + + ) : null} + + handle_open_edit_modal("personal_profile")} + > + {!collapseProfile ? ( + user_info.personal_profile ? ( + {user_info.personal_profile} ) : is_current_user ? ( - { - handle_open_edit_modal("ntrp_level"); - }} - > - 测测你的NTRP水平 + + + 点击添加简介,让更多人了解你 - ) : null} - {user_info.occupation ? ( - { - editable && handle_open_edit_modal("occupation"); - }} - > - - {user_info.occupation.split(" ")[2]} - - - ) : is_current_user ? ( - { - handle_open_edit_modal("occupation"); - }} - > - 选择职业 - - ) : null} - {user_info.country || user_info.province || user_info.city ? ( - editable && handle_open_edit_modal("location")} - > - {`${user_info.province}${user_info.city}`} - - ) : is_current_user ? ( - handle_open_edit_modal("location")} - > - 选择地区 - - ) : null} - - handle_open_edit_modal("personal_profile")} - > - {!collapseProfile ? - user_info.personal_profile ? ( - {user_info.personal_profile} - ) : is_current_user ? ( - - - 点击添加简介,让更多人了解你 - - ) : - null : - null} - - : - null - } + ) : null + ) : null} + + + ) : null} {/* 编辑个人简介弹窗 */} = ({ } initialValue={form_data[editing_field as keyof typeof form_data] || ""} maxLength={editing_field === "nickname" ? 20 : 100} + invalidCharacters={editing_field === "nickname" ? "@<>/" : ""} onSave={handle_edit_modal_save} onCancel={handle_edit_modal_cancel} validationMessage={ editing_field === "nickname" - ? "请填写 1-20 个字符" + ? "请填写 2-24 个字符,不包括 @<>/等无效字符" : "请填写 2-100 个字符" } /> @@ -663,7 +667,9 @@ const UserInfoCardComponent: React.FC = ({ visible={ntrp_picker_visible} setvisible={setNtrpPickerVisible} value={ - !form_data.ntrp_level || form_data.ntrp_level === "0" ? ["3.0"] : [form_data.ntrp_level] + !form_data.ntrp_level || form_data.ntrp_level === "0" + ? ["3.0"] + : [form_data.ntrp_level] } onChange={handle_ntrp_level_change} /> @@ -842,8 +848,9 @@ export const GameTabs: React.FC = ({ {hosted_text} on_tab_change("participated")} > {participated_text} diff --git a/src/user_pages/edit/index.tsx b/src/user_pages/edit/index.tsx index 8d514c2..780669c 100644 --- a/src/user_pages/edit/index.tsx +++ b/src/user_pages/edit/index.tsx @@ -416,8 +416,8 @@ const EditProfilePage: React.FC = () => { }; const handleAddGroup = () => { - console.log("加入社群~") - } + console.log("加入社群~"); + }; const getDefaultOption = (options) => { if (!Array.isArray(options) || options.length === 0) { @@ -693,9 +693,9 @@ const EditProfilePage: React.FC = () => { > {form_data.phone ? form_data.phone.replace( - /(\d{3})(\d{4})(\d{4})/, - "$1 $2 $3" - ) + /(\d{3})(\d{4})(\d{4})/, + "$1 $2 $3" + ) : "未绑定"} { - + 客服聊天 @@ -747,124 +749,115 @@ const EditProfilePage: React.FC = () => { : "介绍一下你的喜好,或者训练习惯" } initialValue={form_data[editing_field as keyof typeof form_data] || ""} - maxLength={editing_field === "nickname" ? 20 : 100} + maxLength={editing_field === "nickname" ? 24 : 100} + invalidCharacters={editing_field === "nickname" ? "@<>/" : ""} onSave={handle_edit_modal_save} onCancel={handle_edit_modal_cancel} validationMessage={ editing_field === "nickname" - ? "请填写 1-20 个字符" + ? "请填写 2-24 个字符,不包括 @<>/等无效字符" : "请填写 2-100 个字符" } /> {/* 性别选择弹窗 */} - { - gender_picker_visible && ( - - ) - } + {gender_picker_visible && ( + + )} {/* 生日选择弹窗 */} - { - birthday_picker_visible && ( - - ) - } + {birthday_picker_visible && ( + + )} {/* 地区选择弹窗 */} - { - location_picker_visible && ( - - ) - } + {location_picker_visible && ( + + )} {/* NTRP水平选择弹窗 */} - { - ntrp_picker_visible && ( - - ) - } + {ntrp_picker_visible && ( + + )} {/* 职业选择弹窗 */} - { - occupation_picker_visible && ( - - ) - } + {occupation_picker_visible && ( + + )} {/* 取消关注确认弹窗 */} { contentTitle="确定要注销账号吗?" contentDesc="你的账号将会彻底删除,该操作不可恢复。" /> - + ); };