diff --git a/src/components/JobPortalHeader/index.less b/src/components/JobPortalHeader/index.less index eb8f8ce..9757b0b 100644 --- a/src/components/JobPortalHeader/index.less +++ b/src/components/JobPortalHeader/index.less @@ -245,6 +245,22 @@ margin: 0 4px; } + .search-input-autocomplete { + flex: 1; + min-width: 0; + + .ant-select-selector { + border: none !important; + box-shadow: none !important; + background: transparent !important; + padding: 0 !important; + } + + .search-input { + width: 100%; + } + } + .search-input { flex: 1; min-width: 0; @@ -341,6 +357,14 @@ } } +.job-suggestion-option { + padding: 4px 2px; + color: @jp-text-primary; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + @media (max-width: 768px) { .job-portal-header { .top-utility-bar .utility-container { diff --git a/src/components/JobPortalHeader/index.tsx b/src/components/JobPortalHeader/index.tsx index 4e5dbc3..deea569 100644 --- a/src/components/JobPortalHeader/index.tsx +++ b/src/components/JobPortalHeader/index.tsx @@ -1,5 +1,6 @@ -import React, { useState, useEffect } from 'react'; +import React, { useState, useEffect, useRef } from 'react'; import { + AutoComplete, Input, Select, Button, @@ -26,7 +27,7 @@ import { PORTAL_LOGIN_URL, prefetchJobPortalUserInfo, } from '@/utils/jobPortalAuth'; -import { getJobRecommend } from '@/services/common/jobTitle'; +import { getJobRecommend, getJobSuggestions } from '@/services/common/jobTitle'; import { getMessageTotal } from '@/services/jobportal/user'; import topBg1 from '@/assets/images/top-bg1.png'; import topBg2 from '@/assets/images/top-bg2.png'; @@ -53,6 +54,9 @@ const JobPortalHeader: React.FC = ({ const [jobRecommendData, setJobRecommendData] = useState(null); const [currentBgIndex, setCurrentBgIndex] = useState(0); const [unreadCount, setUnreadCount] = useState(0); + const [suggestions, setSuggestions] = useState([]); + const [suggestionsLoading, setSuggestionsLoading] = useState(false); + const suggestionRequestId = useRef(0); const location = useLocation(); @@ -195,10 +199,12 @@ const JobPortalHeader: React.FC = ({ }, [showHotJobs]); // 处理搜索功能 - const handleSearch = () => { - if (searchValue.trim()) { + const handleSearch = (value?: string) => { + const keyword = (value ?? searchValue).trim(); + if (keyword) { + setSuggestions([]); // 跳转到职位列表页面,传递搜索参数 - history.push(`/job-portal/list`, { queryParams: { name: searchValue.trim() } }); + history.push(`/job-portal/list`, { queryParams: { name: keyword } }); } else { message.warning('请输入搜索关键词'); } @@ -209,6 +215,40 @@ const JobPortalHeader: React.FC = ({ setSearchValue(e.target.value); }; + // 输入停止后请求岗位联想,避免每个字符都立即请求后端。 + useEffect(() => { + const keyword = searchValue.trim(); + const requestId = ++suggestionRequestId.current; + + if (!keyword) { + setSuggestions([]); + setSuggestionsLoading(false); + return; + } + + const timer = window.setTimeout(async () => { + setSuggestionsLoading(true); + try { + const response = await getJobSuggestions(keyword, 10); + if (requestId !== suggestionRequestId.current) { + return; + } + const data = Array.isArray(response?.data) ? response.data : []; + setSuggestions(data.filter((item): item is string => typeof item === 'string' && item.trim().length > 0)); + } catch (error) { + if (requestId === suggestionRequestId.current) { + setSuggestions([]); + } + } finally { + if (requestId === suggestionRequestId.current) { + setSuggestionsLoading(false); + } + } + }, 250); + + return () => window.clearTimeout(timer); + }, [searchValue]); + // 处理回车搜索 const handleSearchKeyPress = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { @@ -216,6 +256,11 @@ const JobPortalHeader: React.FC = ({ } }; + const suggestionOptions = suggestions.map((suggestion) => ({ + value: suggestion, + label:
{suggestion}
, + })); + // 处理热门职位点击 const handleHotJobClick = (job: string) => { history.push(`/job-portal/list`, { queryParams: { name: job } }); @@ -355,19 +400,28 @@ const JobPortalHeader: React.FC = ({ - + options={suggestionOptions} + onChange={(value) => setSearchValue(value)} + onSelect={(value) => handleSearch(value)} + popupMatchSelectWidth={false} + notFoundContent={suggestionsLoading ? '正在搜索...' : null} + > + + diff --git a/src/services/common/jobTitle.ts b/src/services/common/jobTitle.ts index 820f38f..cbd8d05 100644 --- a/src/services/common/jobTitle.ts +++ b/src/services/common/jobTitle.ts @@ -18,6 +18,14 @@ export async function getJobRecommend(params?: { jobTitle?: string }) { }); } +/** 获取岗位名称联想 GET /api/app/job/suggest */ +export async function getJobSuggestions(keyword: string, limit = 10) { + return request<{ code: number; msg?: string; data?: string[] }>('/api/app/job/suggest', { + method: 'GET', + params: { keyword, limit }, + }); +} + // 获取职位列表数据 export async function getJobList(jobCategory: string) { return request('/api/cms/job/recommend', {