diff --git a/src/components/Navbars/SearchBar/SearchBar.js b/src/components/Navbars/SearchBar/SearchBar.js
index a9b01329..332e50a6 100755
--- a/src/components/Navbars/SearchBar/SearchBar.js
+++ b/src/components/Navbars/SearchBar/SearchBar.js
@@ -1,45 +1,188 @@
-import React from "react";
+// src/components/Navbars/SearchBar/SearchBar.js
+// 全局股票搜索栏 - 模糊搜索 + 下拉选择
+
+import React, { useRef, useEffect, useCallback } from "react";
+import { useNavigate } from "react-router-dom";
import {
- IconButton,
+ Box,
Input,
InputGroup,
InputLeftElement,
+ InputRightElement,
+ IconButton,
+ Text,
+ VStack,
+ HStack,
+ Spinner,
useColorModeValue,
+ Tag,
+ Center,
+ List,
+ ListItem,
+ Flex,
} from "@chakra-ui/react";
-import { SearchIcon } from "@chakra-ui/icons";
+import { SearchIcon, CloseIcon } from "@chakra-ui/icons";
+import { useStockSearch } from "@hooks/useStockSearch";
+
export function SearchBar(props) {
- // Pass the computed styles into the `__css` prop
const { variant, children, ...rest } = props;
- // Chakra Color Mode
- const searchIconColor = useColorModeValue("gray.700", "gray.200");
- const inputBg = useColorModeValue("white", "navy.800");
+ const navigate = useNavigate();
+ const containerRef = useRef(null);
+
+ // 颜色配置
+ const searchIconColor = useColorModeValue("gray.500", "gray.400");
+ const inputBg = useColorModeValue("white", "whiteAlpha.100");
+ const dropdownBg = useColorModeValue("white", "#1a1a2e");
+ const borderColor = useColorModeValue("gray.200", "whiteAlpha.200");
+ const hoverBg = useColorModeValue("gray.50", "whiteAlpha.100");
+ const textColor = useColorModeValue("gray.800", "white");
+ const subTextColor = useColorModeValue("gray.500", "whiteAlpha.600");
+ const accentColor = useColorModeValue("blue.500", "#D4AF37");
+
+ // 使用搜索 Hook
+ const {
+ searchQuery,
+ searchResults,
+ isSearching,
+ showResults,
+ handleSearch,
+ clearSearch,
+ setShowResults,
+ } = useStockSearch({ limit: 10, debounceMs: 300 });
+
+ // 点击外部关闭下拉
+ useEffect(() => {
+ const handleClickOutside = (event) => {
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
+ setShowResults(false);
+ }
+ };
+ document.addEventListener("mousedown", handleClickOutside);
+ return () => document.removeEventListener("mousedown", handleClickOutside);
+ }, [setShowResults]);
+
+ // 选择股票 - 跳转到详情页
+ const handleSelectStock = useCallback((stock) => {
+ clearSearch();
+ // 跳转到股票详情页
+ navigate(`/company/${stock.stock_code}`);
+ }, [navigate, clearSearch]);
+
+ // 处理键盘事件
+ const handleKeyDown = useCallback((e) => {
+ if (e.key === "Enter" && searchResults.length > 0) {
+ handleSelectStock(searchResults[0]);
+ } else if (e.key === "Escape") {
+ setShowResults(false);
+ }
+ }, [searchResults, handleSelectStock, setShowResults]);
+
return (
-
-
- }>
- }
- />
-
-
+
+
+
+
+
+ handleSearch(e.target.value)}
+ onKeyDown={handleKeyDown}
+ onFocus={() => searchQuery && searchResults.length > 0 && setShowResults(true)}
+ borderColor={borderColor}
+ _hover={{ borderColor: accentColor }}
+ _focus={{ borderColor: accentColor, boxShadow: `0 0 0 1px ${accentColor}` }}
+ />
+ {(searchQuery || isSearching) && (
+
+ {isSearching ? (
+
+ ) : (
+ }
+ onClick={clearSearch}
+ aria-label="清除搜索"
+ _hover={{ bg: "transparent" }}
+ />
+ )}
+
+ )}
+
+
+ {/* 搜索结果下拉 */}
+ {showResults && (
+
+ {searchResults.length > 0 ? (
+
+ {searchResults.map((stock, index) => (
+ handleSelectStock(stock)}
+ borderBottomWidth={index < searchResults.length - 1 ? "1px" : "0"}
+ borderColor={borderColor}
+ >
+
+
+
+ {stock.stock_name}
+
+
+
+ {stock.stock_code}
+
+ {stock.pinyin_abbr && (
+
+ ({stock.pinyin_abbr.toUpperCase()})
+
+ )}
+
+
+ {stock.exchange && (
+
+ {stock.exchange}
+
+ )}
+
+
+ ))}
+
+ ) : (
+
+
+ {searchQuery ? "未找到相关股票" : "输入股票代码或名称搜索"}
+
+
+ )}
+
+ )}
+
);
}