diff --git a/src/forge/Main/projecthome/v2/components/terminalAnimation2.jsx b/src/forge/Main/projecthome/v2/components/terminalAnimation2.jsx
index 5f5a740c..54964645 100644
--- a/src/forge/Main/projecthome/v2/components/terminalAnimation2.jsx
+++ b/src/forge/Main/projecthome/v2/components/terminalAnimation2.jsx
@@ -1,12 +1,12 @@
import React, { useEffect, useRef, useState } from 'react';
-const TerminalAnimation = ({startAnimation=true, lines, width, height, class_name}) => {
+const TerminalAnimation = ({ startAnimation = true, lines, width, height, class_name }) => {
const [animationState, setAnimationState] = useState({
lineI: 0,
charI: 0,
curOn: true
});
-
+
const animationRef = useRef(null);
const keyColor = {
@@ -42,12 +42,12 @@ const TerminalAnimation = ({startAnimation=true, lines, width, height, class_nam
// 按优先级检查关键字
const sortedKeys = Object.keys(keyColor).sort((a, b) => b.length - a.length);
-
+
let remainingText = text;
-
+
while (remainingText.length > 0 && charsRendered < availableChars) {
let colored = false;
-
+
// 查找匹配的关键字
for (const key of sortedKeys) {
if (remainingText.startsWith(key)) {
@@ -76,7 +76,7 @@ const TerminalAnimation = ({startAnimation=true, lines, width, height, class_nam
break;
}
}
-
+
// 如果没找到关键字,渲染普通文本
if (!colored && remainingText.length > 0) {
const charsToRender = Math.min(1, availableChars - charsRendered);
@@ -101,75 +101,85 @@ const TerminalAnimation = ({startAnimation=true, lines, width, height, class_nam
remainingText = remainingText.substring(charsToRender);
}
}
-
+
if (charsRendered >= availableChars) break;
}
-
+
return { elements, currentX, charsRendered };
};
// 渲染文本行
-const renderTextSegments = (line, charLimit, y, isCurrentLine, lineIndex) => {
- let x = lineNumberWidth; // 从序号列之后开始
-
- // 渲染行号
- const lineNumberElement = (
-
- {lineIndex + 1}.
-
- );
-
- // 计算可用字符数
- const availableChars = charLimit;
-
- // 渲染命令部分(直接渲染整行,不再分离提示符)
- const { elements: commandElements } = renderColoredText(
- line,
- x,
- y,
- availableChars
- );
-
- const allElements = [...commandElements];
-
- // 如果是当前行且需要光标
- if (isCurrentLine && animationState.curOn) {
- const cursorX = x + getCharWidth(charLimit);
- allElements.push(
-
- );
- }
-
- return allElements;
-};
+ const renderTextSegments = (line, charLimit, y, isCurrentLine, lineIndex) => {
+ let x = lineNumberWidth; // 从序号列之后开始
- // 动画逻辑
- useEffect(() => {
- if (!startAnimation) {
- setAnimationState({
- lineI: 0,
- charI: 0,
- curOn: true
- });
- return;
+ // 渲染行号
+ const lineNumberElement = (
+
+ {lineIndex + 1}.
+
+ );
+
+ // 计算可用字符数
+ const availableChars = charLimit;
+
+ // 渲染命令部分(直接渲染整行,不再分离提示符)
+ const { elements: commandElements } = renderColoredText(
+ line,
+ x,
+ y,
+ availableChars
+ );
+
+ const allElements = [...commandElements];
+
+ // 如果是当前行且需要光标
+ if (isCurrentLine && animationState.curOn) {
+ const cursorX = x + getCharWidth(charLimit);
+ allElements.push(
+
+ );
}
+
+ return allElements;
+ };
+
+ // 重置动画
+ const resetAnimation = () => {
+ setAnimationState({
+ lineI: 0,
+ charI: 0,
+ curOn: true
+ });
+ };
+
+ // 监听 startAnimation 变化
+ useEffect(() => {
+ if (startAnimation) {
+ resetAnimation();
+ }
+ }, [startAnimation]);
+
+ // 动画循环
+ useEffect(() => {
+ if (!startAnimation) return;
+
let lastCharTime = Date.now();
let lastLineTime = Date.now();
let lastBlinkTime = Date.now();
@@ -191,18 +201,22 @@ const renderTextSegments = (line, charLimit, y, isCurrentLine, lineIndex) => {
newState.charI++;
lastCharTime = now;
shouldUpdate = true;
- }
+ }
// 第一行完成后,后续行整行显示
else if (newState.lineI === 0 && newState.charI >= lines[0].length && now - lastLineTime > lineGap) {
newState.lineI++;
- newState.charI = lines[newState.lineI] ? lines[newState.lineI].length : 0; // 整行显示
+ if (newState.lineI < lines.length) {
+ newState.charI = lines[newState.lineI].length;
+ }
lastLineTime = now;
shouldUpdate = true;
- }
+ }
// 后续行之间的间隔
else if (newState.lineI > 0 && newState.lineI < lines.length && now - lastLineTime > lineGap) {
newState.lineI++;
- newState.charI = newState.lineI < lines.length ? lines[newState.lineI].length : 0; // 整行显示
+ if (newState.lineI < lines.length) {
+ newState.charI = lines[newState.lineI].length;
+ }
lastLineTime = now;
shouldUpdate = true;
}
@@ -210,8 +224,11 @@ const renderTextSegments = (line, charLimit, y, isCurrentLine, lineIndex) => {
if (shouldUpdate) {
setAnimationState(newState);
}
-
- animationRef.current = requestAnimationFrame(animate);
+
+ // 如果动画未完成,继续下一帧
+ if (newState.lineI < lines.length && startAnimation) {
+ animationRef.current = requestAnimationFrame(animate);
+ }
};
animationRef.current = requestAnimationFrame(animate);
@@ -221,7 +238,7 @@ const renderTextSegments = (line, charLimit, y, isCurrentLine, lineIndex) => {
cancelAnimationFrame(animationRef.current);
}
};
- }, [animationState, startAnimation]);
+ }, [animationState]); // 包含 animationState 以确保状态更新
return (
@@ -238,7 +255,7 @@ const renderTextSegments = (line, charLimit, y, isCurrentLine, lineIndex) => {
{renderTextSegments(line, line.length, startY + index * lineH, false, index)}
))}
-
+
{/* 渲染当前正在输入的行 */}
{animationState.lineI < lines.length && (
diff --git a/src/forge/Main/projecthome/v2/index.jsx b/src/forge/Main/projecthome/v2/index.jsx
index 4917cffa..afe99f4d 100644
--- a/src/forge/Main/projecthome/v2/index.jsx
+++ b/src/forge/Main/projecthome/v2/index.jsx
@@ -1,4 +1,4 @@
-import React , { useEffect , useState } from 'react';
+import React, { useEffect, useRef, useState } from 'react';
import { TPMIndexHOC } from "../../../../modules/tpm/TPMIndexHOC";
import './index.scss';
import Banner from './components/banner';
@@ -11,21 +11,56 @@ import Forum from './components/forum';
import EcosystemAlliance from './components/ecosystemAlliance';
function Index(props) {
+ const observer = useRef();
+ const [visibleItems, setVisibleItems] = useState({});
- useEffect(()=>{
+ useEffect(() => {
+ // 创建 IntersectionObserver 实例
+ observer.current = new IntersectionObserver((entries) => {
+ entries.forEach((entry) => {
+ const id = entry.target.id;
+ const element = document.getElementById(id);
+ if (element) {
+ if (entry.isIntersecting) {
+ element.classList.add('home_v2_visible');
+ setVisibleItems((prev)=>({...prev, [id]: true}))
+ } else {
+ element.classList.remove('home_v2_visible');
+ setVisibleItems((prev)=>({...prev, [id]: false}))
+ }
+ }
+ });
+ }, {
+ root: null,
+ rootMargin: '0px',
+ threshold: 0.1
+ });
+
+ // 观察所有子组件
+ document.querySelectorAll('.home_v2_child').forEach((el) => {
+ observer.current.observe(el);
+ });
+
+ return () => {
+ // 清理观察器
+ observer.current.disconnect();
+ };
+ }, []);
+
+ useEffect(() => {
document.title = props.mygetHelmetapi && props.mygetHelmetapi.name ? props.mygetHelmetapi.name : '生态创新治理中心';
- },[])
+ }, [])
- return(
+ return (
)
}
diff --git a/src/forge/Main/projecthome/v2/index.scss b/src/forge/Main/projecthome/v2/index.scss
index 5f5f2af8..42f6da54 100644
--- a/src/forge/Main/projecthome/v2/index.scss
+++ b/src/forge/Main/projecthome/v2/index.scss
@@ -86,18 +86,18 @@
}
// 从下边滑入可见区
- .animate-up-box {
- // 初始状态:在下方不可见
- transform: translateY(200px);
- opacity: 0;
- transition: opacity 1s, transform 1s;
+ // .animate-up-box {
+ // // 初始状态:在下方不可见
+ // transform: translateY(200px);
+ // opacity: 0;
+ // transition: opacity 1s, transform 1s;
- // 动效状态:从下方滑入
- &.animate-up {
- transform: translateY(0);
- opacity: 1;
- }
- }
+ // // 动效状态:从下方滑入
+ // &.home_v2_visible {
+ // transform: translateY(0);
+ // opacity: 1;
+ // }
+ // }
// 标题悬停:下划线从左到右滑出
.title-border-to-right {
@@ -392,7 +392,14 @@
.activity-section-Carousel{
width: 400px;
border-radius: 10px;
+ max-height: 211px;
+ overflow: hidden;
+ .slick-track{
+ display: flex;
+ align-items: flex-end;
+ }
img{
+ object-fit: cover;
max-width: 100%;
}
}
@@ -411,9 +418,9 @@
background-color: #df2659;
border-radius: 5px;
font-size: 0.8rem;
- padding: 4px 5px;
- position: relative;
- top: -2px;
+ padding: 0px 5px;
+ height: 18px;
+ line-height: 18px;
}
}
@@ -736,7 +743,7 @@
/* ForumExchange.scss */
.forum-exchange {
- padding: 60px 20px 80px;
+ padding: 60px 20px 50px;
background-image: url('./image/bk2.png');
background-size: 100% 100%;
diff --git a/src/forge/projectHome/explore/index.jsx b/src/forge/projectHome/explore/index.jsx
index 2b74b8eb..68af1ae5 100644
--- a/src/forge/projectHome/explore/index.jsx
+++ b/src/forge/projectHome/explore/index.jsx
@@ -27,27 +27,7 @@ function ProjectHomePage(props) {
const [topicDetail, setTopicDetail] = useState(undefined);
const [count, setCount] = useState({});
const { countByGHM, countByOther, countByGHMType, countByMX, countByRQ } = count;
- // const topicsByCateId = cateTopics && cateTopics[cateID];
- const topicsByCateId = cateTopics && cateTopics[cateID] || [
- {
- "id": "1,2",
- "name": "Maven",
- "icon": "icon-maven",
- "intro": "配置使用本站maven仓库,首先请定位 **settings.xml** 文件,通常位于本地 Maven 安装目录的 **conf/settings.xml** 或用户目录下的 **m2/settings.xml**。\n\n然后,在`settings.xml`文件中` ` 标签中添加私有仓库地址:\n\n```xml\n\n \n xzgd-repo-mirror\n *\n http://172.16.6.110:8081/repository/maven-repo/\n \n\n```\n\n\n在`settings.xml`文件中``标签中添加以下内容:\n\n\n```xml\n \n \n xzgd-maven-mirror-profile\n \n \n xzgd-maven-mirror\n http://172.16.6.110:8081/repository/maven-repo/\n \n \n \n \n xzgd-maven-mirror\n http://172.16.6.110:8081/repository/maven-repo/ \n \n \n \n\n```\n\n在`settings.xml`文件中``标签中添加以下内容:\n\n```xml\n\n xzgd-maven-mirror-profile\n\n```\n"
- },
- {
- "id": "2,4",
- "name": "Python",
- "icon": "icon-python",
- "intro": "**方法一**:通过命令配置\n\n运行以下命令:\n```xml\npip config set global.index-url https://mirrors.aliyun.com/pypi/simple\npip config set install.trusted-host mirrors.aliyun.com\n```\n\n**方法二**:手动修改配置文件\n\n根据操作系统不同,修改 pip 配置文件:\n\n**Windows** 在用户目录下创建或编辑 pip.ini 文件(路径如:C:\\Users\\<用户名>\\pip\\pip.ini),内容如下:\n```xml\n[global]\nindex-url = https://mirrors.aliyun.com/pypi/simple/\n[install]\ntrusted-host = mirrors.aliyun.com\n```\n\n**Linux/Mac** 编辑或创建 ~/.config/pip/pip.conf 文件,内容如下:\n```xml\n[global]\nindex-url = https://mirrors.aliyun.com/pypi/simple\n[install]\ntrusted-host = mirrors.aliyun.com\n```\n\n验证配置,运行以下命令检查是否成功:\n```xml\npip config list\n```"
- },
- {
- "id": "4,5",
- "name": "Npm",
- "icon": "icon-npm",
- "intro": "通过使用npm config set registry命令切换npm的镜像源\n\n使用示例:\n可以在命令行工具中输入以下命令:\n```xml\nnpm config set registry https://registry.npm.taobao.org\n```\n\n切换镜像源后,可以通过以下命令验证是否切换成功:\n```xml\nnpm config get registry\n```\n\n如果输出结果显示镜像源已切换到淘宝的npm镜像源,则表示切换成功。"
- }
- ];
+ const topicsByCateId = cateTopics && cateTopics[cateID];
const topicsLength = topicsByCateId && topicsByCateId.length
const LIMIT = !topicsLength ? 30 : 25;
@@ -105,7 +85,7 @@ function ProjectHomePage(props) {
if (result && result.data) {
const { project_categories = [] } = result.data;
setCateList(project_categories);
- // project_categories[0] && setCateID(project_categories[0].id);
+ project_categories[0] && setCateID(project_categories[0].id);
}
}).catch(error => { })
}
@@ -127,9 +107,8 @@ function ProjectHomePage(props) {
params.language_id = topicId.split(",")
params.topic_id = undefined
}
- console.log('params', params);
- axios.get(url, { params }).then(result => {
+ cateID && axios.get(url, { params }).then(result => {
if (result && result.data) {
setTotal(result.data.total_count);
setProjectsList(result.data.projects);
@@ -241,7 +220,20 @@ function ProjectHomePage(props) {
})}
-
+
+ {topicId && topicDetail && topicDetail.intro &&
trigger.parentNode}
+ content={
+
+
+
+ }
+ trigger="click"
+ placement="bottomLeft"
+ overlayClassName="tipByCate_Popover"
+ >
+ {`设置${topicDetail.name}包管理器仓库地址,`}
查看更多
+ }
- {/* 二级分类以及仓库列表(左右布局) */}
-
- {/* 二级分类,即标签列表 */}
-
- {/* 项目列表 */}
-
- {/* 三方组件下的提示信息
*/}
- {cateID === 39 && topicId && topicDetail && topicDetail.intro &&
trigger.parentNode}
- content={
-
-
-
- }
- trigger="click"
- placement="bottomLeft"
- overlayClassName="tipByCate_Popover"
- >
- {`设置${topicDetail.name}包管理器仓库地址,`}
查看更多
- }
-
-
-