feat: 改为卡片下方直接展开动画效果
- 移除弹窗式展示,改为在面试状态卡片下方直接展开 - 创建新的InterviewStatusAnimation组件,只展示动画 - 点击面试状态按钮后在卡片下方展开动画区域 - 移除标题和描述文字,界面更简洁 - 支持点击同一按钮收起动画 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
.interview-status-animation-wrapper {
|
||||
width: 100%;
|
||||
padding: 10px 0;
|
||||
background: linear-gradient(135deg, #f7faff 0%, #ffffff 100%);
|
||||
border-top: 1px solid #e5e6eb;
|
||||
animation: slideDown 0.3s ease-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
from {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
max-height: 200px;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.animation-container {
|
||||
width: 100%;
|
||||
height: 180px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.animation-container svg {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import lottie from 'lottie-web';
|
||||
import './index.css';
|
||||
|
||||
// 状态动画映射
|
||||
const statusAnimationMap = {
|
||||
'HR初筛未通过': () => import('@/assets/animations/interviewStatus/1-off_初筛未通过.json'),
|
||||
'HR评估中': () => import('@/assets/animations/interviewStatus/1-on_hr评估中.json'),
|
||||
'面试未通过': () => import('@/assets/animations/interviewStatus/2-off_面试未通过.json'),
|
||||
'到场面试': () => import('@/assets/animations/interviewStatus/2-on_到场面试.json'),
|
||||
'收到通知': () => import('@/assets/animations/interviewStatus/2-on_收到通知.json'),
|
||||
'等待面试': () => import('@/assets/animations/interviewStatus/2-wati_等待面试.json'),
|
||||
'未参与面试': () => import('@/assets/animations/interviewStatus/3-off_未参与面试.json'),
|
||||
'等待HR通知': () => import('@/assets/animations/interviewStatus/3-wati_等待HR通知.json'),
|
||||
'拒绝Offer': () => import('@/assets/animations/interviewStatus/4-off_拒绝Offer.json'),
|
||||
'收到Offer': () => import('@/assets/animations/interviewStatus/4-on_收到Offer.json'),
|
||||
'等待回复': () => import('@/assets/animations/interviewStatus/4-wati_等待回复.json'),
|
||||
};
|
||||
|
||||
export default ({ statusText, isOpen }) => {
|
||||
const animationContainer = useRef(null);
|
||||
const lottieInstance = useRef(null);
|
||||
const [animationData, setAnimationData] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && statusText) {
|
||||
// 加载对应的动画数据
|
||||
const loadAnimation = statusAnimationMap[statusText];
|
||||
if (loadAnimation) {
|
||||
loadAnimation().then(module => {
|
||||
setAnimationData(module.default);
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [isOpen, statusText]);
|
||||
|
||||
useEffect(() => {
|
||||
if (animationData && animationContainer.current && isOpen) {
|
||||
// 清除之前的动画实例
|
||||
if (lottieInstance.current) {
|
||||
lottieInstance.current.destroy();
|
||||
}
|
||||
|
||||
// 创建新的动画实例
|
||||
lottieInstance.current = lottie.loadAnimation({
|
||||
container: animationContainer.current,
|
||||
renderer: 'svg',
|
||||
loop: true,
|
||||
autoplay: true,
|
||||
animationData: animationData
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (lottieInstance.current) {
|
||||
lottieInstance.current.destroy();
|
||||
}
|
||||
};
|
||||
}
|
||||
}, [animationData, isOpen]);
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className="interview-status-animation-wrapper">
|
||||
<div className="animation-container" ref={animationContainer} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -136,12 +136,18 @@
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
.interview-item-wrapper {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.company-jobs-page-interview-item {
|
||||
flex-shrink: 0;
|
||||
width: 100%;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e5e6eb;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 0;
|
||||
box-sizing: border-box;
|
||||
padding: 20px;
|
||||
list-style: none;
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Spin, Empty } from "@arco-design/web-react";
|
||||
import InfiniteScroll from "@/components/InfiniteScroll";
|
||||
import toast from "@/components/Toast";
|
||||
import JobList from "./components/JobList";
|
||||
import InterviewStatusDropdown from "./components/InterviewStatusDropdown";
|
||||
import InterviewStatusAnimation from "./components/InterviewStatusAnimation";
|
||||
import {
|
||||
getCompanyJobsPageData,
|
||||
getJobsList,
|
||||
@@ -26,9 +26,7 @@ const CompanyJobsPage = () => {
|
||||
const [interviewsHasMore, setInterviewsHasMore] = useState(true);
|
||||
const [initialDataLoaded, setInitialDataLoaded] = useState(false);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [dropdownOpen, setDropdownOpen] = useState(false);
|
||||
const [selectedInterview, setSelectedInterview] = useState(null);
|
||||
const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0 });
|
||||
const [expandedItemId, setExpandedItemId] = useState(null);
|
||||
const navigate = useNavigate();
|
||||
|
||||
// 初始化页面数据 - 使用聚合接口
|
||||
@@ -127,25 +125,12 @@ const CompanyJobsPage = () => {
|
||||
// 处理面试状态点击
|
||||
const handleStatusClick = (e, item) => {
|
||||
e.stopPropagation();
|
||||
const rect = e.currentTarget.getBoundingClientRect();
|
||||
|
||||
// 计算下拉栏位置,让它在按钮下方居中
|
||||
const dropdownWidth = 360;
|
||||
const buttonCenter = rect.left + rect.width / 2;
|
||||
const left = Math.max(10, buttonCenter - dropdownWidth / 2);
|
||||
|
||||
setDropdownPosition({
|
||||
top: rect.bottom + 5,
|
||||
left: left
|
||||
});
|
||||
setSelectedInterview(item);
|
||||
setDropdownOpen(true);
|
||||
};
|
||||
|
||||
// 关闭下拉栏
|
||||
const handleCloseDropdown = () => {
|
||||
setDropdownOpen(false);
|
||||
setSelectedInterview(null);
|
||||
// 如果点击的是已展开的项,则收起;否则展开新项
|
||||
if (expandedItemId === item.id) {
|
||||
setExpandedItemId(null);
|
||||
} else {
|
||||
setExpandedItemId(item.id);
|
||||
}
|
||||
};
|
||||
|
||||
// 获取企业内推岗位 - 用于分页加载更多
|
||||
@@ -259,10 +244,8 @@ const CompanyJobsPage = () => {
|
||||
className="company-jobs-page-interview-list"
|
||||
>
|
||||
{interviews.map((item) => (
|
||||
<li
|
||||
className="company-jobs-page-interview-item"
|
||||
key={item.id}
|
||||
>
|
||||
<div key={item.id} className="interview-item-wrapper">
|
||||
<li className="company-jobs-page-interview-item">
|
||||
<div className="company-jobs-page-interview-item-info">
|
||||
<p className="company-jobs-page-interview-item-info-position">
|
||||
{item.position}
|
||||
@@ -297,6 +280,11 @@ const CompanyJobsPage = () => {
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<InterviewStatusAnimation
|
||||
statusText={item.statusText}
|
||||
isOpen={expandedItemId === item.id}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
@@ -304,14 +292,7 @@ const CompanyJobsPage = () => {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{/* 面试状态下拉栏 */}
|
||||
<InterviewStatusDropdown
|
||||
status={selectedInterview?.status}
|
||||
statusText={selectedInterview?.statusText}
|
||||
isOpen={dropdownOpen}
|
||||
onClose={handleCloseDropdown}
|
||||
position={dropdownPosition}
|
||||
/>
|
||||
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user