bug修复
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
Some checks failed
Node CI / build (14.x, macOS-latest) (push) Has been cancelled
Node CI / build (14.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (14.x, windows-latest) (push) Has been cancelled
Node CI / build (16.x, macOS-latest) (push) Has been cancelled
Node CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node CI / build (16.x, windows-latest) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
coverage CI / build (push) Has been cancelled
Node pnpm CI / build (16.x, macOS-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, ubuntu-latest) (push) Has been cancelled
Node pnpm CI / build (16.x, windows-latest) (push) Has been cancelled
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { AvatarDropdown, AvatarName, Footer, SelectLang } from '@/components';
|
||||
import EnterpriseHeader from '@/components/EnterpriseHeader';
|
||||
import type { Settings as LayoutSettings } from '@ant-design/pro-components';
|
||||
import { SettingDrawer } from '@ant-design/pro-components';
|
||||
import type { RunTimeLayoutConfig } from '@umijs/max';
|
||||
@@ -166,8 +167,11 @@ export const layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) =
|
||||
// 增加一个 loading 的状态
|
||||
childrenRender: (children) => {
|
||||
// if (initialState?.loading) return <PageLoading />;
|
||||
// roles?.[0] 为 'view' 时是企业账号,显示返回首页顶栏
|
||||
const isEnterprise = initialState?.currentUser?.userType === 'view';
|
||||
return (
|
||||
<>
|
||||
{isEnterprise && <EnterpriseHeader />}
|
||||
{children}
|
||||
<SettingDrawer
|
||||
disableUrlParams
|
||||
|
||||
109
src/components/EnterpriseHeader/index.less
Normal file
109
src/components/EnterpriseHeader/index.less
Normal file
@@ -0,0 +1,109 @@
|
||||
.enterprise-header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 48px;
|
||||
padding: 0 24px;
|
||||
background: #1890ff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15), 0 1px 3px rgba(0, 0, 0, 0.08);
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
|
||||
.header-logo {
|
||||
height: 32px;
|
||||
width: auto;
|
||||
display: block;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.header-divider {
|
||||
width: 1px;
|
||||
height: 20px;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.header-system-name {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
}
|
||||
|
||||
.header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.home-link-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
height: 32px;
|
||||
padding: 0 16px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #fff;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
border: 1px solid rgba(255, 255, 255, 0.25);
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
transition: all 0.25s ease;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
|
||||
.anticon {
|
||||
font-size: 15px;
|
||||
transition: transform 0.25s ease;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: #1677ff;
|
||||
background: #fff;
|
||||
border-color: #fff;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
transform: translateY(-1px);
|
||||
|
||||
.anticon {
|
||||
transform: translateX(-3px);
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 企业头部出现时,整个 ProLayout 向下偏移 48px
|
||||
body.has-enterprise-header {
|
||||
.ant-pro-layout {
|
||||
padding-top: 48px;
|
||||
}
|
||||
|
||||
// 固定侧边栏也需要偏移
|
||||
.ant-pro-sider.ant-layout-sider.ant-pro-sider-fixed {
|
||||
top: 48px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.enterprise-header {
|
||||
padding: 0 12px;
|
||||
|
||||
.header-left .header-system-name {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
42
src/components/EnterpriseHeader/index.tsx
Normal file
42
src/components/EnterpriseHeader/index.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import { HomeOutlined } from '@ant-design/icons';
|
||||
import portalLogo from '@/assets/logo.png';
|
||||
import './index.less';
|
||||
|
||||
/** 人社门户首页地址 */
|
||||
const PORTAL_HOME_URL = 'http://218.31.252.15:9081/hrss-web-vue/home';
|
||||
|
||||
const EnterpriseHeader: React.FC = () => {
|
||||
useEffect(() => {
|
||||
document.body.classList.add('has-enterprise-header');
|
||||
return () => {
|
||||
document.body.classList.remove('has-enterprise-header');
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleGoHome = () => {
|
||||
window.open(PORTAL_HOME_URL, '_blank');
|
||||
};
|
||||
|
||||
const header = (
|
||||
<div className="enterprise-header">
|
||||
<div className="header-left">
|
||||
<img className="header-logo" src={portalLogo} alt="石城智慧就业" />
|
||||
<div className="header-divider" />
|
||||
<span className="header-system-name">石河子智慧就业 · 企业管理端</span>
|
||||
</div>
|
||||
|
||||
<div className="header-right">
|
||||
<div className="home-link-btn" onClick={handleGoHome}>
|
||||
<HomeOutlined />
|
||||
<span>返回首页</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return createPortal(header, document.body);
|
||||
};
|
||||
|
||||
export default EnterpriseHeader;
|
||||
@@ -8,5 +8,6 @@
|
||||
import Footer from './Footer';
|
||||
import { Question, SelectLang } from './RightContent';
|
||||
import { AvatarDropdown, AvatarName } from './RightContent/AvatarDropdown';
|
||||
import EnterpriseHeader from './EnterpriseHeader';
|
||||
|
||||
export { Footer, Question, SelectLang, AvatarDropdown, AvatarName };
|
||||
export { Footer, Question, SelectLang, AvatarDropdown, AvatarName, EnterpriseHeader };
|
||||
|
||||
@@ -184,12 +184,54 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
flex-wrap: wrap;
|
||||
gap: 12px;
|
||||
|
||||
.jobs-section-header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.jobs-title {
|
||||
.jp-section-title();
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.expectation-tags {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.expectation-label {
|
||||
font-size: 13px;
|
||||
color: @jp-text-secondary;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.expectation-tag {
|
||||
.jp-job-tag();
|
||||
padding: 4px 12px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
transition: all 0.2s;
|
||||
border-radius: 20px;
|
||||
|
||||
&:hover {
|
||||
background: @jp-primary !important;
|
||||
color: #fff !important;
|
||||
border-color: @jp-primary !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: @jp-primary !important;
|
||||
color: #fff !important;
|
||||
border-color: @jp-primary !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.view-more {
|
||||
color: @jp-primary;
|
||||
font-size: 14px;
|
||||
|
||||
@@ -15,6 +15,8 @@ import {
|
||||
} from '@ant-design/icons';
|
||||
import { history } from '@umijs/max';
|
||||
import { getJobTitleTreeSelect, getJobRecommend } from '@/services/common/jobTitle';
|
||||
import { getGetInfoCache, saveGetInfoCache } from '@/utils/jobPortalAuth';
|
||||
import { getUserInfo } from '@/services/session';
|
||||
import JobPortalHeader from '@/components/JobPortalHeader';
|
||||
import './index.less';
|
||||
|
||||
@@ -128,6 +130,33 @@ const JobPortalPage: React.FC = () => {
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
const [itemsPerPage] = useState<number>(6);
|
||||
const [totalPages, setTotalPages] = useState<number>(1);
|
||||
const [activeJobTitle, setActiveJobTitle] = useState<string>('');
|
||||
const [jobTitles, setJobTitles] = useState<string[]>(() => {
|
||||
// 初始化时先尝试从缓存读取
|
||||
return (getGetInfoCache()?.user as any)?.jobTitles || [];
|
||||
});
|
||||
|
||||
// 缓存可能因 SSO 登录时序问题尚未写入,主动拉取一次
|
||||
useEffect(() => {
|
||||
if (jobTitles.length > 0) return;
|
||||
const cached = (getGetInfoCache()?.user as any)?.jobTitles;
|
||||
if (cached?.length) {
|
||||
setJobTitles(cached);
|
||||
return;
|
||||
}
|
||||
// 缓存不存在则请求 /api/getInfo 写入后再读取
|
||||
getUserInfo({ skipErrorHandler: true })
|
||||
.then((res: any) => {
|
||||
saveGetInfoCache(res as Record<string, unknown>);
|
||||
const titles = (res?.user as any)?.jobTitles;
|
||||
if (titles?.length) {
|
||||
setJobTitles(titles);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// 静默处理
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const fetchJobTitleData = async () => {
|
||||
@@ -147,9 +176,9 @@ const JobPortalPage: React.FC = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const fetchJobRecommendData = async () => {
|
||||
const fetchJobRecommendData = async (jobTitle?: string) => {
|
||||
try {
|
||||
const response = await getJobRecommend();
|
||||
const response = await getJobRecommend(jobTitle ? { jobTitle } : undefined);
|
||||
setJobRecommendData(response);
|
||||
} catch {
|
||||
// 静默处理
|
||||
@@ -217,6 +246,20 @@ const JobPortalPage: React.FC = () => {
|
||||
history.push(`/job-portal/list`, { queryParams: { name } });
|
||||
};
|
||||
|
||||
const handleExpectationTagClick = (jobTitle: string) => {
|
||||
const newActive = activeJobTitle === jobTitle ? '' : jobTitle;
|
||||
setActiveJobTitle(newActive);
|
||||
const fetchJobRecommendData = async () => {
|
||||
try {
|
||||
const response = await getJobRecommend(newActive ? { jobTitle: newActive } : undefined);
|
||||
setJobRecommendData(response);
|
||||
} catch {
|
||||
// 静默处理
|
||||
}
|
||||
};
|
||||
fetchJobRecommendData();
|
||||
};
|
||||
|
||||
const renderJobCards = () => {
|
||||
const jobs = jobRecommendData?.data;
|
||||
if (jobs?.length) {
|
||||
@@ -358,7 +401,23 @@ const JobPortalPage: React.FC = () => {
|
||||
|
||||
<div className="jobs-section">
|
||||
<div className="jobs-section-header">
|
||||
<div className="jobs-section-header-left">
|
||||
<Title level={3} className="jobs-title">热门职位推荐</Title>
|
||||
{jobTitles.length > 0 && (
|
||||
<div className="expectation-tags">
|
||||
<span className="expectation-label">求职期望</span>
|
||||
{jobTitles.map((title) => (
|
||||
<Tag
|
||||
key={title}
|
||||
className={`expectation-tag ${activeJobTitle === title ? 'active' : ''}`}
|
||||
onClick={() => handleExpectationTagClick(title)}
|
||||
>
|
||||
{title}
|
||||
</Tag>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<span className="view-more" onClick={() => history.push('/job-portal/list')}>
|
||||
查看更多 >
|
||||
</span>
|
||||
|
||||
@@ -8,11 +8,12 @@ export async function getJobTitleTreeSelect() {
|
||||
}
|
||||
|
||||
// 获取热门岗位推荐数据
|
||||
export async function getJobRecommend() {
|
||||
export async function getJobRecommend(params?: { jobTitle?: string }) {
|
||||
return request('/api/cms/job/recommend', {
|
||||
method: 'GET',
|
||||
params: {
|
||||
order: 2
|
||||
order: 2,
|
||||
...(params?.jobTitle ? { jobTitle: params.jobTitle } : {})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user