diff --git a/public/css/gitlink.min.css b/public/css/gitlink.min.css index 2fbfc352f..3a71bc995 100644 --- a/public/css/gitlink.min.css +++ b/public/css/gitlink.min.css @@ -1457,6 +1457,10 @@ a.edu-txt-w80, font-size: 36px !important } +.font-38 { + font-size: 38px !important +} + .font-40 { font-size: 40px !important } diff --git a/src/forge/Information/Component/publicBanner.jsx b/src/forge/Information/Component/publicBanner.jsx index 25bc003e2..2a846868d 100644 --- a/src/forge/Information/Component/publicBanner.jsx +++ b/src/forge/Information/Component/publicBanner.jsx @@ -13,15 +13,18 @@ const { Search } = Input; function PublicBanner(props) { const { deptId } = props.match.params; const { pathname } = props.history.location; - const { data: { sectionHomepageShow, sectionHomepageTitle, sectionProjectShow, sectionDataSetShow, sectionDataSetTitle, sectionProjectTitle, sectionResourceShow, sectionResourceTitle, sectionCmsShow, sectionCmsTitle, sectionMemberShow, sectionPointsShow, sectionMemberTitle, sectionHelperShow, sectionHelperTitle }, data, adminUrl, temp, showLoginDialog, showNotification, checkIfLogin, id } = props; + const { data: { sectionHomepageShow, sectionHomepageTitle, sectionProjectShow, sectionDataSetShow, sectionDataSetTitle, sectionProjectTitle, sectionResourceShow, sectionResourceTitle, sectionCmsShow, sectionCmsTitle, sectionMemberShow, sectionPointsShow, sectionMemberTitle, sectionHelperShow, sectionHelperTitle }, data, adminUrl, temp: defaultTemp, showLoginDialog, showNotification, checkIfLogin, id } = props; const isNSCC = deptId === "NSCC"; const isUOS = deptId === "uos"; + const isCCF = deptId === "CCF-ODC"; const [memberStatus, setMemberStatus] = useState(memberStatusEnum.notMember); const [applyVisible, setApplyVisible] = useState(false); const [ searchShow ,setSearchShow ] = useState(false); const [ searchValue ,setSearchValue ] = useState(null); const searchRef = useRef(); + const temp = isCCF ? "ccf" : defaultTemp + const showMenu = useMemo(() => { return Boolean(sectionHomepageShow | sectionProjectShow | sectionDataSetShow | sectionResourceShow | sectionCmsShow | sectionMemberShow | sectionHelperShow | adminUrl) }, [sectionHomepageShow, sectionProjectShow, sectionDataSetShow, sectionResourceShow, sectionCmsShow, sectionMemberShow, sectionHelperShow, adminUrl]) @@ -100,7 +103,7 @@ function PublicBanner(props) { } return ( -
+
{ data && deptId !== 'xjykyzx' && diff --git a/src/forge/Information/Pages/homepage/ccf/index.jsx b/src/forge/Information/Pages/homepage/ccf/index.jsx new file mode 100644 index 000000000..6ea4e884b --- /dev/null +++ b/src/forge/Information/Pages/homepage/ccf/index.jsx @@ -0,0 +1,90 @@ +import React, { useEffect, useState, useRef } from "react"; +import CCFIntro from "./intro"; +import Registration from "./registration"; +import Vip from "./vip"; +import News from "./news"; +import Project from "./project"; +import Rule from "./rule"; +import "./index.scss"; +import { getNewsAllList } from "../../../api"; + +const CCFHomePage = (props) => { + const {data={}, id, history, role={}} = props || {}; + const [sectionList, setSectionList] = useState([]) + + // 用于Intersection Observer的ref数组 + const sectionRefs = { + intro: useRef(null), + registration: useRef(null), + vip: useRef(null), + news: useRef(null), + project: useRef(null), + rule: useRef(null) + }; + + useEffect(()=>{ + id && getNewsAllList(id).then(result => { + if (result) { + const rows = result.data.rows; + setSectionList(rows); + } + }) + }, [id]) + + // Intersection Observer - 统一处理所有模块的入场动画 + useEffect(() => { + const observerOptions = { + root: null, // 使用视口作为根 + rootMargin: '0px', + threshold: 0.15 // 元素15%进入视口时触发 + }; + + const observerCallback = (entries) => { + entries.forEach(entry => { + if (entry.isIntersecting) { + entry.target.classList.add('is-visible'); + entry.target.classList.add('fadeInChar'); + observer.unobserve(entry.target); // 只触发一次 + } + }); + }; + + const observer = new IntersectionObserver(observerCallback, observerOptions); + + // 观察所有模块 + Object.values(sectionRefs).forEach(ref => { + if (ref.current) { + observer.observe(ref.current); + } + }); + + return () => { + observer.disconnect(); + }; + }, []); + + return ( +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ ); +}; + +export default CCFHomePage; diff --git a/src/forge/Information/Pages/homepage/ccf/index.scss b/src/forge/Information/Pages/homepage/ccf/index.scss new file mode 100644 index 000000000..768620c63 --- /dev/null +++ b/src/forge/Information/Pages/homepage/ccf/index.scss @@ -0,0 +1,900 @@ +// CCF 首页样式 - 自适应宽度,内容区1200px,使用Flexbox布局 + +.ccf-home-page { + background: #f7faff; + font-family: "alibabaReg"; + + .subtitle { + color: #434343; + font-size: 16px; + text-align: center; + } + + .main-title { + text-align: center; + font-family: "DouyinSans"; + font-size: 44px; + font-weight: 700; + color: #262626; + white-space: nowrap; + } + + .color-235 { + color: #235dfa; + } + + .color-5f6 { + color: #5f6777; + } + + .font-bd { + font-family: "alibaba"; + font-weight: normal; + } + + .ccf_block_btn { + background: #262626; + border-radius: 12px; + color: #ffffff; + font-size: 15px; + padding: 12px 26px; + cursor: pointer; + transition: all 0.3s ease; + display: inline-flex; + align-items: center; + + &:hover { + background: #3a3a3a; + + .iconfont { + transform: translateX(5px); + } + } + + .iconfont { + transition: transform 0.3s ease; + } + } +} + +.ccf-intro-section { + width: 100%; +} + +// 内容包装器 - 1200px宽,居中 +.ccf-content-wrapper { + padding: 60px 0 20px 0; + width: 1200px; + margin: 0 auto; + box-sizing: border-box; +} + +.ccf-intro-df { + gap: 96px; +} + +.ccf-intro-left { + background-image: url('../image/ccf_bk2.png'); + background-size: 100% auto; + background-repeat: no-repeat; + background-position-y: 40px; +} + +.ccf-calendar-section { + width: 40%; + background: linear-gradient(177.22deg, #062262 3.43%, #0c5bc8 97.74%); + border: 2px solid; + border-color: #ffffff; + border-radius: 20px; + box-shadow: 0px 0px 10px rgba(7, 60, 157, 0.11); + padding: 24px 27px; +} + +.ccf-calendar-content { + border: 1px solid; + border-color: rgba(255, 255, 255, 0.32); + border-radius: 18px; + padding: 21px 25px; + height: 100%; + background-image: url('../image/ccf_bk15.png'); + background-size: 100% 100%; +} + +.ccf-calendar-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 20px; + padding-left: 14px; + color: white; +} + +.header-line { + width: 4px; + height: 40px; + background: linear-gradient(180deg, #c19937 0%, #64d6f8 100%); + border-radius: 10px; +} + +.ccf-add-button { + width: 100px; + height: 36px; + background: linear-gradient(91deg, #235dfa 0%, #34b1ff 100%); + border: 1px rgba(255, 255, 255, 0.45) solid; + border-radius: 12px; + cursor: pointer; + transition: all 0.3s ease; + text-align: center; + line-height: 35px; + font-size: 15px; + + &:hover { + transform: translateY(-1px); + box-shadow: 0px 4px 12px rgba(35, 93, 250, 0.3); + } +} + +.ccf-expert-section { + background-image: url('../image/ccf_bk1.png'); + background-size: 100% 100%; +} + +.ccf-intro-text { + font-family: "Alibaba PuHuiTi", "Microsoft YaHei", sans-serif; + font-size: 15px; + font-weight: 400; + color: #0c2244; + line-height: 35px; + text-align: left; + overflow-wrap: break-word; + max-width: 603px; +} + +.ccf-features-container { + display: flex; + justify-content: flex-start; + gap: 27px; + flex-wrap: wrap; +} + +.ccf-feature-card { + position: relative; + flex: 1; + padding: 8px 0; + background: rgba(255, 255, 255, 0.77); + border-radius: 15px; + box-shadow: 0px 0px 5px rgba(35, 93, 250, 0.04); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + .group { + width: 17px; + height: 17px; + margin-top: 18px; + } + + .element.text { + color: #262626; + text-align: center; + margin-top: 8px; + } +} + +.ccf-activities-list { + display: flex; + flex-direction: column; + gap: 16px; + margin-top: 16px; + height: 285px; // 固定高度,一屏显示3个元素 + overflow-y: auto; // 允许垂直滚动 + scrollbar-width: none; // Firefox隐藏滚动条 + -ms-overflow-style: none; // IE/Edge隐藏滚动条 + + &::-webkit-scrollbar { + display: none; // Chrome/Safari隐藏滚动条 + } +} + +.ccf-activity-item { + border-radius: 12px; + overflow: hidden; + background: linear-gradient(180deg, rgba(255, 255, 255, 0.39) 0%, rgba(255, 255, 255, 0.15) 100%); + display: flex; + min-height: 85px; + align-items: center; + padding: 0 20px; + gap: 34px; + color: #ffffff; + position: relative; + + a, + a:hover { + color: #ffffff; + } + + .ccf-activity-item-top { + position: absolute; + top: 0px; + width: 80%; + height: 2px; + z-index: 537; + background: linear-gradient(116deg, rgba(255, 255, 255, 0.00) 0%, #ffffff 52%, rgba(255, 255, 255, 0.00) 100%); + } + + &::before { + content: ''; + position: absolute; + inset: 0; + padding: 1px; + background: linear-gradient(180deg, rgba(255, 255, 255, 0.13) 0%, rgba(255, 255, 255, 0.08) 100%); + -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); + -webkit-mask-composite: xor; + mask-composite: exclude; + border-radius: inherit; + pointer-events: none; + } +} + +.ccf-registration-section { + background-image: url('../image/ccf_bk12.png'); + background-size: 100% 100%; + padding-bottom: 20px; + + .ccf-registration-header { + margin-bottom: 60px; + } + + // 主体内容区域 - 左右两栏布局 + .ccf-registration-body { + display: flex; + align-items: stretch; + justify-content: space-between; + gap: 40px; + + // ==================== + // 左侧区域 - 活动详情轮播 + // ==================== + .ccf-registration-left { + flex: 1; + position: relative; + overflow: hidden; + } + + // ==================== + // 右侧区域 - 活动列表 + // ==================== + .ccf-registration-right { + flex: 0 0 12%; + overflow-y: auto; + border-right: 1px solid rgba(38, 38, 38, 0.08); + display: flex; + flex-direction: column; + margin: 30px 0; + + .ccf-activity-list-item { + cursor: pointer; + transition: all 0.3s ease; + color: #262626; + padding: 16px 0; + position: relative; + + &:hover { + color: #235dfa; + } + + &.active { + color: #235dfa; + background: linear-gradient(271.54deg, #ffffff 3.14%, rgba(255, 255, 255, 0) 99.51%); + + &::before { + content: ""; + position: absolute; + right: 0; + width: 2px; + height: 18px; + background: linear-gradient(178.25deg, #235dfa 1.94%, #5320ff 97.6%); + border-radius: 2px; + animation: loadingLineMove 4s ease-in-out infinite; + } + } + } + + } + } +} + +.ccf-vip-section { + + .ccf-vip-grid { + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 25px; + margin-top: 10px; + } + + .ccf-vip-card { + background: #ffffff; + border-radius: 16px; + padding: 24px 16px; + display: flex; + flex-direction: column; + align-items: center; + box-shadow: 0px 0px 10px rgba(35, 93, 250, 0.04); + border: 1px solid rgba(35, 93, 250, 0.13); + transition: all 0.3s ease; + + // &:hover { + // transform: translateY(-20px); + // } + } + + .ccf-vip-avatar { + width: 112px; + height: 112px; + border-radius: 20px; + overflow: hidden; + margin-bottom: 5px; + + img { + width: 100%; + height: 100%; + object-fit: cover; + } + } + + .ccf-vip-name { + font-size: 20px; + font-weight: 600; + color: #262626; + margin-bottom: 12px; + text-align: center; + } + + .ccf-vip-tags { + display: flex; + gap: 14px; + flex-wrap: wrap; + justify-content: center; + margin-bottom: 5px; + } + + .ccf-vip-tag { + padding: 2px 12px; + background: rgba(35, 93, 250, 0.03); + border: 1px solid rgba(106, 146, 255, 0.22); + border-radius: 8px; + font-size: 12px; + color: #2c5c95; + white-space: nowrap; + } + + .ccf-vip-search { + height: 120px; + margin-top: 36px; + text-align: center; + background-image: url('../image/ccf_img2.png'); + background-size: auto 100%; + background-repeat: no-repeat; + background-position: center; + + .ant-input-wrapper { + width: 100%; + } + + // 自定义 Search 样式 + .ant-input-search { + border-radius: 14px; + width: 700px; + height: 55px; + + .ant-input { + border: none; + background: #ffffff; + padding: 12px 16px 12px 29px; + font-size: 15px; + + &:focus { + background: #ffffff; + box-shadow: 0 0 0 2px rgba(35, 93, 250, 0.1); + border: none !important; + } + + &::placeholder { + color: #aab1c3; + } + } + + .ant-input-group-addon { + display: none; + } + + .anticon-search { + width: 39px; + height: 39px; + background: #262626; + border-radius: 8px; + color: #ffffff; + line-height: 39px; + position: relative; + + &:hover { + background: #3a3a3a; + } + + svg { + display: none; + } + + &::before { + content: '\e93e'; + font-family: 'iconfont'; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + } + } + } + } + +} + +.ccf-news-section { + background-image: url('../image/ccf_bk13.png'); + background-size: 100% auto; + background-repeat: no-repeat; + + .ccf-content-wrapper { + .subtitle { + margin-bottom: 40px; + } + } + + // 时间线列表容器 + .ccf-timeline-list { + min-height: 300px; + } + + // 时间线项 + .ccf-timeline-item { + display: flex; + align-items: flex-start; + gap: 34px; + margin-bottom: 40px; + padding-bottom: 32px; + + &:last-child { + margin-bottom: 0; + padding-bottom: 0; + } + + &.ccf-timeline-item-active { + .ccf-timeline-date { + background: #073c9d; + border-color: transparent; + color: #ffffff; + } + } + } + + // 连接线容器 + .ccf-timeline-connector { + position: relative; + top: 65px; + left: 115px; + width: 16px; + height: 99px; + display: flex; + flex-direction: column; + align-items: center; + } + + // 顶部圆形 + .ccf-timeline-connector::before { + content: ''; + display: block; + width: 12px; + height: 12px; + border-radius: 50%; + background: #d6e2ff; + position: relative; + z-index: 3; + } + + // 中间连接线(底色 - 始终显示淡蓝色) + .ccf-timeline-connector::after { + content: ''; + display: block; + width: 2px; + height: 70px; + background: #d6e2ff; + position: relative; + z-index: 1; + } + + // 底部箭头三角 + .ccf-timeline-arrow { + position: absolute; + bottom: 5px; + left: 50%; + transform: translateX(-50%) scale(0.8); + display: inline-block; + color: #d6e2ff; + line-height: 1; + } + + // 激活状态的时间线项 + .ccf-timeline-item-active { + + // 顶部圆形 - 立即变蓝 + .ccf-timeline-connector::before { + background: #235dfa; + // box-shadow: 0 0 10px 2px rgba(35, 93, 250, 0.5); + } + + // 连接线底色 - 保持淡蓝色 + .ccf-timeline-connector::after { + background: #d6e2ff; + } + + // 箭头 - 延迟变蓝 + .ccf-timeline-arrow { + animation: flowArrowBlue 4s ease-in-out infinite; + } + + // 蓝色覆盖层 - 使用 clip-path 从上到下扩展 + .ccf-timeline-connector-blue { + display: block; + position: absolute; + left: 50%; + transform: translateX(-50%); + width: 2px; + height: 82px; + background: #235dfa; + clip-path: inset(0 0 100% 0); + animation: flowBlueClip 4s ease-in-out infinite; + z-index: 2; + } + + // 流动光点 - 在蓝色区域前端 + .ccf-timeline-connector-flow { + // display: block; + // position: absolute; + // left: 50%; + // transform: translateX(-50%); + // width: 4px; + // height: 4px; + // border-radius: 50%; + // background: #235dfa; + // box-shadow: 0 0 8px 2px rgba(35, 93, 250, 0.8); + // animation: flowDotMove 3.5s ease-in-out infinite; + // z-index: 4; + } + } + + // 日期标签 + .ccf-timeline-date { + flex: 0 0 156px; + height: 52px; + background: #ffffff; + border: 1px solid rgba(35, 93, 250, 0.1); + border-radius: 13px; + color: #262626; + font-size: 20px; + transition: all 0.3s ease; + text-align: center; + line-height: 52px; + } + + // 右侧内容区域 + .ccf-timeline-content { + flex: 1; + min-width: 0; + } + + // 标题和标签行 + .ccf-timeline-header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 8px; + flex-wrap: wrap; + } + + .ccf-timeline-title { + font-size: 20px; + font-weight: 600; + color: #434343; + } + + // 标签 + .ccf-timeline-tag { + display: inline-block; + padding: 0px 12px; + background: rgba(35, 93, 250, 0.03); + border: 1px solid rgba(106, 146, 255, 0.22); + border-radius: 8px; + font-size: 14px; + color: #2c5c95; + white-space: nowrap; + } + + // 描述文字 + .ccf-timeline-summary { + color: #6b7280; + font-size: 15px; + line-height: 2.3; + } +} + +.ccf-project-section { + .ccf-project-img { + width: 100%; + position: relative; + top: 45px; + } + + .ccf-project-blue { + height: 408px; + background: url('../image/ccf_bk3.png'), linear-gradient(89.38deg, #062262 1.8%, #0c5bc8 98.52%); + background-size: 100% 100%; + border-radius: 20px; + margin-top: 45px; + padding: 44px 41px 40px 61px; + } + + .ccf-project-blue-left { + color: white; + width: 34.7%; + flex-shrink: 0; + margin-right: auto; + } + + .ccf-project-blue-bottom-1 { + background: linear-gradient(180deg,rgba(7, 60, 157, 0.29) 0%,rgba(35, 93, 250, 0.34) 100%); + border-radius: 20px; + padding: 16px 0; + border-radius: 17px; + margin-top: 35px; + } + + .ccf-project-blue-bottom-2 { + padding: 16px 20px; + border: 1px solid rgba(255, 255, 255, 0.29); + border-radius: 17px; + position: relative; + overflow: hidden; + background: url('../image/ccf_bk4.png'); + background-size: 100% 100%; + } + + .ccf-project-blue-bottom-3 { + padding: 10px 54px; + border: 1px solid rgba(255, 255, 255, 0.29); + border-radius: 17px; + position: relative; + + .ccf-project-blue-bottom-3-top { + position: absolute; + top: -1px; + width: 80%; + height: 2px; + z-index: 537; + background: linear-gradient(116deg, rgba(255, 255, 255, 0.00) 0%, #ffffff 52%, rgba(255, 255, 255, 0.00) 100%); + } + } + + .ccf_proType_1, + .ccf_proType_2 { + width: 26.5%; + height: 100%; + background: url('../image/ccf_bk5.png'), white; + background-size: 100% 100%; + border-radius: 20px; + padding: 49px 34px 30px 34px; + + a { + display: inline-block; + width: 125px; + height: 36px; + border: 1px solid; + border-color: #262626; + border-radius: 9px; + color: #262626; + line-height: 36px; + margin-top: 25px; + + &.unClick { + cursor: no-drop; + } + + &:hover:not(.unClick) { + color: #235dfa; + border-color: #235dfa; + } + } + } + + .ccf_proType_2 { + background: url('../image/ccf_bk6.png'), white; + background-size: 100% 100%; + margin-left: 30px; + } +} + +.ccf-rule-section { + background-image: url('../image/ccf_bk14.png'); + background-size: 100% 100%; + padding-bottom: 100px; + + .ccf-rule-cards-container { + position: relative; + width: 100%; + height: 360px; + display: flex; + align-items: center; + justify-content: center; + } + + .ccf-rule-card { + position: absolute; + width:243px; + height:252px; + border-radius: 20px; + cursor: pointer; + transition: all 0.5s cubic-bezier(0.4, 0, 0.2, 1); + transform-style: preserve-3d; + will-change: transform, opacity; + background-size: 100% 100%; + + &:hover { + z-index: 10 !important; + } + } + + .ccf-rule-card-content { + position: relative; + z-index: 2; + display: flex; + flex-direction: column; + height: 100%; + padding: 30px 24px; + } + + .ccf-rule-arrows { + display: flex; + gap: 20px; + justify-content: center; + margin-top: 15px; + } + + .ccf-rule-arrow { + width: 44px; + height: 44px; + border-radius: 50%; + background: #ffffff; + border: 1px solid rgba(35, 93, 250, 0.15); + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: all 0.3s ease; + color: #262626; + + &:hover { + background: #235dfa; + border-color: #235dfa; + color: #ffffff; + transform: scale(1.1); + box-shadow: 0 4px 12px rgba(35, 93, 250, 0.3); + } + + &:first-of-type{ + transform: scaleX(-1); + } + } +} + +// 蓝色覆盖层 clip-path 动画 - 从上到下展开(3.5秒) +@keyframes flowBlueClip { + 0% { + clip-path: inset(0 0 100% 0); + } + + 100% { + clip-path: inset(0 0 0% 0); + } +} + +// 流动光点位置变化 - 从顶部移动到底部(3.5秒) +@keyframes flowDotMove { + 0% { + top: 0px; + opacity: 1; + } + + 100% { + top: 82px; + opacity: 1; + } +} + +// 箭头变蓝动画 - 延迟3.5秒执行 +@keyframes flowArrowBlue { + + 0%, + 94.5% { + color: #d6e2ff; + } + + 95%, + 100% { + color: #235dfa; + } +} + +// 蓝色线条从上往下移动的动画 +@keyframes loadingLineMove { + 0% { + transform: translateY(-100%); + opacity: 0; + } + + 10% { + opacity: 1; + } + + 90% { + opacity: 1; + } + + 100% { + transform: translateY(100%); + opacity: 1; + } +} + +// ============================================ +// 统一模块出场动画 - Intersection Observer方案 +// 适用于所有高度不固定的模块 +// ============================================ + +// 动画初始状态(默认隐藏) +.ccf-home-page > div[data-animate] { + .ccf-content-animate { + opacity: 0; + transform: translateY(40px); + transition: opacity 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) 1s, + transform 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) 1s; + + } + .subtitle { + opacity: 0; + transform: translateY(40px); + transition: opacity 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.5s, + transform 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94) 0.5s; + + } + +} + +// 动画触发状态(进入视口时添加) +.ccf-home-page > div[data-animate].is-visible{ + .ccf-content-animate, .subtitle{ + opacity: 1; + transform: translateY(0); + } +} + +// 可选:为不同模块添加延迟,实现交错动画效果 +// 如果希望所有模块同时动画,可以删除以下延迟设置 +// .ccf-home-page > div[data-animate]:nth-child(1) { transition-delay: 0s; } +// .ccf-home-page > div[data-animate]:nth-child(2) { transition-delay: 0.1s; } +// .ccf-home-page > div[data-animate]:nth-child(3) { transition-delay: 0.2s; } +// .ccf-home-page > div[data-animate]:nth-child(4) { transition-delay: 0.3s; } +// .ccf-home-page > div[data-animate]:nth-child(5) { transition-delay: 0.4s; } +// .ccf-home-page > div[data-animate]:nth-child(6) { transition-delay: 0.5s; } \ No newline at end of file diff --git a/src/forge/Information/Pages/homepage/ccf/intro.jsx b/src/forge/Information/Pages/homepage/ccf/intro.jsx new file mode 100644 index 000000000..d61ff5f35 --- /dev/null +++ b/src/forge/Information/Pages/homepage/ccf/intro.jsx @@ -0,0 +1,266 @@ +import React, { useEffect, useMemo, useState, useRef } from "react"; +import groupIcon1 from '../image/ccf_icon1.png'; +import groupIcon2 from '../image/ccf_icon2.png'; +import groupIcon3 from '../image/ccf_icon3.png'; +import groupIcon4 from '../image/ccf_icon4.png'; +import groupImg1 from '../image/ccf_img1.png'; +import moment from 'moment'; +import { getSubDocList } from "../../../api"; +import Nodata from "../../../../Nodata"; +import { nsccTitle } from "../nscc"; +import { Dropdown, Menu } from "antd"; + +// 功能卡片数据 +const featureCards = [ + { + id: 1, + title: "开源平台建设", + icon: groupIcon1, + }, + { + id: 2, + title: "开源人才培养", + icon: groupIcon2, + }, + { + id: 3, + title: "开源项目孵化", + icon: groupIcon3, + }, + { + id: 4, + title: "开源生态建设", + icon: groupIcon4, + }, +]; + + +// 功能卡片组件 +const FeatureCard = ({ title, icon }) => ( +
+ +
{title}
+
+); + +// 活动列表项组件 +const ActivityItem = ({ id, keywords, name, summary }) => ( +
+
+ + {moment(summary).format("YYYY")}
+ {moment(summary).format("MM/DD")} +
+
+
{name}
+
{keywords}
+
+
+); + +// 主组件 +const CCFIntro = ({ zoneInfo, sectionList, role }) => { + const { firstTitle, introductionContent, key: deptId } = zoneInfo + const [docList, setDocList] = useState([]); + const scrollRef = useRef(null); + const animationRef = useRef(null); + const lastTimeRef = useRef(null); + const isPausedRef = useRef(false); + const animateRef = useRef(null); // 存储 animate 函数引用 + + // 从sectionList中过滤出name为"执委活动日历"的元素id + const executiveCalendarId = useMemo(() => { + const found = sectionList?.find(item => item.name === "执委活动日历"); + return found?.id; + }, [sectionList]); + + useEffect(() => { + executiveCalendarId && getSubDocList(executiveCalendarId, { pageSize: 1000, pageNum: 1, auditStatus: 1 }).then(result => { + if (result && result.data.rows) { + setDocList(result.data.rows); + } + }) + }, [executiveCalendarId]) + + // 活动列表滚动效果:列表长度大于3时才启用 + useEffect(() => { + const scrollContainer = scrollRef.current; + if (!scrollContainer) return; + + // 清理之前的动画帧 + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + } + + // 列表长度<=3或为空时,不启用滚动 + if (!docList || docList.length <= 3) { + scrollContainer.scrollTop = 0; + return; + } + + const scrollSpeed = 0.5; // 每帧滚动像素 + const intervalTime = 32; // 约60fps + const resetDuration = 1000; // 重置过渡时间 + let isResetting = false; + let resetStartTime = null; + let resetStartScrollTop = 0; + + const animate = (timestamp) => { + animateRef.current = animate; // 存储引用供 JSX 使用 + // 鼠标悬停时暂停滚动 + if (isPausedRef.current) { + return; // 暂停时不调用 requestAnimationFrame + } + + // 如果正在执行重置过渡动画 + if (isResetting) { + const elapsed = timestamp - resetStartTime; + if (elapsed >= resetDuration) { + // 过渡完成,重置状态 + scrollContainer.scrollTop = 0; + isResetting = false; + resetStartTime = null; + } else { + // 使用 easeOutQuad 缓动函数 + const progress = elapsed / resetDuration; + const easeOut = 1 - (1 - progress) * (1 - progress); + scrollContainer.scrollTop = resetStartScrollTop * (1 - easeOut); + } + animationRef.current = requestAnimationFrame(animate); + return; + } + + if (!lastTimeRef.current) { + lastTimeRef.current = timestamp; + } + + const elapsed = timestamp - lastTimeRef.current; + + if (elapsed >= intervalTime) { + if (scrollContainer.scrollTop >= scrollContainer.scrollHeight - scrollContainer.clientHeight) { + // 开始重置过渡 + isResetting = true; + resetStartTime = timestamp; + resetStartScrollTop = scrollContainer.scrollHeight - scrollContainer.clientHeight; + lastTimeRef.current = null; // 重置时间戳,避免重置完成后速度异常 + } else { + scrollContainer.scrollTop += scrollSpeed; + } + lastTimeRef.current = timestamp; + } + + animationRef.current = requestAnimationFrame(animate); + }; + + animationRef.current = requestAnimationFrame(animate); + + return () => { + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + } + lastTimeRef.current = null; + }; + }, [docList]); + + + const addNewMenu = ( + + + 富文本编辑器 + + + MD编辑器 + + + ); + + return ( +
+ {/* 专家简介区域 */} +
+ {/* 内容区域 - 1200px宽 */} +
+
+ {nsccTitle(firstTitle)} +
+
+ {introductionContent} +
+
+
+
+ {featureCards.map((card) => ( + + ))} +
+
+ +
+
CCF开源发展技术委员
+
+ CCF开源发展技术委员会是中国计算机学会(CCF)下属专业技术委员会,为国内开源领域权威学术与产业交流平台。汇聚顶尖专家学者、技术领袖与高校力量,推动开源生态建设、人才培养、技术创新与文化普及。 +
+ 以标准化、公益化、生态化为核心,打造产学研协同的开源合作体系,赋能高校、企业与开发者,助力中国开源高质量发展。 +
+
+ {/* 执委日历区域 */} +
+
+ {/* 左侧蓝色面板 */} + {/* 标题 */} +
+
+
+
执委活动日历
+
近期重点活动预告
+
+ {/* 添加事件按钮 */} + {role && role.role !== "None" && + +
+ 添加事件 +
+
+ } +
+ + {/* 活动列表 */} +
{ + isPausedRef.current = true; + if (animationRef.current) { + cancelAnimationFrame(animationRef.current); + } + }} + onMouseLeave={() => { + isPausedRef.current = false; + lastTimeRef.current = null; // 重置时间戳 + if (typeof animateRef.current === 'function') { + animationRef.current = requestAnimationFrame(animateRef.current); + } + }} + > + {docList && docList.length > 0 ? ( + docList.map((activity) => ( + + )) + ) : ( + + )} +
+
+
+
+
+
+
+ ); +}; + +export default CCFIntro; diff --git a/src/forge/Information/Pages/homepage/ccf/news.jsx b/src/forge/Information/Pages/homepage/ccf/news.jsx new file mode 100644 index 000000000..e6e633ecd --- /dev/null +++ b/src/forge/Information/Pages/homepage/ccf/news.jsx @@ -0,0 +1,122 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import { gethomePageDocList } from "../../../api"; +import moment from 'moment'; +import Nodata from "../../../../Nodata"; +import { nsccTitle } from "../nscc"; + +// 时间线项组件 +const TimelineItem = ({ item, isActive }) => { + const { id, name, publishTime, summary, keywords } = item; + + return ( +
+ {/* 连接线 */} +
+ {isActive && } + {isActive && } + +
+ + {/* 左侧日期标签 */} +
+ {moment(publishTime).format('YYYY-MM-DD')} +
+ + {/* 右侧内容 */} +
+ {/* 标题和标签 */} +
+
{name}
+ {keywords && ( +
{keywords}
+ )} +
+ + {/* 描述文字 */} + {summary && ( +
+ {summary} +
+ )} +
+
+ ); +}; + +// 主组件 +const News = ({ id, autoPlay = true }) => { + const [docList, setDocList] = useState([]); + const [activeIndex, setActiveIndex] = useState(0); + const timerRef = useRef(null); + + useEffect(() => { + id && gethomePageDocList(id).then(result => { + if (result && result.data.rows) { + setDocList(result.data.rows); + } + }) + }, [id]) + + // 自动切换 active 元素 + useEffect(() => { + if (!autoPlay || docList.length === 0) { + return; + } + + const intervalCount = docList.length; + + if (timerRef.current) { + clearInterval(timerRef.current); + } + + timerRef.current = setInterval(() => { + setActiveIndex((prev) => { + const next = (prev + 1) % intervalCount; + return next; + }); + }, 4000); + + return () => { + if (timerRef.current) { + clearInterval(timerRef.current); + } + }; + }, [autoPlay, docList.length]); + + return ( +
+ {/* 内容包装器 - 1200px宽,居中 */} +
+ {/* 顶部标题区域 */} +
+ {nsccTitle("最新动态 · 开源前沿", 0.1, "", 6, "color-235")} +
+
+ 实时更新活动资讯、公告与行业开源前沿动态 +
+ +
+ {/* 时间线列表 */} +
+ {docList && docList.length > 0 ? ( + docList.map((item, index) => ( + + )) + ) : ( + + )} +
+ {docList && docList.length > 0 && } +
+
+
+ ); +}; + +export default News; \ No newline at end of file diff --git a/src/forge/Information/Pages/homepage/ccf/project.jsx b/src/forge/Information/Pages/homepage/ccf/project.jsx new file mode 100644 index 000000000..0eeb21622 --- /dev/null +++ b/src/forge/Information/Pages/homepage/ccf/project.jsx @@ -0,0 +1,91 @@ +import React, { useEffect, useMemo, useState } from "react"; +import { getProjectsTypeLists, getZoneStatistics } from "../../../api"; +import icon1 from '../image/ccf_icon5.png'; +import icon2 from '../image/ccf_icon6.png'; +import ccf_img3 from '../image/ccf_img3.png'; +import ccf_img4 from '../image/ccf_img4.png'; +import { Link } from "react-router-dom"; +import { nsccTitle } from "../nscc"; + +function project({ id }) { + const [ statistics, setStatistics ] = useState(undefined); + const [ typeList , setTypeList ] = useState([]); + const {communityUserCount, projectCount} = statistics || {} + + useEffect(()=>{ + id && getZoneStatistics(id).then(result => { + if (result && result.data) { + setStatistics(result.data.data); + } + }); + + id && getProjectsTypeLists(id).then(result=>{ + if(result){ + setTypeList(result.data.rows); + } + }).catch(error=>{}) + }, [id]) + + const typeId1 = useMemo(() => { + if (!typeList || !Array.isArray(typeList)) return null; + const targetSection = typeList.find((item) => item.name === "捐赠开源项目库"); + return targetSection?.id || null; + }, [typeList]); + + const typeId2 = useMemo(() => { + if (!typeList || !Array.isArray(typeList)) return null; + const targetSection = typeList.find((item) => item.name === "开源学习资源库"); + return targetSection?.id || null; + }, [typeList]); + + return
+
+ +
+ {nsccTitle("开源项目 · 共享资源", 0.1, "", 6, "color-235")} +
+
+ 优质开源项目合集 & 免费学习资源,助力开发者快速成长 +
+ +
+
+ + + {communityUserCount}+ + 贡献者 +
联结 CCF 会员,搭建全球开源协同创新实践平台
+
+
+
+
+
+ {typeList.length}+ +
项目分类数
+
+
+ {projectCount}+ +
代码库数
+
+
+
+
+
+
+ +
捐赠开源项目库
+
覆盖AI、云原生、嵌入式等多领域优质开源项目,开放共享
+ {typeId1 ? 立即查看 : 暂未开放} +
+
+ +
开源学习资源库
+
教程、文档、工具、案例合集,一站式开源学习平台
+ {typeId2 ? 立即查看 : 暂未开放} +
+
+
+
+} + +export default project; \ No newline at end of file diff --git a/src/forge/Information/Pages/homepage/ccf/registration.jsx b/src/forge/Information/Pages/homepage/ccf/registration.jsx new file mode 100644 index 000000000..06b4f310a --- /dev/null +++ b/src/forge/Information/Pages/homepage/ccf/registration.jsx @@ -0,0 +1,101 @@ +import React, { useState, useRef, useEffect, useMemo } from "react"; +import Slider from "react-slick"; +import { getDocAndContentList, getSubDocList } from "../../../api"; +import { Base64 } from "js-base64"; +import { nsccTitle } from "../nscc"; + +// 主组件 +const Registration = ({ sectionList, autoPlay = true }) => { + const [activeId, setActiveId] = useState(); + const [docList, setDocList] = useState([]); + const sliderRef = useRef(null); + + // 从 sectionList 中过滤出 name 为"参与开源"的元素的 id + const participationOpenSourceId = useMemo(() => { + if (!sectionList || !Array.isArray(sectionList)) return null; + const targetSection = sectionList.find((item) => item.name === "参与开源"); + return targetSection?.id || null; + }, [sectionList]); + + + useEffect(() => { + participationOpenSourceId && getDocAndContentList(participationOpenSourceId, { pageSize: 4, pageNum: 1, auditStatus: 1 }).then(result => { + if (result && result.data.rows) { + setDocList(result.data.rows); + result.data.rows[0] && setActiveId(result.data.rows[0].id) + } + }) + }, [participationOpenSourceId]) + + // 处理活动切换:同时更新状态和轮播位置 + const handleActivityChange = (activityId) => { + setActiveId(activityId); + if (sliderRef.current) { + const index = docList.findIndex((item) => item.id === activityId); + if (index >= 0) { + sliderRef.current.slickGoTo(index); + } + } + }; + + // react-slick 水平轮播配置(左侧) + const carouselSettings = { + dots: false, + autoplay: autoPlay, + autoplaySpeed: 4000, + speed: 600, + infinite: true, + slidesToShow: 1, + slidesToScroll: 1, + // initialSlide: docList.findIndex((item) => item.id === (docList[0]?.id)), + beforeChange: (current, next) => { + const nextActivity = docList[next % docList.length]; + if (nextActivity) { + setActiveId(nextActivity.id); + } + }, + pauseOnHover: true, + arrows: true, + adaptiveHeight: true, + }; + + return ( +
+ {/* 内容包装器 - 1200px宽,居中 */} +
+ {/* 顶部标题区域 */} +
+
+ {nsccTitle("一键报名 · 参与开源", 0.1, "", 6, "color-235")} +
+
+ 四大品牌核心活动,全维度覆盖开源人才培养、行业交流与生态共建 +
+
+ + {/* 主体内容区域 */} +
+ {/* 左侧区域 - 活动详情轮播 */} +
+ + {docList.map(item => { + return
+ })} +
+
+ + {/* 右侧区域 - 活动列表 */} +
+ {docList.map((activity) => ( +
handleActivityChange(activity.id)} className={`font-bd ccf-activity-list-item ${activity.id === activeId ? "active" : ""}`}> + {activity.name} +
+ ))} +
+
+
+
+ ); +}; + +export default Registration; diff --git a/src/forge/Information/Pages/homepage/ccf/rule.jsx b/src/forge/Information/Pages/homepage/ccf/rule.jsx new file mode 100644 index 000000000..1958b3107 --- /dev/null +++ b/src/forge/Information/Pages/homepage/ccf/rule.jsx @@ -0,0 +1,202 @@ +import React, { useState, useEffect, useCallback, useMemo } from "react"; +import { getSubDocList } from "../../../api"; +import bk1 from '../image/ccf_bk7.png'; +import bk2 from '../image/ccf_bk8.png'; +import bk3 from '../image/ccf_bk9.png'; +import bk4 from '../image/ccf_bk10.png'; +import bk5 from '../image/ccf_bk11.png'; +import icon1 from '../image/ccf_icon7.png'; +import icon2 from '../image/ccf_icon8.png'; +import icon3 from '../image/ccf_icon9.png'; +import icon4 from '../image/ccf_icon10.png'; +import icon5 from '../image/ccf_icon11.png'; +import { nsccTitle } from "../nscc"; + +// 卡片颜色主题配置 +const cardThemes = [ + { bgImage: bk4, icon: icon4, textColor: "#ffffff" }, + { bgImage: bk5, icon: icon5, textColor: "#262626" }, + { bgImage: bk1, icon: icon1, textColor: "#ffffff" }, + { bgImage: bk2, icon: icon2, textColor: "#ffffff" }, + { bgImage: bk3, icon: icon3, textColor: "#262626" }, +]; + +function Rule({ sectionList, history }) { + const [ruleCards, setRuleCards] = useState([]); + const [currentIndex, setCurrentIndex] = useState(0); + const [isAutoPlaying, setIsAutoPlaying] = useState(true); + const autoPlayInterval = 4000; + + // 从 sectionList 中过滤出 name 为"官方规则"的元素的 id + const ruleTypeId = useMemo(() => { + if (!sectionList || !Array.isArray(sectionList)) return null; + const targetSection = sectionList.find((item) => item.name === "官方规则"); + return targetSection?.id || null; + }, [sectionList]); + + useEffect(() => { + ruleTypeId && getSubDocList(ruleTypeId, { pageSize: 100, pageNum: 1, auditStatus: 1 }).then(result => { + if (result && result.data.rows) { + const transformedCards = result.data.rows.map((item, index) => { + const theme = cardThemes[index % cardThemes.length]; + return { + ...item, + ...theme + }; + }); + // .concat(transformedCards) + setRuleCards(transformedCards.concat(transformedCards).concat(transformedCards).concat(transformedCards).concat(transformedCards).concat(transformedCards)); + } + }) + }, [ruleTypeId]) + + // 计算需要显示的卡片列表(循环填充到5张) + const displayCards = useMemo(() => { + const total = ruleCards.length; + if (total === 0) return []; + + const cards = []; + + // 如果卡片数量 >= 5,使用原始卡片数;否则填充到5张 + const targetCount = Math.max(total, 5); + + for (let i = 0; i < targetCount; i++) { + const originalCard = ruleCards[i % total]; + const theme = cardThemes[i % cardThemes.length]; + cards.push({ + ...originalCard, + ...theme, + }); + } + + return cards; + }, [ruleCards]); + + // 获取当前可见的5张卡片(循环窗口) + const getVisibleCards = useCallback((current, cards) => { + const total = cards.length; + if (total === 0) return []; + + const visible = []; + for (let i = -2; i <= 2; i++) { + const index = (current + i + total) % total; + visible.push({ ...cards[index] }); + } + return visible; + }, []); + + const visibleCards = getVisibleCards(currentIndex, displayCards); + + // 切换到下一张 + const nextCard = useCallback(() => { + setCurrentIndex((prev) => (prev + 1) % displayCards.length); + }, [displayCards.length]); + + // 切换到上一张 + const prevCard = useCallback(() => { + setCurrentIndex((prev) => (prev - 1 + displayCards.length) % displayCards.length); + }, [displayCards.length]); + + // 跳转到详情页 + const handleCardClick = useCallback((id) => { + if (id) { + history.push(`/zone/CCF-ODC/newdetail/${id}`) + } + }, []); + + // 自动播放 + useEffect(() => { + if (!isAutoPlaying || displayCards.length <= 5) return; + const interval = setInterval(nextCard, autoPlayInterval); + return () => clearInterval(interval); + }, [isAutoPlaying, nextCard, displayCards.length]); + + // 鼠标悬停时暂停自动播放 + const handleMouseEnter = useCallback(() => { + setIsAutoPlaying(false); + }, []); + + const handleMouseLeave = useCallback(() => { + setIsAutoPlaying(true); + }, []); + + // 获取每张卡片的位置和样式(直接使用 position 参数,0-4 对应左2到右2) + const getCardStyle = (position, bgImage) => { + const rotations = [-35, -20, 0, 20, 35]; + const translatesX = [-510, -230, 0, 230, 510]; + const opacities = [1, 1, 1, 1, 1]; + const translateY = [130, 30, -10, 30, 130]; + + return { + transform: `translateX(${translatesX[position]}px) rotate(${rotations[position]}deg) translateY(${translateY[position]}px)`, + opacity: opacities[position], + zIndex: 5 - Math.abs(position - 2), + transition: "all 0.5s cubic-bezier(0.4, 0, 0.2, 1)", + backgroundImage: bgImage ? `url(${bgImage})` : 'none', + }; + }; + + return ( +
+ {/* 内容包装器 - 1200px宽,居中 */} +
+
+ {nsccTitle("官方规则 · 公开透明", 0.1, "", 6, "color-235")} +
+
+ 全量规则公示,规范运营、公开透明,接受社会监督 +
+
+ {/* 卡片容器 */} +
+ {visibleCards.map((card, position) => { + const isCenter = position === 2; + return ( +
handleCardClick(card.id)} + > +
+ +
{card.name}
+
{card.summary}
+
+
+ ); + })} +
+ + {/* 导航控制 */} +
+
+ + +
+
+
+
+
+ ); +} + +export default Rule; diff --git a/src/forge/Information/Pages/homepage/ccf/vip.jsx b/src/forge/Information/Pages/homepage/ccf/vip.jsx new file mode 100644 index 000000000..a9912104c --- /dev/null +++ b/src/forge/Information/Pages/homepage/ccf/vip.jsx @@ -0,0 +1,102 @@ +import React, { useEffect, useState, useMemo } from "react"; +import { Input } from 'antd'; +import { getGlobal, getVIPLists } from "../../../api"; +import Nodata from "../../../../Nodata"; +import { nsccTitle } from "../nscc"; + +const Search = Input.Search; + +function Ccf_vip({id}) { + const [ vipLists , setVIPLists ] = useState(undefined); + const [ searchValue, setSearchValue ] = useState(''); + + useEffect(()=>{ + if(searchValue){ + getGlobal({ + extraSearchParam: { + supportMemberCategoryLevelSearch: true + }, + keyword: searchValue, + types: ["member"], + zoneId: id + }).then(result => { + if (result && result.data) { + setVIPLists(result.data.rows.map(item=>{ + const {username, imageUrl, memberLevelName, memberTypeName} = item.extendData + return{ + name: username, + imageUrl: imageUrl, + memberLevel: memberLevelName, + typeName: memberTypeName + } + })); + } + }) + return + } + id && getVIPLists(id, {isHomepage: 1, search: searchValue}).then(response=>{ + if(response){ + // 将 typeName 合并到每个 zoneMemberList 元素中,然后聚合到一个数组 + const list = response.data.rows && response.data.rows.reduce((acc, item) => { + const members = (item.zoneMemberList || []).map(member => ({ + ...member, + typeName: item.typeName + })); + return acc.concat(members); + }, []); + setVIPLists(list); + } + }) + }, [id, searchValue]) + + const handleSearch = (value) => { + setSearchValue(value); + }; + + return
+
+
+ {nsccTitle("核心执委 · 专家智库", 0.1, "", 6, "color-235")} +
+
+ 汇聚国内200+开源领域专家、学者与技术领袖,共建开源智慧平台 +
+
+ {/* 搜索框 */} +
+ +
+ + {vipLists && vipLists.length > 0 ? ( +
+ {vipLists.map((member, index) => ( +
+
+ {member.name} +
+
{member.name}
+
+ {member.typeName} + {member.memberLevel} +
+
+ ))} +
+ ) : ( + searchValue ? : + )} + {vipLists && vipLists.length > 0 && } +
+
+
+} + +export default Ccf_vip; \ No newline at end of file diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk1.png b/src/forge/Information/Pages/homepage/image/ccf_bk1.png new file mode 100644 index 000000000..94ec234ab Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk1.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk10.png b/src/forge/Information/Pages/homepage/image/ccf_bk10.png new file mode 100644 index 000000000..fee8b545e Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk10.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk11.png b/src/forge/Information/Pages/homepage/image/ccf_bk11.png new file mode 100644 index 000000000..acf16cf86 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk11.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk12.png b/src/forge/Information/Pages/homepage/image/ccf_bk12.png new file mode 100644 index 000000000..2799fc915 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk12.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk13.png b/src/forge/Information/Pages/homepage/image/ccf_bk13.png new file mode 100644 index 000000000..639c764ff Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk13.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk14.png b/src/forge/Information/Pages/homepage/image/ccf_bk14.png new file mode 100644 index 000000000..27f1c6f05 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk14.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk15.png b/src/forge/Information/Pages/homepage/image/ccf_bk15.png new file mode 100644 index 000000000..f00940b0c Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk15.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk2.png b/src/forge/Information/Pages/homepage/image/ccf_bk2.png new file mode 100644 index 000000000..4a37be059 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk2.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk3.png b/src/forge/Information/Pages/homepage/image/ccf_bk3.png new file mode 100644 index 000000000..15c452a29 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk3.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk4.png b/src/forge/Information/Pages/homepage/image/ccf_bk4.png new file mode 100644 index 000000000..78d3b0b48 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk4.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk5.png b/src/forge/Information/Pages/homepage/image/ccf_bk5.png new file mode 100644 index 000000000..6327e7386 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk5.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk6.png b/src/forge/Information/Pages/homepage/image/ccf_bk6.png new file mode 100644 index 000000000..29734b411 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk6.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk7.png b/src/forge/Information/Pages/homepage/image/ccf_bk7.png new file mode 100644 index 000000000..11b0f7cf7 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk7.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk8.png b/src/forge/Information/Pages/homepage/image/ccf_bk8.png new file mode 100644 index 000000000..f1431c258 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk8.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_bk9.png b/src/forge/Information/Pages/homepage/image/ccf_bk9.png new file mode 100644 index 000000000..df3f38d93 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_bk9.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon1.png b/src/forge/Information/Pages/homepage/image/ccf_icon1.png new file mode 100644 index 000000000..1073aca23 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon1.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon10.png b/src/forge/Information/Pages/homepage/image/ccf_icon10.png new file mode 100644 index 000000000..f4271cd91 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon10.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon11.png b/src/forge/Information/Pages/homepage/image/ccf_icon11.png new file mode 100644 index 000000000..c146fe857 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon11.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon2.png b/src/forge/Information/Pages/homepage/image/ccf_icon2.png new file mode 100644 index 000000000..4ef3fa711 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon2.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon3.png b/src/forge/Information/Pages/homepage/image/ccf_icon3.png new file mode 100644 index 000000000..0b1ec62b5 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon3.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon4.png b/src/forge/Information/Pages/homepage/image/ccf_icon4.png new file mode 100644 index 000000000..9eb6da855 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon4.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon5.png b/src/forge/Information/Pages/homepage/image/ccf_icon5.png new file mode 100644 index 000000000..20c10317f Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon5.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon6.png b/src/forge/Information/Pages/homepage/image/ccf_icon6.png new file mode 100644 index 000000000..fae5839b2 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon6.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon7.png b/src/forge/Information/Pages/homepage/image/ccf_icon7.png new file mode 100644 index 000000000..98880285e Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon7.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon8.png b/src/forge/Information/Pages/homepage/image/ccf_icon8.png new file mode 100644 index 000000000..8ebceb88f Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon8.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_icon9.png b/src/forge/Information/Pages/homepage/image/ccf_icon9.png new file mode 100644 index 000000000..1f86d43bc Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_icon9.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_img1.png b/src/forge/Information/Pages/homepage/image/ccf_img1.png new file mode 100644 index 000000000..d5a338c16 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_img1.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_img2.png b/src/forge/Information/Pages/homepage/image/ccf_img2.png new file mode 100644 index 000000000..7becfab1f Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_img2.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_img3.png b/src/forge/Information/Pages/homepage/image/ccf_img3.png new file mode 100644 index 000000000..27f23efc2 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_img3.png differ diff --git a/src/forge/Information/Pages/homepage/image/ccf_img4.png b/src/forge/Information/Pages/homepage/image/ccf_img4.png new file mode 100644 index 000000000..81f5e7ef1 Binary files /dev/null and b/src/forge/Information/Pages/homepage/image/ccf_img4.png differ diff --git a/src/forge/Information/Pages/homepage/nscc.jsx b/src/forge/Information/Pages/homepage/nscc.jsx index 9644c6aec..fe63d9ddb 100644 --- a/src/forge/Information/Pages/homepage/nscc.jsx +++ b/src/forge/Information/Pages/homepage/nscc.jsx @@ -13,11 +13,11 @@ import { Anchor, Carousel } from 'antd'; import { Base64 } from 'js-base64'; import CountUp from 'react-countup'; // 标题出场效果组件 -export const nsccTitle = (title, delay=0.1, classname="") => { +export const nsccTitle = (title, delay=0.1, classname="", colorStartIndex=0, charClass="") => { if (!title) return null; return
{title.split("").map((char, index) => ( - + = colorStartIndex ? charClass : ''}`} style={{ animationDelay: `${delay + index * 0.08}s` }}> {char} ))} diff --git a/src/forge/Information/Pages/newsCreate.jsx b/src/forge/Information/Pages/newsCreate.jsx index a78100fbd..56a1cbabb 100644 --- a/src/forge/Information/Pages/newsCreate.jsx +++ b/src/forge/Information/Pages/newsCreate.jsx @@ -1,5 +1,5 @@ -import React,{ useState , useEffect } from 'react'; -import { Breadcrumb, Button, Form, Input, message, Select } from 'antd'; +import React,{ useState , useEffect, useMemo } from 'react'; +import { Breadcrumb, Button, Form, Input, Select } from 'antd'; import { getZoneUrl } from 'educoder'; import MdEditor from '../../../modules/tpm/challengesnew/tpm-md-editor'; import RichEditor from '../../Component/RichEditor'; @@ -15,18 +15,37 @@ function NewsCreate(props){ const { getFieldDecorator, validateFields , setFieldsValue, setFields } = props.form; const { deptId, id: newsId } = props.match.params; const pathname = props.location.pathname; - const [type, setType] = useState(new URLSearchParams(props.location.search.substring(1)).get('type')); + const searchParams = new URLSearchParams(props.location.search.substring(1)); + + const [type, setType] = useState(searchParams.get('type')); const [value, setValue] = useState(undefined); const [imageUrl, setImageUrl] = useState(undefined) const [dirList, setDirList] = useState(undefined); const [loading, setLoading] = useState(false); const [isEdit, setIsEdit] = useState(false); const sectionCmsTitle = props.data && props.data.sectionCmsTitle; + + const defaultDirId = searchParams.get('dirId'); + const filedLabel = searchParams.get('formType'); + const dirIdDisabled = defaultDirId && filedLabel; + const layout = { labelCol: { span: 2 }, wrapperCol: { span: 14 }, }; + const labelMap = useMemo(() => { + // 优先使用自定义labelMap(数字key) + if(filedLabel === "ccfActivity"){ + return { + name: '活动名称', + summary: "时间", + keywords: "活动地点" + } + } + return {}; + }, [filedLabel]); + useEffect(()=>{ if((role && role.role === "None") || (current_user && !current_user.login)){ history.push(`/zone/${deptId}`); @@ -37,6 +56,15 @@ function NewsCreate(props){ id && getDircList(); },[id]) + useEffect(()=>{ + // 如果有默认dirId,设置到表单 + if (defaultDirId) { + setTimeout(() => { + setFieldsValue({ dirId: +defaultDirId }); + }, 200); + } + },[defaultDirId]) + useEffect(()=>{ if(pathname){ if(pathname.endsWith("/edit")){ @@ -132,42 +160,42 @@ function NewsCreate(props){
- + {getFieldDecorator("name", { - rules:[{ required:true,message:"请输入文章标题!" }, + rules:[{ required:true,message:`请输入${labelMap.name || "文章标题"}!` }, {type: 'string', max: 200, message: "最大长度200"}, {pattern: /^[^<>[\]/\\]+$/, message: "不能输入特殊字符:< > [ ] / \\"}] })( - + )} - + {getFieldDecorator("summary", { - rules:[{ required:true,message:"请输入概览!" }, + rules:[{ required:true,message:`请输入${labelMap.summary || "概览"}!` }, {type: 'string', max: 200, message: "最大长度200"}] })( - + )} - + {getFieldDecorator("dirId", { rules:[{ required:true,message:"请选择文章所属栏目!" }] })( - {dirList && dirList.map(item=>{ return {item.name} })} )} - + {getFieldDecorator("keywords", { rules:[{type: 'string', max: 30, message: "请精简文章标签,最大长度30"}], })( - + )} - + {getFieldDecorator("content",{ rules:[{required:true,message:"请输入内容!"}], })( @@ -181,7 +209,7 @@ function NewsCreate(props){ > )} - + setImageUrl(url) } url={ imageUrl ? imageUrl : undefined} action={ getZoneUrl(`/api/file/common/upload`) } /> diff --git a/src/forge/Information/Pages/projectSource.jsx b/src/forge/Information/Pages/projectSource.jsx index 44fab0e42..c10b57bf2 100644 --- a/src/forge/Information/Pages/projectSource.jsx +++ b/src/forge/Information/Pages/projectSource.jsx @@ -13,9 +13,13 @@ import AddProjects from '../Component/addProjects'; import { Link } from 'react-router-dom'; const { Search } = Input; -function ProjectSource(props){ +function ProjectSource(props){ const { deptId } = props.match.params; - const [ typeId , setTypeId ] = useState(0); + // 从路由 state 中获取默认项目分类 id(不显示在URL中) + const getDefaultTypeId = () => { + return props.location?.state?.id ? Number(props.location.state.id) : 0; + }; + const [ typeId , setTypeId ] = useState(getDefaultTypeId()); const [ typeList , setTypeList ] = useState(undefined); const [ lists , setLists ] = useState(undefined); const [ page, setPage ] = useState(1); diff --git a/src/forge/Information/img/ccfMenu1.png b/src/forge/Information/img/ccfMenu1.png new file mode 100644 index 000000000..7a940bdb7 Binary files /dev/null and b/src/forge/Information/img/ccfMenu1.png differ diff --git a/src/forge/Information/img/ccfMenu2.png b/src/forge/Information/img/ccfMenu2.png new file mode 100644 index 000000000..9f4bbf16d Binary files /dev/null and b/src/forge/Information/img/ccfMenu2.png differ diff --git a/src/forge/Information/img/ccfMenu3.png b/src/forge/Information/img/ccfMenu3.png new file mode 100644 index 000000000..ed027dbd0 Binary files /dev/null and b/src/forge/Information/img/ccfMenu3.png differ diff --git a/src/forge/Information/img/ccfMenu4.png b/src/forge/Information/img/ccfMenu4.png new file mode 100644 index 000000000..3823c7c43 Binary files /dev/null and b/src/forge/Information/img/ccfMenu4.png differ diff --git a/src/forge/Information/img/ccfMenu6.png b/src/forge/Information/img/ccfMenu6.png new file mode 100644 index 000000000..eeeaa739c Binary files /dev/null and b/src/forge/Information/img/ccfMenu6.png differ diff --git a/src/forge/Information/img/ccfMenu7.png b/src/forge/Information/img/ccfMenu7.png new file mode 100644 index 000000000..66527e76f Binary files /dev/null and b/src/forge/Information/img/ccfMenu7.png differ diff --git a/src/forge/Information/img/ccfMenu8.png b/src/forge/Information/img/ccfMenu8.png new file mode 100644 index 000000000..2bdec6a85 Binary files /dev/null and b/src/forge/Information/img/ccfMenu8.png differ diff --git a/src/forge/Information/img/ccfMenu9.png b/src/forge/Information/img/ccfMenu9.png new file mode 100644 index 000000000..c1ac752e7 Binary files /dev/null and b/src/forge/Information/img/ccfMenu9.png differ diff --git a/src/forge/Information/index.jsx b/src/forge/Information/index.jsx index 2e063c7df..0516a2400 100644 --- a/src/forge/Information/index.jsx +++ b/src/forge/Information/index.jsx @@ -71,7 +71,7 @@ const HeaderPageZone1 = Loadable({ }); const HeaderPageCCF = Loadable({ - loader : () => import("./Pages/headerPagebyCCF"), + loader : () => import("./Pages/homepage/ccf"), loading : Loading, }); @@ -397,7 +397,7 @@ function Index(props){ ( - deptId==="CCF-ODC" ? : + deptId==="CCF-ODC" ? : deptId === "JCC" ? : deptId === "uos" ? : deptId==="xjykyzx" ? : diff --git a/src/forge/Information/index.scss b/src/forge/Information/index.scss index fd9c1e04f..4f007ca7b 100644 --- a/src/forge/Information/index.scss +++ b/src/forge/Information/index.scss @@ -379,6 +379,59 @@ } } } + + &.bannerByCCF{ + height: 560px; + .main_t{ + font-size:86px; + color:#ffffff; + font-family: "sanjikai"; + } + .sub_t{ + font-size: 18px; + } + .bannerMenus{ + backdrop-filter:blur(44px); + height:60px; + + .ant-menu li{ + height: 60px; + line-height: 60px; + + a{ + font-size: 15px; + color:#cdd4f4 !important; + + img{ + width: 25px; + } + } + } + } + .slick-track{ + height: 560px; + } + .slick-dots{ + li{ + width: 10px; + height: 10px; + background: #ffffff43; + border-radius: 12px; + } + li.slick-active{ + width:59px; + button{ + background: #ffffff43; + } + } + li.slick-active::after{ + width:59px; + height:10px; + background:linear-gradient(267.49deg,#c19937 0.57%,#64d6f8 89.68%); + border-radius:10px; + } + } + } } .main_content{ padding: 40px 0px 80px; @@ -2466,6 +2519,7 @@ .fadeInChar { .title-char { + min-width: 10px; display: inline-block; opacity: 0; animation: fadeInCharZone 0.5s ease-out forwards;