UI优化更新:面试模拟、简历面试、项目库、求职策略等多个页面改进

主要更新:
- 面试模拟页:移除上滑查看评价,添加渐进式评分(72→81→89)
- 简历面试页:添加岗位头像、标签背景、面试题加粗等视觉优化
- 项目库页:添加"我完成的项目库"板块,增加hover效果
- 求职策略详情页:优化圆柱体和矩形对齐,添加CSV岗位数据,调整批次文字位置
- 企业岗位列表页:添加返回按钮功能
- 全局:统一岗位级别术语(普通岗/技术骨干岗/储备干部岗)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
KQL
2025-09-05 20:46:03 +08:00
parent 1703894e74
commit 4e0e96e6b8
64 changed files with 7806 additions and 2112 deletions

View File

@@ -3,15 +3,7 @@ import ScoreChart from "../ScoreChart";
import RadarChart from "../RadarChart";
import "./index.css";
// 滑动阈值(向上滑动超过这个距离触发切换)
const SWIPE_THRESHOLD = 100;
export default ({ selectedItem = "求职面试初体验" }) => {
const [isSlide, setIsSlide] = useState(false);
const [isDragging, setIsDragging] = useState(false);
const [startY, setStartY] = useState(0);
const [currentY, setCurrentY] = useState(0);
const slideRef = useRef(null);
// 根据选中项目获取对应的视频URL
const getVideoUrl = () => {
switch(selectedItem) {
@@ -19,6 +11,12 @@ export default ({ selectedItem = "求职面试初体验" }) => {
return "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/video/teach_sys/interview_offline_vedio/recuUpJSOKoqAm.mov";
case "未来的自己":
return "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/video/teach_sys/interview_offline_vedio/recuUpJT02CMM5.mp4";
case "第一次线下面试模拟":
return "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/video/teach_sys/interview_offline_vedio/recuUpJSOKoqAm.mov"; // 使用相同视频作为示例
case "第二次线下面试模拟":
return "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/video/teach_sys/interview_offline_vedio/recuUpJT02CMM5.mp4"; // 使用相同视频作为示例
case "第三次线下面试模拟":
return "https://ddcz-1315997005.cos.ap-nanjing.myqcloud.com/static/video/teach_sys/interview_offline_vedio/recuUpJSOKoqAm.mov"; // 使用相同视频作为示例
default:
return "";
}
@@ -26,7 +24,9 @@ export default ({ selectedItem = "求职面试初体验" }) => {
// 判断是否是锁定的面试模拟项目
const isLockedItem = () => {
return selectedItem?.includes("线下面试模拟");
return selectedItem === "第一次线下面试模拟" ||
selectedItem === "第二次线下面试模拟" ||
selectedItem === "第三次线下面试模拟";
};
// 根据选中项目获取评价数据
@@ -42,11 +42,47 @@ export default ({ selectedItem = "求职面试初体验" }) => {
沟通表达上,候选人语言表达流畅自然,逻辑思维清晰有条理,能够积极主动地与面试官互动。在面对开放性问题时展现出良好的思维发散能力,回答层次分明,重点突出,表现出强烈的学习意愿和职业发展规划意识。整体表现超出预期,具备优秀的职场素养。`
};
} else if (selectedItem === "第一次线下面试模拟") {
return {
totalScore: 72,
professionalScore: 28.0,
performanceScore: 44.0,
radarData: [7, 6, 7, 7],
radarData2: [6, 6, 5, 6],
title: "初次模拟评价",
content: `在专业能力方面,候选人对基础知识有一定了解,但在深入问题上表现不够自信。回答问题时思路基本清晰,但缺乏具体案例支撑。对行业动态的了解较为表面,需要加强专业知识的深度学习。在描述项目经验时,表达略显生疏,未能充分展现个人价值。
沟通表达上,候选人表现出一定的紧张情绪,语速较快,有时会出现词不达意的情况。逻辑性有待加强,回答问题时容易偏离主题。肢体语言不够自然,眼神交流不足。建议多进行面试练习,提升表达的流畅度和自信心。整体来看,还有较大的提升空间。`
};
} else if (selectedItem === "第二次线下面试模拟") {
return {
totalScore: 81,
professionalScore: 32.5,
performanceScore: 48.5,
radarData: [8, 7, 8, 8],
radarData2: [7, 7, 6, 7],
title: "进步明显评价",
content: `在专业能力方面,候选人相比第一次有明显进步,对专业知识的理解更加深入。能够结合实际案例阐述观点,展现出一定的实践经验。对于技术问题的回答更有条理,能够抓住问题的关键点。行业认知有所提升,能够说出一些前沿趋势。
沟通表达上,紧张情绪明显缓解,语速适中,表达更加清晰。逻辑结构有所改善,能够按照"总-分-总"的结构组织答案。肢体语言更加自然,与面试官的互动增多。自信心有所提升,敢于表达自己的观点。但在一些压力问题上仍需加强应对能力。`
};
} else if (selectedItem === "第三次线下面试模拟") {
return {
totalScore: 89,
professionalScore: 36.5,
performanceScore: 52.5,
radarData: [9, 8, 9, 9],
radarData2: [8, 8, 7, 8],
title: "接近优秀评价",
content: `在专业能力方面,候选人展现出扎实的专业功底,能够深入浅出地解释复杂概念。项目经验描述详实,能够清楚说明技术难点和解决方案。对行业发展有独到见解,能够将理论与实践很好地结合。专业深度和广度都达到了较高水平。
沟通表达上,表现自然从容,完全没有紧张感。语言组织能力强,逻辑清晰,重点突出。能够根据面试官的反应及时调整表达方式,展现出良好的沟通技巧。肢体语言得体,眼神交流充分,整体气场稳定。已经基本具备了通过正式面试的能力,继续保持即可。`
};
} else {
return {
totalScore: 85,
professionalScore: 38.0,
performanceScore: 50.0,
professionalScore: 34.0,
performanceScore: 51.0,
radarData: [9, 8, 9, 9],
title: "基础面试评价",
content: `在专业能力方面,候选人对 [岗位相关专业知识] 有基本掌握,能够清晰回答与过往项目经验相关的问题,例如在描述 [具体项目] 时,能准确说明自己承担的职责和达成的成果,体现出一定的实践操作能力。但在深入探讨 [某一专业难点] 时,表述略显浅显,对行业前沿动态的了解不够全面,专业深度有提升空间。
@@ -56,164 +92,37 @@ export default ({ selectedItem = "求职面试初体验" }) => {
}
};
// 处理触摸/鼠标开始
const handleStart = (clientY) => {
setIsDragging(true);
setStartY(clientY);
setCurrentY(clientY);
if (slideRef.current) {
slideRef.current.style.transition = "none";
}
// 判断是否应该显示评价内容
const shouldShowEvaluation = () => {
return selectedItem === "求职面试初体验" ||
selectedItem === "未来的自己" ||
selectedItem === "第一次线下面试模拟" ||
selectedItem === "第二次线下面试模拟" ||
selectedItem === "第三次线下面试模拟";
};
// 处理触摸/鼠标移动
const handleMove = (clientY) => {
if (!isDragging) return;
setCurrentY(clientY);
const diffY = startY - clientY; // 正值表示向上滑动,负值表示向下滑动
if (isSlide) {
// 在评价界面时,只允许向下滑动
if (diffY < 0) {
const translateY = Math.min(Math.abs(diffY), 150);
if (slideRef.current) {
slideRef.current.style.transform = `translateY(${translateY}px)`;
}
}
} else {
// 在视频界面时,只允许向上滑动,且只对懵懂初试的项目生效
if (diffY > 0 && (selectedItem === "求职面试初体验" || selectedItem === "未来的自己")) {
const translateY = Math.min(diffY, 150);
if (slideRef.current) {
slideRef.current.style.transform = `translateY(-${translateY}px)`;
}
}
}
};
// 处理触摸/鼠标结束
const handleEnd = () => {
if (!isDragging) return;
setIsDragging(false);
const diffY = startY - currentY;
// 恢复位置
if (slideRef.current) {
slideRef.current.style.transition = "transform 0.3s ease";
slideRef.current.style.transform = "";
}
// 检查滑动方向和阈值
if (isSlide) {
// 在评价界面时,向下滑动返回视频界面
if (diffY < -SWIPE_THRESHOLD) {
handleSwipeDown();
}
} else {
// 在视频界面时,向上滑动到评价界面
if (diffY > SWIPE_THRESHOLD) {
handleSwipeUp();
}
}
};
// 向上滑动事件处理
const handleSwipeUp = () => {
// 只有懵懂初试的项目可以上滑查看评价
if (selectedItem === "求职面试初体验" || selectedItem === "未来的自己") {
console.log("触发向上滑动切换");
setIsSlide(true);
}
};
// 向下滑动事件处理
const handleSwipeDown = () => {
console.log("触发向下滑动返回");
setIsSlide(false);
};
// 鼠标事件处理
const handleMouseDown = (e) => {
handleStart(e.clientY);
};
const handleMouseMove = (e) => {
if (isDragging) {
e.preventDefault();
handleMove(e.clientY);
}
};
const handleMouseUp = () => {
handleEnd();
};
const handleMouseLeave = () => {
handleEnd();
};
// 触摸事件处理
const handleTouchStart = (e) => {
handleStart(e.touches[0].clientY);
};
const handleTouchMove = (e) => {
if (isDragging) {
e.preventDefault();
handleMove(e.touches[0].clientY);
}
};
const handleTouchEnd = () => {
handleEnd();
};
// 添加全局事件监听
useEffect(() => {
const handleGlobalMouseMove = (e) => handleMouseMove(e);
const handleGlobalMouseUp = () => handleMouseUp();
if (isDragging) {
document.addEventListener("mousemove", handleGlobalMouseMove);
document.addEventListener("mouseup", handleGlobalMouseUp);
document.body.style.cursor = "grabbing";
document.body.style.userSelect = "none";
}
return () => {
document.removeEventListener("mousemove", handleGlobalMouseMove);
document.removeEventListener("mouseup", handleGlobalMouseUp);
document.body.style.cursor = "";
document.body.style.userSelect = "";
};
}, [isDragging]);
return (
<div
className={`interview-rating-wrapper ${
isSlide ? "interview-rating-wrapper2" : ""
}`}
>
{isSlide ? (
<div
className="interview-evaluation-wrapper"
ref={slideRef}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onMouseLeave={handleMouseLeave}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
style={{
cursor: "grab",
userSelect: "none",
WebkitUserSelect: "none",
touchAction: "pan-x",
}}
>
<div className="interview-rating-wrapper">
{/* 视频播放器区域 */}
<div className="interview-rating-video-section">
<div className="interview-rating-header">
<span className="interview-rating-header-title">
钢铁是怎样炼成的
</span>
</div>
<div className="interview-rating-video">
{isLockedItem() ? (
<img src="/线下面试模拟锁定.png" alt="线下面试模拟锁定" style={{width: "100%", height: "100%", objectFit: "cover"}} />
) : (
<video src={getVideoUrl()} controls></video>
)}
</div>
</div>
{/* 评价内容区域 - 仅在特定项目时显示 */}
{shouldShowEvaluation() && (
<>
{/* 面试评分区域 */}
<div className="interview-evaluation-charts-wrapper">
<div className="interview-rating-header">
<span className="interview-rating-header-title">面试评分</span>
@@ -241,16 +150,30 @@ export default ({ selectedItem = "求职面试初体验" }) => {
className="radar-chart"
data={getEvaluationData().radarData}
indicator={[
{ name: "{a|核心知识掌握}\\n{b|与精准应用}", max: 10 },
{ name: "{a|问题分析方案设计}\\n{b|与成果表达}", max: 10 },
{ name: "{a|产业认知与行业}\\n{b|趋势洞察}", max: 10 },
{ name: "{a|企业工作流}\\n{b|理解与实践}", max: 10 },
{ name: "核心知识掌握与精准应用", max: 10 },
{ name: "问题分析方案设计与成果表达", max: 10 },
{ name: "产业认知与行业趋势洞察", max: 10 },
{ name: "企业工作流理解与实践", max: 10 },
]}
/>
<RadarChart className="radar-chart" />
<RadarChart
className="radar-chart"
data={getEvaluationData().radarData2 || [7, 8, 6, 7]}
indicator={[
{ name: "沟通表达与逻辑思维", max: 10 },
{ name: "团队协作与责任意识", max: 10 },
{ name: "学习能力与适应能力", max: 10 },
{ name: "职业素养与发展潜力", max: 10 },
]}
lineClolr="#FFE4D9"
areaColor="#FFD4C1"
areaBorderColor="#FFB89A"
/>
</div>
</div>
</div>
{/* 基础面试评价区域 */}
<div className="interview-evaluation-text-wrapper">
<div className="interview-rating-header">
<span className="interview-rating-header-title">{getEvaluationData().title}</span>
@@ -259,42 +182,7 @@ export default ({ selectedItem = "求职面试初体验" }) => {
{getEvaluationData().content}
</div>
</div>
</div>
) : (
<div
className="interview-rating-video-content"
ref={slideRef}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onMouseLeave={handleMouseLeave}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={handleTouchEnd}
style={{
cursor: "grab",
userSelect: "none",
WebkitUserSelect: "none",
touchAction: "pan-x",
}}
>
<div className="interview-rating-header">
<span className="interview-rating-header-title">
钢铁是怎样炼成的
</span>
</div>
<div className="interview-rating-video">
{isLockedItem() ? (
<img src="/线下面试模拟锁定.png" alt="线下面试模拟锁定" style={{width: "100%", height: "100%", objectFit: "cover"}} />
) : (
<video src={getVideoUrl()} controls></video>
)}
</div>
<div className="interview-rating-slide">
<i />
<span>上滑查看评价</span>
</div>
</div>
</>
)}
</div>
);