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:
@@ -3,13 +3,15 @@
|
||||
height: 860px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
padding: 16px;
|
||||
background-color: #f2f3f5;
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
gap: 20px;
|
||||
|
||||
.interview-rating-header {
|
||||
width: 100%;
|
||||
@@ -28,69 +30,52 @@
|
||||
}
|
||||
}
|
||||
|
||||
.interview-rating-video-content {
|
||||
.interview-rating-video-section {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
background-color: #fff;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.interview-rating-video {
|
||||
width: 100%;
|
||||
height: 670px;
|
||||
height: 450px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
> video {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
> img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
.interview-rating-slide {
|
||||
width: 100%;
|
||||
height: 36px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
border-radius: 2px;
|
||||
background-color: #e8f3ff;
|
||||
margin-top: 60px;
|
||||
|
||||
> i {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-size: 100% 100%;
|
||||
margin: 0 5px;
|
||||
background-image: url("@/assets/images/InterviewSimulationPage/slide_up_icon.png");
|
||||
}
|
||||
> span {
|
||||
font-size: 14px;
|
||||
color: #2c7aff;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 滑动后 */
|
||||
.interview-evaluation-wrapper {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
overflow-y: auto;
|
||||
/* 面试评分图表区域 */
|
||||
|
||||
.interview-rating-header {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.interview-evaluation-charts-wrapper {
|
||||
width: 100%;
|
||||
height: 660px;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
flex-shrink: 0;
|
||||
.interview-evaluation-charts-wrapper {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
flex-shrink: 0;
|
||||
|
||||
.charts-content {
|
||||
width: 100%;
|
||||
@@ -180,36 +165,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
.interview-evaluation-text-wrapper {
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
.interview-evaluation-text-wrapper {
|
||||
width: 100%;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
box-sizing: border-box;
|
||||
background-color: #fff;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
|
||||
.interview-rating-text {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
background-color: #f2f3f5;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
color: #1d2129;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
}
|
||||
.interview-rating-text {
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
background-color: #f2f3f5;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
padding: 16px;
|
||||
color: #1d2129;
|
||||
font-size: 16px;
|
||||
font-weight: 400;
|
||||
line-height: 1.6;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.interview-rating-wrapper2 {
|
||||
padding: 0px;
|
||||
border-radius: 0;
|
||||
overflow: auto;
|
||||
background-color: #f2f3f5;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -18,22 +18,19 @@
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
font-weight: 700;
|
||||
line-height: 20px;
|
||||
color: #1d2129;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #e5e6eb;
|
||||
margin-bottom: 20px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 20px;
|
||||
bottom: 5px;
|
||||
width: 31px;
|
||||
height: 3px;
|
||||
background-image: url("@/assets/images/Common/title_icon.png");
|
||||
background-size: 100% 100%;
|
||||
.mock-interview-title-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import { Timeline } from "@arco-design/web-react";
|
||||
import IconFont from "@/components/IconFont";
|
||||
import "./index.css";
|
||||
|
||||
const TimelineItem = Timeline.Item;
|
||||
@@ -14,7 +15,10 @@ export default ({ onItemSelect }) => {
|
||||
|
||||
return (
|
||||
<div className="mock-interview-wrapper">
|
||||
<p className="mock-interview-title">面试模拟</p>
|
||||
<p className="mock-interview-title">
|
||||
<IconFont className="mock-interview-title-icon" src="recuUY5uwYg4km" />
|
||||
<span>面试模拟</span>
|
||||
</p>
|
||||
<ul className="mock-interview-list">
|
||||
<li className="mock-interview-item">
|
||||
<p className="mock-interview-item-title">
|
||||
@@ -33,7 +37,24 @@ export default ({ onItemSelect }) => {
|
||||
onClick={() => handleItemClick("求职面试初体验")}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<p>求职面试初体验</p>
|
||||
<p>
|
||||
求职面试初体验
|
||||
<span style={{
|
||||
marginLeft: '8px',
|
||||
padding: '2px 8px',
|
||||
background: 'linear-gradient(135deg, #5DADE2 0%, #2874A6 100%)',
|
||||
borderRadius: '12px',
|
||||
color: '#ffffff',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
fontStyle: 'italic',
|
||||
letterSpacing: '1px',
|
||||
textTransform: 'uppercase',
|
||||
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
|
||||
}}>
|
||||
demo
|
||||
</span>
|
||||
</p>
|
||||
<div className="time-line-item-info">
|
||||
初次接触面试环境,体验真实面试流程,了解自身在面试中的基本表现和待提升的方面
|
||||
</div>
|
||||
@@ -48,7 +69,24 @@ export default ({ onItemSelect }) => {
|
||||
onClick={() => handleItemClick("未来的自己")}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<p>未来的自己</p>
|
||||
<p>
|
||||
未来的自己
|
||||
<span style={{
|
||||
marginLeft: '8px',
|
||||
padding: '2px 8px',
|
||||
background: 'linear-gradient(135deg, #5DADE2 0%, #2874A6 100%)',
|
||||
borderRadius: '12px',
|
||||
color: '#ffffff',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
fontStyle: 'italic',
|
||||
letterSpacing: '1px',
|
||||
textTransform: 'uppercase',
|
||||
boxShadow: '0 2px 4px rgba(0,0,0,0.1)'
|
||||
}}>
|
||||
demo
|
||||
</span>
|
||||
</p>
|
||||
<div className="time-line-item-info">
|
||||
经过系统训练后的面试表现,展示个人成长和进步,体现出更强的职场竞争力和专业素养
|
||||
</div>
|
||||
@@ -98,30 +136,6 @@ export default ({ onItemSelect }) => {
|
||||
<p>第三次线下面试模拟</p>
|
||||
</div>
|
||||
</TimelineItem>
|
||||
<TimelineItem
|
||||
lineType="dashed"
|
||||
dot={<div className={`time-line-dot-icon ${selectedItem === "第四次线下面试模拟" ? "time-line-dot-icon-active" : ""}`} />}
|
||||
>
|
||||
<div
|
||||
className={`time-line-item ${selectedItem === "第四次线下面试模拟" ? "time-line-item-active" : ""}`}
|
||||
onClick={() => handleItemClick("第四次线下面试模拟")}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<p>第四次线下面试模拟</p>
|
||||
</div>
|
||||
</TimelineItem>
|
||||
<TimelineItem
|
||||
lineType="dashed"
|
||||
dot={<div className={`time-line-dot-icon ${selectedItem === "第五次线下面试模拟" ? "time-line-dot-icon-active" : ""}`} />}
|
||||
>
|
||||
<div
|
||||
className={`time-line-item ${selectedItem === "第五次线下面试模拟" ? "time-line-item-active" : ""}`}
|
||||
onClick={() => handleItemClick("第五次线下面试模拟")}
|
||||
style={{ cursor: "pointer" }}
|
||||
>
|
||||
<p>第五次线下面试模拟</p>
|
||||
</div>
|
||||
</TimelineItem>
|
||||
</Timeline>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -1,69 +1,125 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import { useRef, useEffect } from "react";
|
||||
import * as echarts from "echarts";
|
||||
|
||||
export default function RadarChart({
|
||||
data = [4200, 3000, 20000, 35000, 50000, 18000],
|
||||
data = [5, 8, 5, 8],
|
||||
value = null,
|
||||
indicator = [
|
||||
{ name: "Sales", max: 6500 },
|
||||
{ name: "Administration", max: 16000 },
|
||||
{ name: "Information Technology", max: 30000 },
|
||||
{ name: "Customer Support", max: 38000 },
|
||||
{ name: "Development", max: 52000 },
|
||||
{ name: "Marketing", max: 25000 },
|
||||
],
|
||||
className = "",
|
||||
lineClolr = "#DCDFFF",
|
||||
areaColor = "#CCCDFC",
|
||||
areaBorderColor = "#BDB5FF",
|
||||
}) {
|
||||
const chartRef = useRef(null);
|
||||
const chartInstance = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!chartRef.current) return;
|
||||
chartInstance.current = echarts.init(chartRef.current);
|
||||
|
||||
const option = {
|
||||
radar: {
|
||||
const option = {
|
||||
tooltip: { show: false },
|
||||
grid: { show: false },
|
||||
radar: [
|
||||
{
|
||||
center: ["50%", "55%"],
|
||||
indicator,
|
||||
radius: "65%", // 默认 65%,调大即可把文字整体外推
|
||||
nameGap: 20, // 再额外增加 6-12px 间距
|
||||
splitArea: { show: false }, // 关键:不显示花纹
|
||||
shape: "circle", // 设置雷达图外圈为圆形
|
||||
// 网格线样式配置
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: lineClolr, // 网格线颜色
|
||||
width: 2,
|
||||
type: "solid", // 线条类型:solid, dashed, dotted
|
||||
},
|
||||
},
|
||||
splitArea: { show: false },
|
||||
axisName: {
|
||||
color: "#4E5969",
|
||||
fontSize: 12,
|
||||
align: "center", // 水平居中
|
||||
verticalAlign: "middle", // 垂直居中
|
||||
lineHeight: 14, // 与富文本行高一致
|
||||
rich: {
|
||||
a: { fontSize: 12, color: "#4E5969" },
|
||||
b: { fontSize: 12, color: "#4E5969" },
|
||||
formatter: function(value) {
|
||||
// 移除富文本标记,只返回纯文本
|
||||
return value.replace(/{[ab]\|([^}]+)}/g, '$1').replace(/\n/g, '');
|
||||
},
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#E5E6EB",
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "radar",
|
||||
data: [{ value: data }],
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: "radar",
|
||||
radarIndex: 0,
|
||||
data: [{
|
||||
value: value || data,
|
||||
label: {
|
||||
// 关键:显示数值
|
||||
show: true,
|
||||
formatter: "{c}", // 取当前轴值
|
||||
show: false, // 关键:隐藏雷达图内的标签
|
||||
},
|
||||
emphasis: {
|
||||
label: {
|
||||
show: false, // 确保 hover 时也不显示
|
||||
},
|
||||
fontSize: 12,
|
||||
color: "#333",
|
||||
},
|
||||
areaStyle: {}, // 关键:显示面积
|
||||
symbol: "none", // 关键:隐藏所有交点
|
||||
},
|
||||
],
|
||||
};
|
||||
chartInstance.current.setOption(option);
|
||||
areaStyle: {
|
||||
color: areaColor, // 面积填充颜色
|
||||
}, // 关键:显示面积
|
||||
lineStyle: {
|
||||
color: areaBorderColor, // 连接线颜色(边框颜色)
|
||||
width: 3, // 连接线宽度
|
||||
type: "solid", // 线条类型
|
||||
},
|
||||
symbol: "circle", // 显示端点
|
||||
symbolSize: 6, // 端点大小
|
||||
itemStyle: {
|
||||
color: "#fff", // 端点颜色
|
||||
borderColor: areaColor, // 端点边框颜色
|
||||
borderWidth: 2, // 端点边框宽度
|
||||
},
|
||||
}],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!chartRef.current) return;
|
||||
|
||||
// 如果实例不存在,则初始化
|
||||
if (!chartInstance.current) {
|
||||
chartInstance.current = echarts.init(chartRef.current);
|
||||
}
|
||||
|
||||
// 设置或更新配置,使用 notMerge: false 来避免重新触发动画
|
||||
chartInstance.current.setOption(option, {
|
||||
notMerge: false,
|
||||
lazyUpdate: true,
|
||||
silent: false,
|
||||
});
|
||||
|
||||
const handleResize = () => {
|
||||
chartInstance.current?.resize();
|
||||
};
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
|
||||
// 自适应
|
||||
const resize = () => chartInstance.current?.resize();
|
||||
window.addEventListener("resize", resize);
|
||||
return () => {
|
||||
window.removeEventListener("resize", resize);
|
||||
window.removeEventListener("resize", handleResize);
|
||||
};
|
||||
}, [data, value, indicator]);
|
||||
|
||||
// 组件卸载时清理
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
chartInstance.current?.dispose();
|
||||
};
|
||||
}, [data, indicator, className]);
|
||||
}, []);
|
||||
|
||||
return <div ref={chartRef} className={className} />;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import { useEffect, useRef } from "react";
|
||||
import * as echarts from "echarts";
|
||||
|
||||
export default function RadarChart({
|
||||
data = [4200, 3000, 20000, 35000, 50000, 18000],
|
||||
indicator = [
|
||||
{ name: "Sales", max: 6500 },
|
||||
{ name: "Administration", max: 16000 },
|
||||
{ name: "Information Technology", max: 30000 },
|
||||
{ name: "Customer Support", max: 38000 },
|
||||
{ name: "Development", max: 52000 },
|
||||
{ name: "Marketing", max: 25000 },
|
||||
],
|
||||
className = "",
|
||||
}) {
|
||||
const chartRef = useRef(null);
|
||||
const chartInstance = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!chartRef.current) return;
|
||||
chartInstance.current = echarts.init(chartRef.current);
|
||||
|
||||
const option = {
|
||||
radar: {
|
||||
indicator,
|
||||
radius: "65%", // 默认 65%,调大即可把文字整体外推
|
||||
nameGap: 20, // 再额外增加 6-12px 间距
|
||||
splitArea: { show: false }, // 关键:不显示花纹
|
||||
axisName: {
|
||||
color: "#4E5969",
|
||||
fontSize: 12,
|
||||
align: "center", // 水平居中
|
||||
verticalAlign: "middle", // 垂直居中
|
||||
lineHeight: 14, // 与富文本行高一致
|
||||
rich: {
|
||||
a: { fontSize: 12, color: "#4E5969" },
|
||||
b: { fontSize: 12, color: "#4E5969" },
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "radar",
|
||||
data: [{ value: data }],
|
||||
label: {
|
||||
// 关键:显示数值
|
||||
show: true,
|
||||
formatter: "{c}", // 取当前轴值
|
||||
fontSize: 12,
|
||||
color: "#333",
|
||||
},
|
||||
areaStyle: {}, // 关键:显示面积
|
||||
symbol: "none", // 关键:隐藏所有交点
|
||||
},
|
||||
],
|
||||
};
|
||||
chartInstance.current.setOption(option);
|
||||
|
||||
// 自适应
|
||||
const resize = () => chartInstance.current?.resize();
|
||||
window.addEventListener("resize", resize);
|
||||
return () => {
|
||||
window.removeEventListener("resize", resize);
|
||||
chartInstance.current?.dispose();
|
||||
};
|
||||
}, [data, indicator, className]);
|
||||
|
||||
return <div ref={chartRef} className={className} />;
|
||||
}
|
||||
@@ -1,19 +1,14 @@
|
||||
import { useRef, useEffect, useState } from "react";
|
||||
import { useRef, useEffect } from "react";
|
||||
import * as echarts from "echarts";
|
||||
|
||||
const screenWidth = window.screen.width;
|
||||
|
||||
const ScoreChart = ({
|
||||
className = "",
|
||||
value = 70, // 当前得分(0-100)
|
||||
colors = [
|
||||
[1 / 6, "#FF4C3C"],
|
||||
[2 / 6, "#FF8855"],
|
||||
[3 / 6, "#FFBA62"],
|
||||
[4 / 6, "#A5CC58"],
|
||||
[5 / 6, "#66B86F"],
|
||||
[1, "#49AB55"],
|
||||
],
|
||||
colors = new echarts.graphic.LinearGradient(0, 0, 1, 0, [
|
||||
// 渐变色配置
|
||||
{ offset: 0, color: "#2C7FFF" }, // 起始颜色(左端)
|
||||
{ offset: 1, color: "#2CA9FF" }, // 结束颜色(右端)
|
||||
]),
|
||||
}) => {
|
||||
const chartRef = useRef(null);
|
||||
const chartInstance = useRef(null);
|
||||
@@ -24,56 +19,90 @@ const ScoreChart = ({
|
||||
useEffect(() => {
|
||||
if (!chartRef.current) return;
|
||||
|
||||
// 销毁旧实例
|
||||
if (chartInstance.current) chartInstance.current.dispose();
|
||||
|
||||
// 新建实例
|
||||
chartInstance.current = echarts.init(chartRef.current);
|
||||
// 如果实例不存在,则初始化
|
||||
if (!chartInstance.current) {
|
||||
chartInstance.current = echarts.init(chartRef.current);
|
||||
}
|
||||
|
||||
const option = {
|
||||
series: [
|
||||
{
|
||||
type: "gauge",
|
||||
center: ["50%", "80%"],
|
||||
startAngle: 180,
|
||||
endAngle: 360,
|
||||
min: 0,
|
||||
max: 120,
|
||||
splitNumber: 10,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 15,
|
||||
max: 100,
|
||||
radius: "100%",
|
||||
splitNumber: 5,
|
||||
itemStyle: {
|
||||
color: "#FFAB91",
|
||||
},
|
||||
progress: {
|
||||
show: true,
|
||||
width: 20,
|
||||
roundCap: true, // 开启圆角
|
||||
itemStyle: {
|
||||
color: colors,
|
||||
},
|
||||
},
|
||||
pointer: {
|
||||
length: "60%",
|
||||
itemStyle: { color: "auto" },
|
||||
show: false,
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 20,
|
||||
},
|
||||
},
|
||||
axisTick: { show: false },
|
||||
splitLine: { show: false },
|
||||
axisLabel: { show: false },
|
||||
detail: {
|
||||
fontSize: 20,
|
||||
offsetCenter: [0, "60%"],
|
||||
valueAnimation: true,
|
||||
formatter: "{value}.00\n总评分",
|
||||
color: "inherit",
|
||||
anchor: {
|
||||
show: false,
|
||||
},
|
||||
radius: "100%",
|
||||
data: [{ value }],
|
||||
title: {
|
||||
show: false,
|
||||
},
|
||||
detail: {
|
||||
valueAnimation: true,
|
||||
lineHeight: 40,
|
||||
borderRadius: 8,
|
||||
offsetCenter: [0, "-15%"],
|
||||
fontSize: 24,
|
||||
formatter: "{value}.00 ",
|
||||
color: "#1D2129",
|
||||
},
|
||||
data: [
|
||||
{
|
||||
value,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
// 设置或更新配置,避免重新触发动画
|
||||
chartInstance.current.setOption(option, {
|
||||
notMerge: false,
|
||||
lazyUpdate: true,
|
||||
silent: false,
|
||||
});
|
||||
|
||||
// 监听窗口变化
|
||||
window.addEventListener("resize", resize);
|
||||
return () => {
|
||||
window.removeEventListener("resize", resize);
|
||||
chartInstance.current?.dispose();
|
||||
};
|
||||
}, [value, colors]);
|
||||
|
||||
// 组件卸载时清理
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
chartInstance.current?.dispose();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return <div ref={chartRef} className={className} />;
|
||||
};
|
||||
|
||||
export default ScoreChart;
|
||||
export default ScoreChart;
|
||||
@@ -0,0 +1,79 @@
|
||||
import { useRef, useEffect, useState } from "react";
|
||||
import * as echarts from "echarts";
|
||||
|
||||
const screenWidth = window.screen.width;
|
||||
|
||||
const ScoreChart = ({
|
||||
className = "",
|
||||
value = 70, // 当前得分(0-100)
|
||||
colors = [
|
||||
[1 / 6, "#FF4C3C"],
|
||||
[2 / 6, "#FF8855"],
|
||||
[3 / 6, "#FFBA62"],
|
||||
[4 / 6, "#A5CC58"],
|
||||
[5 / 6, "#66B86F"],
|
||||
[1, "#49AB55"],
|
||||
],
|
||||
}) => {
|
||||
const chartRef = useRef(null);
|
||||
const chartInstance = useRef(null);
|
||||
|
||||
// 图表自适应容器
|
||||
const resize = () => chartInstance.current?.resize();
|
||||
|
||||
useEffect(() => {
|
||||
if (!chartRef.current) return;
|
||||
|
||||
// 销毁旧实例
|
||||
if (chartInstance.current) chartInstance.current.dispose();
|
||||
|
||||
// 新建实例
|
||||
chartInstance.current = echarts.init(chartRef.current);
|
||||
|
||||
const option = {
|
||||
series: [
|
||||
{
|
||||
type: "gauge",
|
||||
min: 0,
|
||||
max: 120,
|
||||
splitNumber: 10,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
width: 15,
|
||||
color: colors,
|
||||
},
|
||||
},
|
||||
pointer: {
|
||||
length: "60%",
|
||||
itemStyle: { color: "auto" },
|
||||
},
|
||||
axisTick: { show: false },
|
||||
splitLine: { show: false },
|
||||
axisLabel: { show: false },
|
||||
detail: {
|
||||
fontSize: 20,
|
||||
offsetCenter: [0, "60%"],
|
||||
valueAnimation: true,
|
||||
formatter: "{value}.00\n总评分",
|
||||
color: "inherit",
|
||||
},
|
||||
radius: "100%",
|
||||
data: [{ value }],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
chartInstance.current.setOption(option);
|
||||
|
||||
// 监听窗口变化
|
||||
window.addEventListener("resize", resize);
|
||||
return () => {
|
||||
window.removeEventListener("resize", resize);
|
||||
chartInstance.current?.dispose();
|
||||
};
|
||||
}, [value, colors]);
|
||||
|
||||
return <div ref={chartRef} className={className} />;
|
||||
};
|
||||
|
||||
export default ScoreChart;
|
||||
Reference in New Issue
Block a user