mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-10 11:36:36 +08:00
feat: Implement toggleable search input and data filtering across tunnel, user, and forward pages.
This commit is contained in:
@@ -76,6 +76,7 @@ import {
|
||||
executeForwardBatchToggleService,
|
||||
} from "@/pages/forward/batch-actions";
|
||||
import { buildForwardOrder, FORWARD_ORDER_KEY } from "@/pages/forward/order";
|
||||
import { SearchIcon } from "@/components/icons";
|
||||
import { PageLoadingState } from "@/components/page-state";
|
||||
import { useMobileBreakpoint } from "@/hooks/useMobileBreakpoint";
|
||||
import { saveOrder } from "@/utils/order-storage";
|
||||
@@ -126,6 +127,8 @@ export default function ForwardPage() {
|
||||
const [forwards, setForwards] = useState<Forward[]>([]);
|
||||
const [tunnels, setTunnels] = useState<Tunnel[]>([]);
|
||||
const isMobile = useMobileBreakpoint();
|
||||
const [searchKeyword, setSearchKeyword] = useState("");
|
||||
const [isSearchVisible, setIsSearchVisible] = useState(false);
|
||||
|
||||
// 显示模式状态 - 从localStorage读取,默认为平铺显示
|
||||
const [viewMode, setViewMode] = useState<"grouped" | "direct">(() => {
|
||||
@@ -1103,6 +1106,15 @@ export default function ForwardPage() {
|
||||
filteredForwards = filteredForwards.filter(f => f.tunnelId === targetTunnelId);
|
||||
}
|
||||
|
||||
if (searchKeyword.trim()) {
|
||||
const lowerKeyword = searchKeyword.toLowerCase();
|
||||
filteredForwards = filteredForwards.filter(f =>
|
||||
(f.name && f.name.toLowerCase().includes(lowerKeyword)) ||
|
||||
(f.remoteAddr && f.remoteAddr.toLowerCase().includes(lowerKeyword)) ||
|
||||
(f.userName && f.userName.toLowerCase().includes(lowerKeyword))
|
||||
);
|
||||
}
|
||||
|
||||
// 确保过滤后的转发列表有效
|
||||
if (!filteredForwards || filteredForwards.length === 0) {
|
||||
return [];
|
||||
@@ -1144,7 +1156,7 @@ export default function ForwardPage() {
|
||||
}
|
||||
|
||||
return sortedByDb;
|
||||
}, [forwards, forwardOrder, viewMode, tokenUserId, filterUserId, filterTunnelId]);
|
||||
}, [forwards, forwardOrder, viewMode, tokenUserId, filterUserId, filterTunnelId, searchKeyword]);
|
||||
|
||||
const sortableForwardIds = useMemo(
|
||||
() => sortedForwards.map((f) => f.id).filter((id) => id > 0),
|
||||
@@ -1609,8 +1621,64 @@ export default function ForwardPage() {
|
||||
return (
|
||||
<div className="px-3 lg:px-6 py-8">
|
||||
{/* 页面头部 */}
|
||||
<div className="flex items-center justify-between mb-6 gap-2">
|
||||
<div className="flex-1"></div>
|
||||
<div className="flex flex-col sm:flex-row items-stretch sm:items-center justify-between mb-6 gap-3">
|
||||
<div className="flex-1 max-w-sm flex items-center gap-2">
|
||||
{!isSearchVisible ? (
|
||||
<Button
|
||||
isIconOnly
|
||||
aria-label="搜索"
|
||||
className="text-default-600"
|
||||
color="default"
|
||||
size="sm"
|
||||
variant="flat"
|
||||
onPress={() => setIsSearchVisible(true)}
|
||||
>
|
||||
<SearchIcon className="w-4 h-4" />
|
||||
</Button>
|
||||
) : (
|
||||
<div className="flex w-full items-center gap-2 animate-appearance-in">
|
||||
<Input
|
||||
autoFocus
|
||||
classNames={{
|
||||
base: "bg-default-100",
|
||||
input: "bg-transparent",
|
||||
inputWrapper:
|
||||
"bg-default-100 border-2 border-default-200 hover:border-default-300 data-[hover=true]:border-default-300",
|
||||
}}
|
||||
placeholder="搜索转发名称、地址或用户名"
|
||||
value={searchKeyword}
|
||||
onChange={(e) => setSearchKeyword(e.target.value)}
|
||||
/>
|
||||
<Button
|
||||
isIconOnly
|
||||
aria-label="关闭搜索"
|
||||
className="text-default-600 shrink-0"
|
||||
color="default"
|
||||
size="sm"
|
||||
variant="light"
|
||||
onPress={() => {
|
||||
setIsSearchVisible(false);
|
||||
setSearchKeyword("");
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="w-4 h-4"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
d="M6 18L18 6M6 6l12 12"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth={2}
|
||||
/>
|
||||
</svg>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center justify-end gap-2 sm:gap-3">
|
||||
{/* 筛选按钮 */}
|
||||
<Button
|
||||
|
||||
Reference in New Issue
Block a user