From 01492feb5a51661b3cfd69306e61be9e125cbb35 Mon Sep 17 00:00:00 2001 From: KQL Date: Mon, 8 Sep 2025 05:34:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=B9=E4=B8=BA=E5=8D=A1=E7=89=87?= =?UTF-8?q?=E4=B8=8B=E6=96=B9=E7=9B=B4=E6=8E=A5=E5=B1=95=E5=BC=80=E5=8A=A8?= =?UTF-8?q?=E7=94=BB=E6=95=88=E6=9E=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 移除弹窗式展示,改为在面试状态卡片下方直接展开 - 创建新的InterviewStatusAnimation组件,只展示动画 - 点击面试状态按钮后在卡片下方展开动画区域 - 移除标题和描述文字,界面更简洁 - 支持点击同一按钮收起动画 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../InterviewStatusAnimation/index.css | 33 +++++ .../InterviewStatusAnimation/index.jsx | 68 ++++++++++ src/pages/CompanyJobsPage/index.css | 8 +- src/pages/CompanyJobsPage/index.jsx | 117 ++++++++---------- 4 files changed, 157 insertions(+), 69 deletions(-) create mode 100644 src/pages/CompanyJobsPage/components/InterviewStatusAnimation/index.css create mode 100644 src/pages/CompanyJobsPage/components/InterviewStatusAnimation/index.jsx diff --git a/src/pages/CompanyJobsPage/components/InterviewStatusAnimation/index.css b/src/pages/CompanyJobsPage/components/InterviewStatusAnimation/index.css new file mode 100644 index 0000000..ab7acd3 --- /dev/null +++ b/src/pages/CompanyJobsPage/components/InterviewStatusAnimation/index.css @@ -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%; +} \ No newline at end of file diff --git a/src/pages/CompanyJobsPage/components/InterviewStatusAnimation/index.jsx b/src/pages/CompanyJobsPage/components/InterviewStatusAnimation/index.jsx new file mode 100644 index 0000000..679950d --- /dev/null +++ b/src/pages/CompanyJobsPage/components/InterviewStatusAnimation/index.jsx @@ -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 ( +
+
+
+ ); +}; \ No newline at end of file diff --git a/src/pages/CompanyJobsPage/index.css b/src/pages/CompanyJobsPage/index.css index 602b91a..c2e9418 100644 --- a/src/pages/CompanyJobsPage/index.css +++ b/src/pages/CompanyJobsPage/index.css @@ -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; diff --git a/src/pages/CompanyJobsPage/index.jsx b/src/pages/CompanyJobsPage/index.jsx index cfa0e69..6f5da48 100644 --- a/src/pages/CompanyJobsPage/index.jsx +++ b/src/pages/CompanyJobsPage/index.jsx @@ -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,44 +244,47 @@ const CompanyJobsPage = () => { className="company-jobs-page-interview-list" > {interviews.map((item) => ( -
  • -
    -

    - {item.position} -

    - {item.job?.tags?.length > 0 ? ( -
      - {item.job.tags.map((tag) => ( -
    • - {tag} -
    • - ))} -
    - ) : null} - - {item.job?.salary || "面议"} - -
    -
    - {item.interviewTime} -
    handleStatusClick(e, item)} - style={{ cursor: 'pointer' }} - > - {item.statusText} +
    +
  • +
    +

    + {item.position} +

    + {item.job?.tags?.length > 0 ? ( +
      + {item.job.tags.map((tag) => ( +
    • + {tag} +
    • + ))} +
    + ) : null} + + {item.job?.salary || "面议"} +
    -
  • - +
    + {item.interviewTime} +
    handleStatusClick(e, item)} + style={{ cursor: 'pointer' }} + > + {item.statusText} +
    +
    + + + ))} @@ -304,14 +292,7 @@ const CompanyJobsPage = () => { )} - {/* 面试状态下拉栏 */} - + ); };