Просмотр исходного кода

fix: 修复用户管理页面搜索框中文输入法消失问题

- 添加 composition 事件处理,使用 useRef 追踪输入法状态
- 确保输入法结束后才触发搜索,避免中文输入过程中被中断
- 修复角色筛选标签中重复的 X 组件问题
- 移除冗余的 X 图标,保持 UI 一致性

生成工具: [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 5 часов назад
Родитель
Сommit
8431c50fe7
1 измененных файлов с 18 добавлено и 17 удалено
  1. 18 17
      packages/user-management-ui/src/components/UserManagement.tsx

+ 18 - 17
packages/user-management-ui/src/components/UserManagement.tsx

@@ -1,4 +1,4 @@
-import React, { useState, useMemo, useCallback } from 'react';
+import React, { useState, useMemo, useCallback, useRef } from 'react';
 import { useQuery } from '@tanstack/react-query';
 import { format } from 'date-fns';
 import { Plus, Search, Edit, Trash2, Filter, X } from 'lucide-react';
@@ -57,6 +57,9 @@ export const UserManagement = () => {
 
   const [isCreateForm, setIsCreateForm] = useState(true);
 
+  // 输入法输入状态 - 使用 ref 确保同步更新
+  const isComposingRef = useRef(false);
+
   const createForm = useForm<CreateUserFormData>({
     resolver: zodResolver(createUserFormSchema),
     defaultValues: {
@@ -136,7 +139,10 @@ export const UserManagement = () => {
   const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
     const keyword = e.target.value;
     setSearchParams(prev => ({ ...prev, keyword }));
-    debouncedSearch(keyword);
+    // 只在非输入法状态下触发防抖更新(使用 ref 确保读取最新值)
+    if (!isComposingRef.current) {
+      debouncedSearch(keyword);
+    }
   };
 
   // 处理搜索表单提交
@@ -320,6 +326,12 @@ export const UserManagement = () => {
                   placeholder="搜索用户名、昵称或邮箱..."
                   value={searchParams.keyword || ''}
                   onChange={handleSearchChange}
+                  onCompositionStart={() => { isComposingRef.current = true }}
+                  onCompositionEnd={(e) => {
+                    isComposingRef.current = false;
+                    // 输入法结束后,使用最终输入的值触发搜索
+                    debouncedSearch(e.currentTarget.value);
+                  }}
                   className="pl-8"
                 />
               </div>
@@ -421,12 +433,6 @@ export const UserManagement = () => {
                               roleIds: filters.roleIds.filter(id => id !== roleId)
                             })}
                           />
-                          <X
-                            className="h-3 w-3 cursor-pointer pointer-events-auto"
-                            onClick={() => handleFilterChange({
-                              roleIds: filters.roleIds.filter(id => id !== roleId)
-                            })}
-                          />
                         </Badge>
                       ))}
                     </div>
@@ -487,27 +493,22 @@ export const UserManagement = () => {
                   </Badge>
                 )}
                 {filters.roleIds.map(roleId => (
-                  <Badge 
-                    key={roleId} 
-                    variant="secondary" 
+                  <Badge
+                    key={roleId}
+                    variant="secondary"
                     className="flex items-center gap-1 overflow-visible cursor-pointer hover:opacity-80"
                     onClick={() => handleFilterChange({
                       roleIds: filters.roleIds.filter(id => id !== roleId)
                     })}
                   >
                     角色: {roleId === 1 ? '管理员' : '普通用户'}
-                          <X
-                            className="h-3 w-3 cursor-pointer pointer-events-auto"
-                            onClick={() => handleFilterChange({
-                              roleIds: filters.roleIds.filter(id => id !== roleId)
-                            })}
-                          />
                     <X
                       className="h-3 w-3 cursor-pointer pointer-events-auto"
                       onClick={() => handleFilterChange({
                         roleIds: filters.roleIds.filter(id => id !== roleId)
                       })}
                     />
+                  </Badge>
                 ))}
                 {filters.createdAt && (
                   <Badge variant="secondary" className="flex items-center gap-1 overflow-visible">