更新Company页面的UI为FUI风格

This commit is contained in:
2025-12-18 00:05:55 +08:00
parent 852438b17e
commit 3199e6764d

View File

@@ -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 (
<InputGroup borderRadius='8px' w='200px' {...rest}>
<InputLeftElement
children={
<IconButton
bg='inherit'
borderRadius='inherit'
_hover={{}}
_active={{
bg: "inherit",
transform: "none",
borderColor: "transparent",
}}
_focus={{
boxShadow: "none",
}}
icon={
<SearchIcon color={searchIconColor} w='15px' h='15px' />
}></IconButton>
}
/>
<Input
variant='search'
fontSize='xs'
bg={inputBg}
placeholder='Type here...'
/>
</InputGroup>
<Box ref={containerRef} position="relative" {...rest}>
<InputGroup borderRadius="8px" w="220px">
<InputLeftElement pointerEvents="none">
<SearchIcon color={searchIconColor} w="15px" h="15px" />
</InputLeftElement>
<Input
variant="search"
fontSize="sm"
bg={inputBg}
placeholder="搜索股票..."
value={searchQuery}
onChange={(e) => 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) && (
<InputRightElement>
{isSearching ? (
<Spinner size="sm" color={accentColor} />
) : (
<IconButton
size="xs"
variant="ghost"
icon={<CloseIcon w="10px" h="10px" />}
onClick={clearSearch}
aria-label="清除搜索"
_hover={{ bg: "transparent" }}
/>
)}
</InputRightElement>
)}
</InputGroup>
{/* 搜索结果下拉 */}
{showResults && (
<Box
position="absolute"
top="100%"
left={0}
mt={2}
w="320px"
bg={dropdownBg}
border="1px solid"
borderColor={borderColor}
borderRadius="md"
boxShadow="lg"
maxH="400px"
overflowY="auto"
zIndex={9999}
>
{searchResults.length > 0 ? (
<List spacing={0}>
{searchResults.map((stock, index) => (
<ListItem
key={stock.stock_code}
px={4}
py={3}
cursor="pointer"
_hover={{ bg: hoverBg }}
onClick={() => handleSelectStock(stock)}
borderBottomWidth={index < searchResults.length - 1 ? "1px" : "0"}
borderColor={borderColor}
>
<Flex align="center" justify="space-between">
<VStack align="start" spacing={0} flex={1}>
<Text fontWeight="bold" color={textColor} fontSize="sm">
{stock.stock_name}
</Text>
<HStack spacing={2}>
<Text fontSize="xs" color={subTextColor}>
{stock.stock_code}
</Text>
{stock.pinyin_abbr && (
<Text fontSize="xs" color={subTextColor}>
({stock.pinyin_abbr.toUpperCase()})
</Text>
)}
</HStack>
</VStack>
{stock.exchange && (
<Tag
size="sm"
colorScheme="blue"
variant="subtle"
fontSize="xs"
>
{stock.exchange}
</Tag>
)}
</Flex>
</ListItem>
))}
</List>
) : (
<Center p={4}>
<Text color={subTextColor} fontSize="sm">
{searchQuery ? "未找到相关股票" : "输入股票代码或名称搜索"}
</Text>
</Center>
)}
</Box>
)}
</Box>
);
}