11
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:
francis-fh
2026-06-04 16:25:38 +08:00
parent 3815dd63da
commit 03f26885c5
32 changed files with 2642 additions and 3062 deletions

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react';
import React, { useState, useEffect, useMemo } from 'react';
import { useParams, history, useLocation } from '@umijs/max';
import {
Card,
@@ -27,10 +27,17 @@ import {
import { Radar } from '@ant-design/charts';
import JobPortalHeader from '@/components/JobPortalHeader';
import './index.less';
import { getJobCompetitiveness } from '@/services/jobportal/competitiveness';
import {
getJobCompetitiveness,
getEmptyCompetitivenessRadar,
} from '@/services/jobportal/competitiveness';
import { isJobPortalLoggedIn } from '@/utils/jobPortalAuth';
import { favoriteJob, unfavoriteJob, applyJob } from '@/services/jobportal/user';
import { getAccessToken } from '@/access';
import { PageEnum } from '@/enums/pagesEnums';
import { ensureJobPortalLogin, PORTAL_LOGIN_URL } from '@/utils/jobPortalAuth';
import { getDictLabel, findTreeLabelById } from '@/utils/jobPortalDict';
import { getDictValueEnum } from '@/services/system/dict';
import { getCmsIndustryTreeList } from '@/services/classify/industry';
import type { DictValueEnumObj } from '@/components/DictTag';
const { Title, Text, Paragraph } = Typography;
@@ -106,11 +113,13 @@ const transformJobData = (jobData: any) => {
<p>3. 具备良好的团队协作能力;</p>
`,
companyInfo: {
name: jobData.companyName || jobData.company,
type: jobData.industry || '互联网/电子商务',
scale: jobData.scale || '100-499人',
industry: jobData.industry || '计算机/互联网',
description: jobData.companyVo?.companyDescription || jobData.companyDescription || '暂无公司描述信息'
name: jobData.companyName || jobData.company || jobData.companyVo?.name,
scale: jobData.companyVo?.scale ?? jobData.scale ?? '',
industry: jobData.companyVo?.industry ?? jobData.industry ?? '',
description:
jobData.companyVo?.companyDescription
|| jobData.companyDescription
|| '暂无公司描述信息',
},
competitiveness: {
overall: 75,
@@ -157,7 +166,6 @@ const mockJobDetail = {
`,
companyInfo: {
name: '青岛科技发展有限公司',
type: '互联网/电子商务',
scale: '500-999人',
industry: '计算机/互联网',
description: '青岛科技发展有限公司是一家专注于软件开发、技术服务的科技企业。公司致力于为客户提供优质的IT解决方案业务涵盖企业信息化、移动应用开发等领域。我们拥有一支年轻、专业的团队注重技术创新和人才培养为员工提供良好的发展平台。'
@@ -193,6 +201,36 @@ const JobDetailPage: React.FC = () => {
{ item: '年龄', score: 0 },
{ item: '工作地', score: 0 }
]);
const [scaleEnum, setScaleEnum] = useState<DictValueEnumObj>({});
const [industryTree, setIndustryTree] = useState<any[]>([]);
useEffect(() => {
Promise.all([
getDictValueEnum('scale', true, true),
getCmsIndustryTreeList(),
]).then(([scaleData, industryRes]) => {
setScaleEnum(scaleData);
if (industryRes?.code === 200 && industryRes?.data) {
setIndustryTree(industryRes.data);
}
});
}, []);
const companyMetaItems = useMemo(() => {
const company = originalJobData?.companyVo || {};
const rawScale = company.scale ?? originalJobData?.scale ?? jobDetail.companyInfo?.scale;
const rawIndustry =
company.industry ?? originalJobData?.industry ?? jobDetail.companyInfo?.industry;
const items: string[] = [];
const scaleLabel = getDictLabel(scaleEnum, rawScale) || rawScale;
const industryLabel = findTreeLabelById(industryTree, rawIndustry) || rawIndustry;
if (scaleLabel) items.push(scaleLabel);
if (industryLabel) items.push(industryLabel);
return items;
}, [originalJobData, jobDetail.companyInfo, scaleEnum, industryTree]);
useEffect(() => {
// 首先尝试从传递的数据中获取职位信息
@@ -226,10 +264,19 @@ const JobDetailPage: React.FC = () => {
}, [jobDetail?.id]);
const fetchCompetitiveness = async (jobIdNum: number) => {
if (!isJobPortalLoggedIn()) {
setOverallScore(0);
setRadarData(getEmptyCompetitivenessRadar());
return;
}
try {
const res = await getJobCompetitiveness(jobIdNum);
const data = res as any;
if (!data) return;
if (!data) {
setOverallScore(0);
setRadarData(getEmptyCompetitivenessRadar());
return;
}
if (typeof data.matchScore === 'number') {
const clamped = Math.max(0, Math.min(100, data.matchScore));
setOverallScore(clamped);
@@ -248,36 +295,25 @@ const JobDetailPage: React.FC = () => {
].map(d => ({ ...d, score: Math.max(0, Math.min(100, d.score)) }));
setRadarData(mapped);
} else {
setRadarData([
{ item: '技能', score: 0 },
{ item: '工作经验', score: 0 },
{ item: '学历', score: 0 },
{ item: '薪资', score: 0 },
{ item: '年龄', score: 0 },
{ item: '工作地', score: 0 }
]);
setRadarData(getEmptyCompetitivenessRadar());
}
} catch (e) {
// 保持默认mock数据
setOverallScore(0);
setRadarData(getEmptyCompetitivenessRadar());
}
};
const handleCollect = async () => {
// 检查用户是否登录
const token = getAccessToken();
if (!token) {
message.warning('请先登录');
history.push(PageEnum.LOGIN);
if (!ensureJobPortalLogin('收藏职位')) {
return;
}
// 如果是取消收藏,调用取消收藏接口
if (isFavorited) {
// 获取用户ID
const userId = getUserIdFromCache();
if (!userId) {
message.warning('无法获取用户信息,请重新登录');
history.push(PageEnum.LOGIN);
window.location.href = PORTAL_LOGIN_URL;
return;
}
@@ -307,12 +343,10 @@ const JobDetailPage: React.FC = () => {
return;
}
// 如果是收藏,调用收藏接口
// 获取用户ID
const userId = getUserIdFromCache();
if (!userId) {
message.warning('无法获取用户信息,请重新登录');
history.push(PageEnum.LOGIN);
window.location.href = PORTAL_LOGIN_URL;
return;
}
@@ -342,19 +376,14 @@ const JobDetailPage: React.FC = () => {
};
const handleApply = async () => {
// 检查用户是否登录
const token = getAccessToken();
if (!token) {
message.warning('请先登录');
history.push(PageEnum.LOGIN);
if (!ensureJobPortalLogin('申请职位')) {
return;
}
// 获取用户ID
const userId = getUserIdFromCache();
if (!userId) {
message.warning('无法获取用户信息,请重新登录');
history.push(PageEnum.LOGIN);
window.location.href = PORTAL_LOGIN_URL;
return;
}
@@ -471,12 +500,10 @@ const JobDetailPage: React.FC = () => {
<Title level={4} style={{ margin: 0 }}>
{jobDetail.companyInfo.name}
</Title>
<Space className="company-meta">
<Text>{jobDetail.companyInfo.type}</Text>
<Divider type="vertical" />
<Text>{jobDetail.companyInfo.scale}</Text>
<Divider type="vertical" />
<Text>{jobDetail.companyInfo.industry}</Text>
<Space className="company-meta" split={<Divider type="vertical" />}>
{companyMetaItems.map((label) => (
<Text key={label}>{label}</Text>
))}
</Space>
</div>
</Space>