301 lines
11 KiB
React
301 lines
11 KiB
React
|
|
import { useState, useRef, useEffect } from "react";
|
|||
|
|
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) {
|
|||
|
|
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";
|
|||
|
|
default:
|
|||
|
|
return "";
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 判断是否是锁定的面试模拟项目
|
|||
|
|
const isLockedItem = () => {
|
|||
|
|
return selectedItem?.includes("线下面试模拟");
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 根据选中项目获取评价数据
|
|||
|
|
const getEvaluationData = () => {
|
|||
|
|
if (selectedItem === "未来的自己") {
|
|||
|
|
return {
|
|||
|
|
totalScore: 92,
|
|||
|
|
professionalScore: 39.5,
|
|||
|
|
performanceScore: 55.0,
|
|||
|
|
radarData: [10, 9, 10, 9],
|
|||
|
|
title: "优秀表现评价",
|
|||
|
|
content: `在专业能力方面,候选人对相关专业知识掌握扎实,能够深入且准确地回答与项目经验相关的复杂问题。在描述具体项目时,不仅能清晰说明自己的职责和成果,还能主动分析项目中的技术难点和解决方案,体现出优秀的实践操作能力和技术思维。对行业前沿动态有深入了解,能够结合实际工作提出创新性见解。
|
|||
|
|
|
|||
|
|
沟通表达上,候选人语言表达流畅自然,逻辑思维清晰有条理,能够积极主动地与面试官互动。在面对开放性问题时展现出良好的思维发散能力,回答层次分明,重点突出,表现出强烈的学习意愿和职业发展规划意识。整体表现超出预期,具备优秀的职场素养。`
|
|||
|
|
};
|
|||
|
|
} else {
|
|||
|
|
return {
|
|||
|
|
totalScore: 85,
|
|||
|
|
professionalScore: 38.0,
|
|||
|
|
performanceScore: 50.0,
|
|||
|
|
radarData: [9, 8, 9, 9],
|
|||
|
|
title: "基础面试评价",
|
|||
|
|
content: `在专业能力方面,候选人对 [岗位相关专业知识] 有基本掌握,能够清晰回答与过往项目经验相关的问题,例如在描述 [具体项目] 时,能准确说明自己承担的职责和达成的成果,体现出一定的实践操作能力。但在深入探讨 [某一专业难点] 时,表述略显浅显,对行业前沿动态的了解不够全面,专业深度有提升空间。
|
|||
|
|
|
|||
|
|
沟通表达上,候选人语言流畅,逻辑较为清晰,能够主动回应面试官的问题,展现出良好的沟通意愿。不过在面对一些开放性问题时,思维发散性稍弱,回答的层次感不够突出,有时会出现表述重复的情况。`
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 处理触摸/鼠标开始
|
|||
|
|
const handleStart = (clientY) => {
|
|||
|
|
setIsDragging(true);
|
|||
|
|
setStartY(clientY);
|
|||
|
|
setCurrentY(clientY);
|
|||
|
|
if (slideRef.current) {
|
|||
|
|
slideRef.current.style.transition = "none";
|
|||
|
|
}
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
// 处理触摸/鼠标移动
|
|||
|
|
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-evaluation-charts-wrapper">
|
|||
|
|
<div className="interview-rating-header">
|
|||
|
|
<span className="interview-rating-header-title">面试评分</span>
|
|||
|
|
</div>
|
|||
|
|
<div className="charts-content">
|
|||
|
|
<div className="charts-content-top">
|
|||
|
|
<ScoreChart className="score-chart" value={getEvaluationData().totalScore} />
|
|||
|
|
<div className="score-info">
|
|||
|
|
<div className="score-info-item item1">
|
|||
|
|
<span className="score-info-item-title">
|
|||
|
|
专业能力评分(40)
|
|||
|
|
</span>
|
|||
|
|
<span className="score-info-item-value">{getEvaluationData().professionalScore}</span>
|
|||
|
|
</div>
|
|||
|
|
<div className="score-info-item item2">
|
|||
|
|
<span className="score-info-item-title">
|
|||
|
|
现场表现评分(60)
|
|||
|
|
</span>
|
|||
|
|
<span className="score-info-item-value">{getEvaluationData().performanceScore}</span>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div className="charts-content-bottom">
|
|||
|
|
<RadarChart
|
|||
|
|
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 },
|
|||
|
|
]}
|
|||
|
|
/>
|
|||
|
|
<RadarChart className="radar-chart" />
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div className="interview-evaluation-text-wrapper">
|
|||
|
|
<div className="interview-rating-header">
|
|||
|
|
<span className="interview-rating-header-title">{getEvaluationData().title}</span>
|
|||
|
|
</div>
|
|||
|
|
<div className="interview-rating-text">
|
|||
|
|
{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>
|
|||
|
|
);
|
|||
|
|
};
|