仓库首页×2

This commit is contained in:
谢思 2025-12-17 20:36:31 +08:00
parent db2d0800b0
commit 9b36f9d62e
71 changed files with 1835 additions and 70 deletions

View File

@ -1474,6 +1474,10 @@ a.decoration {
font-weight: 400
}
.mt-5{
margin-top: -5px;
}
.mt-8{
margin-top: -8px;
}
@ -1894,6 +1898,10 @@ a.decoration {
padding-top: 5px !important
}
.pt8 {
padding-top: 8px !important
}
.pt10 {
padding-top: 10px
}
@ -2078,6 +2086,10 @@ a.decoration {
padding-left: 40px
}
.pl45 {
padding-left: 45px
}
.pl50 {
padding-left: 50px
}

View File

@ -1,8 +1,8 @@
@font-face {
font-family: "iconfont"; /* Project id 2340181 */
src: url('iconfont.woff2?t=1765510650736') format('woff2'),
url('iconfont.woff?t=1765510650736') format('woff'),
url('iconfont.ttf?t=1765510650736') format('truetype');
src: url('iconfont.woff2?t=1765938619495') format('woff2'),
url('iconfont.woff?t=1765938619495') format('woff'),
url('iconfont.ttf?t=1765938619495') format('truetype');
}
.iconfont {
@ -13,6 +13,14 @@
-moz-osx-font-smoothing: grayscale;
}
.icon-svg_jiantou1:before {
content: "\e9c3";
}
.icon-zuojiantou1:before {
content: "\e9c4";
}
.icon-jiantou4:before {
content: "\e9c2";
}

File diff suppressed because one or more lines are too long

View File

@ -5,6 +5,20 @@
"css_prefix_text": "icon-",
"description": "",
"glyphs": [
{
"icon_id": "46370299",
"name": "svg_箭头1",
"font_class": "svg_jiantou1",
"unicode": "e9c3",
"unicode_decimal": 59843
},
{
"icon_id": "46370300",
"name": "左箭头",
"font_class": "zuojiantou1",
"unicode": "e9c4",
"unicode_decimal": 59844
},
{
"icon_id": "46329189",
"name": "箭头",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -151,12 +151,18 @@ body {
width: 1600px;
margin: 0 auto;
}
.opacity7 {
opacity: 0.7;
.opacity9 {
opacity: 0.9;
}
.opacity8 {
opacity: 0.8;
}
.opacity7 {
opacity: 0.7;
}
.opacity6 {
opacity: 0.6;
}
.opacity4 {
opacity: 0.4;
}

View File

@ -510,20 +510,6 @@ class App extends Component {
{/* 项目标签列表页 */}
<Route path="/explore/topic/:id/:name" component={Topic} mygetHelmetapi={mygetHelmetapi} />
<Route exact path="/explore/all"
render={
(props) => (
<ProjectIndex {...this.props} {...props} />
)
}
/>
<Route exact path="/explore"
render={
(props) => (
<Store {...this.props} {...props} />
)
}
/>
<Route path={"/:OIdentifier/enterprise"}
render={
(props) => {
@ -603,6 +589,13 @@ class App extends Component {
}
}>
</Route>
<Route exact path="/explore"
render={
(props) => (
<Projects {...this.props} {...props} {...this.state}/>
)
}
/>
<Route
path={"/governance"}
render={

View File

@ -15,7 +15,7 @@ export function getImageUrl(path) {
// https://testbdweb.trustie.net
// const local = 'http://localhost:3000'
path && !path.startsWith('/') && !path.startsWith('http') && (path = '/'.concat(path));
const local = 'https://testforgeplus.trustie.net';
const local = 'http://172.20.32.203:4000';
if (isDev) {
return `${local}${path}`
}

View File

@ -18,12 +18,12 @@ const ProjectNew = Loadable({
loading: Loading,
});
const ProjectIndex = Loadable({
loader: () => import("./Main/Index"),
loader: () => import("./projectHome/projectList"),
loading: Loading,
});
const ProjectHome = Loadable({
loader: () => import("./Main/projecthome/Index"),
loader: () => import("./projectHome/explore"),
loading: Loading,
});
@ -60,7 +60,7 @@ class Index extends Component {
)}
></Route>
<Route
path="/explore/all"
path="/projects"
render={(props) => (
<ProjectIndex {...this.props} {...props} />
)}

View File

@ -52,7 +52,7 @@ function ProjectHomePage(props) {
getCate();
// getList();
getCateTopic();
document.title = '军用开源软件仓库';
document.title = 'JY开源软件仓库';
//
getInitCount();
}, [])
@ -121,7 +121,9 @@ function ProjectHomePage(props) {
params.language_id = topicId.split(",")
params.topic_id = undefined
}
cateID && axios.get(url, { params }).then(result => {
console.log('params', params);
axios.get(url, { params }).then(result => {
if (result && result.data) {
setTotal(result.data.total_count);
setProjectsList(result.data.projects);
@ -152,7 +154,7 @@ function ProjectHomePage(props) {
<div className="banner-content">
<div className="homepageMain banner_main df">
<div className="">
<div className="font-30 color-white banner-title-1">军用开源软件仓库</div>
<div className="font-30 color-white banner-title-1">JY开源软件仓库</div>
<div className="font-16 opacity80 color-white mt5 mb15">汇聚全球顶尖开源力量构建安全协同创新的软件生态赋能军事数字化转型与智能化升级</div>
<FeedBack {...props}/>
</div>

View File

@ -6,7 +6,7 @@ import banner3 from '../../img/home/banner3.webp';
import { Link } from "react-router-dom";
const BANNER_DATA = [
{ key: 1, keyword: '仓库', name: '军用开源软件仓库', title: '军用开源软件仓库', content: '提供软件源码的集中托管与协作、编译构建后的制品统一管理,并支持一键搜索与下载成熟可用的应用程序,为军事软件的全生命周期提供一站式管理与分发服务', img: banner1 },
{ key: 1, keyword: '仓库', name: 'JY开源软件仓库', title: 'JY开源软件仓库', content: '提供软件源码的集中托管与协作、编译构建后的制品统一管理,并支持一键搜索与下载成熟可用的应用程序,为军事软件的全生命周期提供一站式管理与分发服务', img: banner1 },
{ key: 2, keyword: '供应链', name: '供应链监测', title: '供应链监测', content: '实现供应链全流程可视化与智能决策。通过实时数据监控、需求预测与风险预警,优化库存与资源配置,助力精准掌控供应链动态,实现降本增效', img: banner2 },
// { key: 3, keyword: '', name: '', title: '', content: '线', img: banner3 }
]

View File

@ -71,7 +71,7 @@ function Factory(props) {
return (
<div className="home-factory home-module">
<h1 className="module-title">软件工厂专区</h1>
<p className="module-desc">面向军用软件开发的高效项目工程化系统管理与平台支撑</p>
<p className="module-desc">面向JY软件开发的高效项目工程化系统管理与平台支撑</p>
<div className={ `factory-content1 ${isVisible1 ? 'animate-active' : ''}`} ref={content1Ref}>
{
Item1.map((e, index) => {

View File

@ -49,7 +49,7 @@ function Store(props) {
return (
<div className="home-store home-module">
<h1 className="module-title">军用开源软件仓库</h1>
<h1 className="module-title">JY开源软件仓库</h1>
<p className="module-desc">一站式软件资源服务中心</p>
<div className="store-feature">
{

View File

@ -1,8 +1,38 @@
import { Divider } from 'antd';
import React from 'react';
import TerminalAnimation from './terminalAnimation';
import TerminalAnimation from './terminalAnimation2';
import ActionItem from '../../../../../factory/resource/components/ActionItem';
function Banner() {
const lines1 = [
'if(!isVisible)',
' return',
'',
'const interval = ',
'setInterval(() => {',
' setActive(prev => {',
' return prev + 1',
' });',
'}, 6000);',
'',
'return () => {',
' clearInterval',
' (interval);',
'};',
];
const lines2 = [
'const params = {',
' id: id,',
' ...values',
'}',
'',
'addComment(params)',
' if(res){',
' reloadComment();',
' }',
'})',
]
return (
<div className="banner_v2 color-white">
{/* 主要内容区域 */}
@ -19,13 +49,28 @@ function Banner() {
</div>
</div>
</div>
<p className="opacity8 mb40" style={{ marginTop: '-12px' }}>持续汇聚多源需求开放共享可信资源协同创新核心技术聚智赋能软件生态</p>
<p className="font-18 mb40" style={{ marginTop: '-12px' }}>持续汇聚多源需求开放共享可信资源协同创新核心技术聚智赋能软件生态</p>
{/* 中央展示图 */}
<div className="center-image-container" style={{ width: '600px', minHeight: '340px', backgroundColor: 'rgba(228, 229, 231, 0.54)', margin: '0 auto' }}>
<div className="center-image-container width1600">
<ActionItem className="center-1-bk-wrapper" padding="1px" borderRadius="15px">
<div className='center-1-bk'>
<div className='edu-txt-left pl25 pt8'>
<span className='center-1-circle'></span>
<span className='center-1-circle active ml8 mr8'></span>
<span className='center-1-circle'></span>
</div>
<img src={require('../image/img10.png').default}/>
</div>
</ActionItem>
<div className='center-left-bk'>
<TerminalAnimation lines={lines1} width={197} height={280} class_name="center-left-code"/>
</div>
<div className='center-right-bk'>
<TerminalAnimation lines={lines2} width={197} height={186}/>
</div>
</div>
{/* <TerminalAnimation /> */}
{/* */}
</div>
{/* 底部统计数据 */}

View File

@ -53,7 +53,10 @@ const CommunityDynamic = () => {
<p className="opacity8 font-16">
{firstByList1.summary}
</p>
<Link className="blackBut mt12" to={`/news/${firstByList1.id}`}>了解更多</Link>
<Link className="blackBut mt12" to={`/news/${firstByList1.id}`}>
<span>了解更多</span>
<span>了解更多</span>
</Link>
</div>
{/* 新闻列表 */}
@ -61,7 +64,7 @@ const CommunityDynamic = () => {
{list1.slice(1,5).map((item, index) => (
<Fragment key={index}>
<div className="news-item-v2">
<div className='font-20 font-bd task-hide mb6'><Link to={`/news/${firstByList1.id}`}>{item.name}</Link></div>
<Link to={`/news/${firstByList1.id}`}><div className='font-20 font-bd mb10 title-border-to-right task-hide'>{item.name}</div></Link>
<p className='task-hide-2 opacity8' style={{ lineHeight: 'normal' }}>{item.summary}</p>
</div>
{index < 3 && <Divider type="vertical" style={{ height: '60px' }} className="mt20 opacity8" />}
@ -80,7 +83,10 @@ const CommunityDynamic = () => {
<ul>
{list2.slice(0,4).map((item, index) => (
<li key={index} className="activity-item-v2 df">
<span className="font-16"><Link to={`/news/${firstByList1.id}`}>{item.summary}</Link>{item.tag && <span className="hot-tag color-white ml5">{item.tag}</span>}</span>
<span className="font-16">
<Link to={`/news/${firstByList1.id}`} className="title-border-to-right">{item.summary}</Link>
{index === 1 && <span className="hot-tag color-white ml5">HOT</span>}
</span>
{/* <span className="opacity8 font-15">{moment(item.publishTime).format('MM月DD日')}</span> */}
<span className="opacity8 font-15">{item.name}</span>
</li>
@ -97,7 +103,10 @@ const CommunityDynamic = () => {
<ul>
{list3.slice(0,4).map((item, index) => (
<li key={index} className="activity-item-v2 df">
<span className="font-16"><Link to={`/news/${firstByList1.id}`}>{item.name}</Link>{item.tag && <span className="hot-tag color-white ml5">{item.tag}</span>}</span>
<span className="font-16">
<Link to={`/news/${firstByList1.id}`} className="title-border-to-right">{item.name}</Link>
{index === 0 && <span className="hot-tag color-white ml5">NEW</span>}
</span>
<span className="opacity8 font-15">{moment(item.publishTime).format('YYYY-MM-DD')}</span>
</li>
))}

View File

@ -9,24 +9,58 @@ const EcosystemAlliance = () => {
rootMargin: '0px 0px -50px 0px'
});
const partners = [
{ name: '国防科技大学', logo: require('../image/logo1.png') },
{ name: '航天工程大学', logo: require('../image/logo3.png').default },
{ name: '信息工程大学', logo: require('../image/logo4.png').default },
{ name: '海军工程大学', logo: require('../image/logo5.png') },
{ name: '陆军工程大学', logo: require('../image/logo6.png') },
{ name: '中国电子北京中软', logo: require('../image/logo7.png').default },
{ name: '中国电科第十五研究所', logo: require('../image/logo8.png').default },
{ name: '华为', logo: require('../image/logo2.png') },
{ name: '麒麟', logo: require('../image/logo9.png') },
{ name: '飞腾', logo: require('../image/logo10.png') },
{ name: '阿里云', logo: require('../image/logo11.png') },
{ name: '中国电子云', logo: require('../image/logo12.png') },
{ name: '中国移动云', logo: require('../image/logo13.png').default }
];
// const partners = [
// { name: '', logo: require('../image/logo1.png') },
// { name: '', logo: require('../image/logo3.png').default },
// { name: '', logo: require('../image/logo4.png').default },
// { name: '', logo: require('../image/logo5.png') },
// { name: '', logo: require('../image/logo6.png') },
// { name: '', logo: require('../image/logo7.png').default },
// { name: '', logo: require('../image/logo8.png').default },
// { name: '', logo: require('../image/logo2.png') },
// { name: '', logo: require('../image/logo9.png') },
// { name: '', logo: require('../image/logo10.png') },
// { name: '', logo: require('../image/logo11.png') },
// { name: '', logo: require('../image/logo12.png') },
// { name: '', logo: require('../image/logo13.png').default }
// ];
//
const firstRowPartners = partners.slice(0, Math.ceil(partners.length / 2));
const secondRowPartners = partners.slice(Math.ceil(partners.length / 2));
// const firstRowPartners = partners.slice(0, Math.ceil(partners.length / 2));
// const secondRowPartners = partners.slice(Math.ceil(partners.length / 2));
const partners1 = [
{title: "合作高校", children: [
{ name: '国防科技大学', logo: require('../image/logo1.png') },
{ name: '海军工程大学', logo: require('../image/logo5.png').default },
{ name: '南京信息工程大学', logo: require('../image/logo4.png').default },
{ name: '陆军工程大学', logo: require('../image/logo6.png').default },
{ name: '航天工程大学', logo: require('../image/logo3.png').default },
{ name: '信息工程大学', logo: require('../image/logo14.png').default },
]},
{title: "合作企业", children: [
{ name: '中电太极', logo: require('../image/logo7.png').default },
{ name: '中国电科第十五研究所', logo: require('../image/logo8.png').default },
{ name: '华为', logo: require('../image/logo2.png') },
{ name: '阿里云', logo: require('../image/logo11.png') },
{ name: '飞腾', logo: require('../image/logo10.png') },
{ name: '航天706所', logo: require('../image/logo15.png') },
{ name: '麒麟', logo: require('../image/logo9.png') },
{ name: '中国电子云', logo: require('../image/logo12.png') },
{ name: '中国移动云', logo: require('../image/logo13.png').default }
]},
{title: "合作社区", children: [
{ name: 'GitLink', logo: require('../image/logo16.png') },
{ name: '红山开源', logo: require('../image/logo17.png') },
{ name: '麒麟社区', logo: require('../image/logo18.png') },
{ name: '鸿蒙社区', logo: require('../image/logo19.png') },
{ name: '鸥栖社区', logo: require('../image/logo20.png') },
{ name: '木兰开源社区', logo: require('../image/logo21.png').default },
{ name: '魔搭社区', logo: require('../image/logo22.png') },
{ name: '魔乐社区', logo: require('../image/logo25.png') },
{ name: '启智社区', logo: require('../image/logo23.png') },
{ name: '欧拉社区', logo: require('../image/logo24.png') },
]}
]
//
const handleTabChange = (tab) => {
@ -48,19 +82,34 @@ const EcosystemAlliance = () => {
</span>
</div>
<div className='edu-txt-left width1600 mb40'>
<div className='font-24 font-bd mb3'>一站式协作平台</div>
<div className='font-16 opacity8'>5G自组网技术联盟是5G自组网技术学术交流平台非社会团体非实体机构由5G自组网领域单位组成<br />遵循公开公平公正的原则开展5G自组网技术体制与标准研究制定促进成员单位深入交流...</div>
<Button className='mt20 blackBut'>立即试用</Button>
<div className='edu-txt-left width1600 mb100'>
<div className='font-24 font-bd mb3'>生态聚力 智创共赢</div>
<div className='font-16 opacity8'>开放协作与合作伙伴共拓市场蓝海链接前沿技术共建智慧产业新生态赋能合作伙伴<br />共筑可持续发展平台</div>
<Button className='mt20 blackBut'>了解更多</Button>
</div>
<div className='width1600 pt70'>
{partners1.map((i,key)=>{
return <div key={key} className='mb40'>
<div className='edu-txt-left font-24 font-bd mb20'>{i.title}</div>
<div className='partner1-list'>
{i.children.map((partner, index)=>{
return <div key={`${key}-${index}`} className="partner1-item edu-txt-left">
<img src={partner.logo} alt={partner.name} />
</div>
})}
</div>
</div>
})}
</div>
<div className="partners-container width1600 mb100">
{/* <div className="partners-container width1600 mb100">
<div
className="partners-slider slider-row-1 mb20"
>
<div className="slider-content">
{/* 复制两份数据实现无缝循环 */}
{[...firstRowPartners, ...firstRowPartners].map((partner, index) => (
<div key={index} className="partner-item edu-txt-left">
<div className="partner-logo mb15">
@ -74,7 +123,6 @@ const EcosystemAlliance = () => {
<div
className="partners-slider slider-row-2"
>
{/* 复制两份数据实现无缝循环 */}
<div className="slider-content">
{[...secondRowPartners, ...secondRowPartners].map((partner, index) => (
<div key={index} className="partner-item edu-txt-left">
@ -86,7 +134,7 @@ const EcosystemAlliance = () => {
))}
</div>
</div>
</div>
</div> */}
</div>
);
};

View File

@ -0,0 +1,253 @@
import React, { useEffect, useRef, useState } from 'react';
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 = {
'git clone': '#fff700',
'git commit': '#fff700',
'git log': '#fff700',
'git merge': '#fff700',
'git remote': '#fff700',
'git pull': '#d24a6f',
'git push': '#d24a6f',
'git status': '#2977ff',
'git fetch': '#2977ff',
'git add': '#9aff41',
'cd forgeplus': '#9aff41',
'git checkout': '#9aff41'
};
const fontSize = 12;
const lineH = 20;
const startY = 10;
const charGap = 30;
const lineGap = 300;
const lineNumberWidth = 0; //
//
const getCharWidth = (charCount) => charCount * 9.6;
//
const renderColoredText = (text, x, y, availableChars) => {
const elements = [];
let currentX = x;
let charsRendered = 0;
//
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)) {
const charsToRender = Math.min(key.length, availableChars - charsRendered);
if (charsToRender > 0) {
const displayText = key.substring(0, charsToRender);
elements.push(
<text
key={`colored-${currentX}-${charsRendered}`}
x={currentX}
y={y}
fill={keyColor[key]}
fontFamily="'Courier New', monospace"
fontSize={fontSize}
dominantBaseline="middle"
fontWeight="bold"
>
{displayText}
</text>
);
currentX += getCharWidth(displayText.length);
charsRendered += charsToRender;
remainingText = remainingText.substring(charsToRender);
colored = true;
}
break;
}
}
//
if (!colored && remainingText.length > 0) {
const charsToRender = Math.min(1, availableChars - charsRendered);
if (charsToRender > 0) {
const char = remainingText[0];
elements.push(
<text
key={`normal-${currentX}-${charsRendered}`}
x={currentX}
y={y}
fill="#8187B9"
fontFamily="'Courier New', monospace"
fontSize={fontSize}
dominantBaseline="middle"
fontWeight="bold"
>
{char}
</text>
);
currentX += getCharWidth(1);
charsRendered += charsToRender;
remainingText = remainingText.substring(charsToRender);
}
}
if (charsRendered >= availableChars) break;
}
return { elements, currentX, charsRendered };
};
//
const renderTextSegments = (line, charLimit, y, isCurrentLine, lineIndex) => {
let x = lineNumberWidth; //
//
const lineNumberElement = (
<text
key="line-number"
x={lineNumberWidth / 2}
y={y+1}
fill="#ffffff"
fontFamily="'Courier New', monospace"
fontSize={fontSize}
dominantBaseline="middle"
textAnchor="middle"
fontWeight="bold"
>
{lineIndex + 1}.
</text>
);
//
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(
<rect
key="cursor"
x={cursorX + 2}
y={y - fontSize/2 + 2}
width={2}
height={fontSize - 4}
fill="#8187B9"
/>
);
}
return allElements;
};
//
useEffect(() => {
if (!startAnimation) {
setAnimationState({
lineI: 0,
charI: 0,
curOn: true
});
return;
}
let lastCharTime = Date.now();
let lastLineTime = Date.now();
let lastBlinkTime = Date.now();
const animate = () => {
const now = Date.now();
let shouldUpdate = false;
let newState = { ...animationState };
//
if (now - lastBlinkTime > 500) {
newState.curOn = !newState.curOn;
lastBlinkTime = now;
shouldUpdate = true;
}
//
if (newState.lineI === 0 && newState.charI < lines[0].length && now - lastCharTime > charGap) {
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; //
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; //
lastLineTime = now;
shouldUpdate = true;
}
if (shouldUpdate) {
setAnimationState(newState);
}
animationRef.current = requestAnimationFrame(animate);
};
animationRef.current = requestAnimationFrame(animate);
return () => {
if (animationRef.current) {
cancelAnimationFrame(animationRef.current);
}
};
}, [animationState, startAnimation]);
return (
<div className={class_name}>
<svg
width={width}
height={height}
viewBox={`0 0 ${width} ${height}`}
xmlns="http://www.w3.org/2000/svg"
style={{ backgroundColor: 'transparent' }}
>
{/* 渲染已完成的行 */}
{lines.slice(0, animationState.lineI).map((line, index) => (
<g key={index}>
{renderTextSegments(line, line.length, startY + index * lineH, false, index)}
</g>
))}
{/* 渲染当前正在输入的行 */}
{animationState.lineI < lines.length && (
<g key="current-line">
{renderTextSegments(lines[animationState.lineI], animationState.charI, startY + animationState.lineI * lineH, true, animationState.lineI)}
</g>
)}
</svg>
</div>
);
};
export default TerminalAnimation;

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -9,6 +9,10 @@
color: #091221;
font-family: "alibabaReg";
a:not(.blackBut):hover, a:not(.blackBut):focus{
color: #2149d4;
}
.title_v2 {
font-family: 'DouyinSansBold';
font-size: 40px;
@ -27,11 +31,39 @@
border: none;
height: 36px;
line-height: 36px;
overflow: hidden;
-webkit-backdrop-filter: blur(24px);
backdrop-filter: blur(24px);
transition: background-color .4s ease-in-out;
position: relative;
&::before{
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(120deg, rgba(255,255,255,0)0%, rgba(255,255,255,0.5)50%,rgba(255,255,255,0)100%);
transition: left 0.5s ease-in-out;
transition-delay: 0.5s;
}
&.white {
background-color: #ffffff;
color: #091221;
}
span{
display: block;
transition: transform 0.5s;
}
&:hover{
span{
transform: translateY(-36px);
}
&::before{
left: 100%;
}
}
}
.but-to-right {
@ -58,6 +90,39 @@
}
}
// 标题悬停下划线从左到右滑出
.title-border-to-right{
display: inline-block;
max-width: 100%;
position: relative;
&::after{
position: absolute;
bottom: 0;
left: 0;
content: '';
width: 0;
height: 1px;
background-color: #2149d4;
transition: all 0.5s ease;
}
&:hover{
padding-right: 25px;
&+.hot-tag{
display: none;
}
}
&:hover::after{
width: 100%;
}
&:hover::before{
content: "\e9c4";
font-family: 'iconfont';
font-weight: normal;
position: absolute;
right: 0;
}
}
}
.banner_v2 {
@ -149,6 +214,81 @@
font-family: "ziyouwenyihei";
}
}
.center-image-container{
position: relative;
.center-left-bk{
background-image:linear-gradient(91.39deg,rgba(255, 255, 255, 0.04) 0%,rgba(255, 255, 255, 0.05) 30%,rgba(255, 255, 255, 0.15) 100%);
border-radius:15px;
padding: 10px;
position: absolute;
top: 15%;
left: 8%;
}
.center-left-code{
border-radius: 10px;
position: relative;
padding: 20px;
&::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: inherit;
padding: 2px;
background: linear-gradient(90deg, #434C9F 0%, rgba(255, 255, 255, 0) 100%);
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
mask-composite: exclude;
}
}
.center-right-bk{
background-image:linear-gradient(178.97deg,rgba(91, 99, 187, 0.23) 0%,rgba(78, 87, 171, 0.14) 13.39%,rgba(255, 255, 255, 0) 100%);
border-radius:0px 15px 15px 15px;
padding: 10px;
position: absolute;
bottom: 8%;
right: 9.5%;
}
}
.center-1-bk-wrapper{
display: inline-block;
&:before {
animation-delay: 1s;
animation: rotate 8s linear infinite;
background: conic-gradient(
from 180deg at 50% 50%,
#e3ffca 0deg,
#43bfff 45deg,
transparent 90deg,
transparent 180deg,
#e3ffca 180deg,
#43bfff 225deg,
transparent 270deg
);
z-index: 0;
}
}
.center-1-bk{
width:866px;
height:512px;
border-radius:15px;
background-image: url('./image/banner-bk.png');
background-size: 100% 100%;
.center-1-circle{
display: inline-block;
width: 12px;
height: 12px;
border-radius: 50%;
background-color:#ffffff;
&.active{
background-color:#e5caff;
}
}
}
}
.community-dynamic {
@ -509,8 +649,9 @@
.ecosystem-alliance {
background-image: url('./image/bk3.png');
background-size: 100% 100%;
padding: 60px 20px;
background-size: 100% auto;
background-repeat: no-repeat;
padding: 90px 20px 60px 20px;
.tabs_v2 {
display: inline-block;
@ -597,6 +738,23 @@
}
}
}
.partner1-list{
gap: 20px;
display: grid;
grid-template-columns: repeat(5, 1fr);
.partner1-item {
height: 101px;
background-color: #ffffff;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
img{
max-width: 80%;
}
}
}
}
.open-source-collaboration-container {

View File

@ -0,0 +1,296 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
import { Button, Divider, Input, Pagination, Popover, Spin, Tooltip } from "antd";
import { Link } from "react-router-dom";
import Nodata from "../../Nodata";
import { getImageUrl } from "../../../common/UrlTool";
import { TPMIndexHOC } from "../../../modules/tpm/TPMIndexHOC";
import RenderHtml from "../../../components/render-html";
import FeedBack from "../../../forge/Component/feedBack";
import './index.scss';
import ActionItem from "../../../factory/resource/components/ActionItem";
const { Search } = Input;
function ProjectHomePage(props) {
const [cateList, setCateList] = useState(undefined);
const [projectsList, setProjectsList] = useState(undefined);
const [search, setSearch] = useState(undefined);
const [cateID, setCateID] = useState(undefined);
const [isSpin, setIsSpin] = useState(true);
const [monthList, setMonthList] = useState(undefined);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [cateTopics, setCateTopics] = useState(undefined);
const [topicId, setTopicId] = useState(undefined);
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`​文件中` <mirrors>` 标签中添加私有仓库地址:\n\n```xml\n<mirrors>\n <mirror>\n <id>xzgd-repo-mirror</id>\n <mirrorOf>*</mirrorOf>\n <url>http://172.16.6.110:8081/repository/maven-repo/</url>\n </mirror>\n</mirrors>\n```\n\n\n在`settings.xml`​文件中`<profiles>`​标签中添加以下内容:\n\n\n```xml\n<profiles> \n <profile> \n <id>xzgd-maven-mirror-profile</id>\n <repositories>\n <repository>\n <id>xzgd-maven-mirror</id>\n <url>http://172.16.6.110:8081/repository/maven-repo/</url>\n </repository>\n </repositories>\n <pluginRepositories>\n <pluginRepository>\n <id>xzgd-maven-mirror</id>\n <url>http://172.16.6.110:8081/repository/maven-repo/</url> \n </pluginRepository> \n </pluginRepositories> \n </profile> \n</profiles>\n```\n\n在`settings.xml`​文件中`<activeProfiles>`​标签中添加以下内容:\n\n```xml\n<activeProfiles>\n <activeProfile>xzgd-maven-mirror-profile</activeProfile>\n</activeProfiles>\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 topicsLength = topicsByCateId && topicsByCateId.length
const LIMIT = !topicsLength ? 30 : 25;
useEffect(() => {
getCate();
// getList();
getCateTopic();
document.title = 'JY开源软件仓库';
//
getInitCount();
}, [])
useEffect(() => {
setIsSpin(true);
getProject();
}, [cateID, search, page, topicId])
function getInitCount() {
const obj = {
countByGHM: 20000,
countByOther: 0,
countByGHMType: 10
}
axios.get(`/organizations/gh_mirrors/projects.json?page=1&limit=15&sort_by=updated_on&sort_direction=desc`).then(result => {
if (result && result.data) {
obj.countByGHM = result.data.total_count || 0
}
return axios.get(`/projects.json?pinned=d&limit=1`)
}).then(result => {
if (result && result.data) {
obj.countByOther = result.data.total_count - obj.countByGHM
}
}).finally(() => {
// cateTopics && cateTopics[39] && (obj.countByGHMType = cateTopics[39].length)
setCount({
countByGHM: 20000,
countByOther: obj.countByOther,
countByGHMType: 10,
countByMX: 99,
countByRQ: 10
});
})
}
function getCateTopic() {
fetch('/cate_topic.json').then(r => r.json()).then(res => {
setCateTopics(res);
});
}
function getCate() {
const url = `/project_categories/pinned_index.json`;
axios.get(url).then(result => {
if (result && result.data) {
const { project_categories = [] } = result.data;
setCateList(project_categories);
// project_categories[0] && setCateID(project_categories[0].id);
}
}).catch(error => { })
}
function getProject() {
const url = `/projects.json`;
let params = {
pinned: "d",
category_id: cateID,
limit: LIMIT,
search: search,
page: page,
topic_id: topicId,
sort_by: cateID ? undefined : "praises_count",
language_id: undefined
};
if (cateID === 39 && topicId) {
// topicIdlanguage_idmavenpythonnpm
params.language_id = topicId.split(",")
params.topic_id = undefined
}
console.log('params', params);
axios.get(url, { params }).then(result => {
if (result && result.data) {
setTotal(result.data.total_count);
setProjectsList(result.data.projects);
setIsSpin(false);
}
}).catch(error => { })
}
function getList() {
// const url = `/project_rank.json`;
const url = `/projects/banner_recommend.json`
axios.get(url, {
// params: {
// time: 30,
// page: 1,
// limit: 16
// }
}).then(result => {
if (result && result.data) {
setMonthList(result.data.projects);
}
}).catch(error => { })
}
return <div className="homepage-box">
{/* banner区域内容 */}
<div className="width1600 mb40">
<div className="font-60 p_h_title center pt70">开源软件仓库·<span className="p_h_title_text">护航J事数智</span></div>
<div className="font-18 center mb40">汇聚全球顶尖开源力量构建安全协同创新的软件生态赋能J事数字化转型与智能化升级</div>
<div className="df">
<div className="df color-white project_count flex1 FlexAJ">
<div className="project_count_item">
<p><img src={require('../image/icon9.png')} className="mr15 mt5" width={30} />{countByOther}<span className="font-24">+</span></p>
<span className="opacity8 pl45">应用软件</span>
</div>
<Divider type="vertical" />
<div className="project_count_item">
<p><img src={require('../image/icon10.png')} className="mr15 mt5" width={30} />{countByGHMType}<span className="font-24">+</span></p>
<span className="opacity8 pl45">三方组件</span>
</div>
<Divider type="vertical" />
<div className="project_count_item">
<p><img src={require('../image/icon11.png')} className="mr15 mt5" width={30} />{countByGHM}<span className="font-24">+</span></p>
<span className="opacity8 pl45">数据集</span>
</div>
<Divider type="vertical" />
<div className="project_count_item">
<p><img src={require('../image/icon12.png')} className="mr15 mt5" width={30} />{countByMX}<span className="font-24">+</span></p>
<span className="opacity8 pl45">智能模型</span>
</div>
<Divider type="vertical" />
<div className="project_count_item">
<p><img src={require('../image/icon13.png')} className="mr15 mt5" width={30} />{countByRQ}<span className="font-24">+</span></p>
<span className="opacity8 pl45">容器镜像</span>
</div>
</div>
<div className="feedBackBox ml20">
<div className="font-22">反馈需求共建优质体验</div>
<div className="font-15 opacity8 mt-5 mb10">欢迎大家随时通过官方渠道提出宝贵建议</div>
<FeedBack {...props} />
</div>
</div>
</div>
<div className="homepage_content_v3 pt40">
<div className="width1600">
<div className="AlignCenter">
<div className="cate_list_box">
<span className={`font-15 font-bd`}>软件分类</span>
{cateList && !!cateList.length && cateList.map(cate => {
const isActive = cate.id === cateID;
return <span key={cate.id} className={`cate_item font-15 ${isActive ? 'active' : ''}`} onClick={() => { setPage(1); setCateID(cate.id); setTopicId(undefined) }}>{cate.name}</span>
})}
</div>
</div>
<div className="df mt25">
{topicsByCateId && !!topicsByCateId.length && <div className="left_cate2 mr25">
<ul className="topic_ul">
<li className={!topicId ? 'active' : ''} onClick={() => { setPage(1); setTopicId(undefined) }}>
<img src={require(`../../Main/projectHomeNew/v2/img/${!topicId ? 'icon-all-1' : 'icon-all'}.png`)} alt="" width="18px" className="mr10 mb3" />
<span>全部类别</span>
</li>
{topicsByCateId.map((item, index) => {
const uniqueKey = `${cateID}-${index}`;
const isActive = item.id === topicId;
const imageName = `${item.icon}${isActive ? '-1' : ''}.png`;
return <li key={uniqueKey} className={item.id === topicId ? 'active' : ''} onClick={() => { setPage(1); setTopicId(item.id); setTopicDetail(item) }}>
<img src={require(`../../Main/projectHomeNew/v2/img/${imageName}`)} alt="" width="18px" className="mr10 mb3" />
<span>{item.name}</span>
</li>
})}
</ul>
</div>}
<div className="flex1">
{/* 推荐仓库 */}
<div>推荐仓库</div>
<div className="mb20">
<Search
placeholder="输入名称关键字"
size="middle"
onSearch={(value) => { setPage(1); setSearch(value); }}
className="mlat custom-search"
style={{ width: "320px", marginLeft: "auto", height: "32px", marginTop: "8px" }}
allowClear
/>
</div>
<Spin spinning={isSpin}>
{projectsList && !!projectsList.length ? <div className={`df home_project_list ${!topicsLength ? 'sixItemBox' : ''}`}>
{projectsList.map(i => {
const url = i.author ? `/${i.author.login}/${i.identifier}${i.author.login === "gh_mirrors" ? "/about" : "/about"}` : ``
return <div className="home_project">
<div className="df a-i-center" style={{ flex: 1 }}>
{i.lesson_url && <img src={getImageUrl(`${i.lesson_url}`)} alt="" className="author_img" />}
{!i.lesson_url && <img src={require("../image/icon14.png").default} alt="" className="author_img" />}
<div className="flex1">
<Link to={url}><div className="task-hide font-16 color-dark hover-light" style={{ marginTop: '-5px' }} title={i.name}>{i.name}</div></Link>
{/* 项目标签 */}
{i.topics && <div className='proListTopics mt3'>
{/* {i.author && i.author.login === "gh_mirrors" && i.topics && !i.topics.length && <span className='proListTopic mr15 font-13 task-hide'>华中科技大学</span>} */}
{i.topics.slice(0, 2).map(item => <Tooltip title={item.name}><Link to={`/explore/topic/${item.id}/${encodeURIComponent(item.name)}`} className='proListTopic mr15 font-13 task-hide'>{item.name}</Link></Tooltip>)}
</div>}
</div>
</div>
{/* {i.description && <Tooltip title={i.description}>
<div className="task-hide color-424 mt10">
{i.description}
</div>
</Tooltip>} */}
{i.author && i.author.login !== "gh_mirrors" && <a className="download-icon mt10" href={url}><i className="iconfont icon-a-xiazai3 font-12 mr5 color-dark"></i>下载</a>}
<Button className="detail-but-black">查看详情</Button>
</div>
})}
</div> : <Nodata _html="暂无数据" />}
</Spin>
{cateID && <Pagination pageSize={LIMIT} total={total} hideOnSinglePage={true} current={page} onChange={(page) => { setPage(page) }} className='center mt30' />}
</div>
</div>
</div>
{/* 二级分类以及仓库列表(左右布局) */}
<div className="width1600 homepageMain df project_list_box">
{/* 二级分类,即标签列表 */}
{/* 项目列表 */}
<div className="flex1" style={{ position: 'relative' }}>
{/* 三方组件下的提示信息<div dangerouslySetInnerHTML={{__html: topicDetail.intro}}></div>*/}
{cateID === 39 && topicId && topicDetail && topicDetail.intro && <Popover
getPopupContainer={trigger => trigger.parentNode}
content={
<div style={{ overflowY: 'auto', maxHeight: '500px' }}>
<RenderHtml value={topicDetail.intro} />
</div>
}
trigger="click"
placement="bottomLeft"
overlayClassName="tipByCate_Popover"
>
<div className="tipByCate pointer">{`设置${topicDetail.name}包管理器仓库地址,`}<a>查看更多</a></div>
</Popover>}
</div>
</div>
</div>
</div>
}
export default ProjectHomePage

View File

@ -0,0 +1,226 @@
.homepage-box {
font-family: "alibabaReg";
color: #091221;
background-image: url('../image/banner.png');
background-size: 100% auto;
background-repeat: no-repeat;
background-color: #f1f6fd;
padding-bottom: 200px;
.p_h_title {
font-family: "DouyinSansBold";
letter-spacing: 4px;
line-height: normal;
}
.p_h_title_text {
background-image: linear-gradient(313.07deg, #eda62a 0%, #352eff 46.85%, #091221 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.project_count {
padding: 0 80px;
height: 145px;
background-image: url('../image/bk4.png');
background-size: 100% 100%;
.ant-divider-vertical {
height: 52px;
background-color: rgba(255, 255, 255, 0.3);
}
.project_count_item p {
font-size: 30px;
font-family: "YouSheBiaoTiHei";
line-height: normal;
}
}
.feedBackBox {
padding: 17px 30px;
background-image: linear-gradient(145.03deg, #f2e8e9 0%, #f2e8e9 19.38%, #a7b0ff 76.71%, #b3a7ff 100%);
border-radius: 15px;
}
.needApplyBut {
display: inline-block;
width: 83px;
height: 32px;
border: 1px solid #091221;
border-radius: 18px;
text-align: center;
line-height: 32px;
color: #091221;
transition: all 0.3s ease;
&:hover,
&:active,
&:focus {
color: #ffffff;
background-color: #091221;
}
}
.homepage_content_v3 {
background-image: linear-gradient(179.88deg, #ffffff 0%, #F3F7FD 100%);
border-radius: 40px 40px 0 0;
.cate_list_box {
display: flex;
gap: 15px;
flex-wrap: wrap;
}
.cate_item {
cursor: pointer;
padding: 2px 25px;
background-color: #f5f7fb;
border-radius: 16px;
&.active {
font-weight: normal;
font-size: 16px;
color: #ffffff;
background-color: #091221;
}
}
.left_cate2 {
width: 200px;
background-color: #ffffff;
border-radius: 10px;
box-shadow: 0px 0px 6px rgba(92, 102, 193, 0.05);
padding: 25px 10px;
li {
color: #42464e;
font-size: 16px;
padding: 10px 20px;
cursor: pointer;
&.active {
background-color: #f7f9fd;
border-radius: 6px;
font-weight: bold;
}
}
}
.home_project_list {
flex-wrap: wrap;
gap: 15px;
&.sixItemBox {
.home_project {
flex: 0 0 calc(16.6% - 13px);
}
}
.home_project {
padding: 20px 20px 60px 20px;
flex: 0 0 calc(20% - 13px);
background-color:#ffffff;
border-radius:8px;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 0;
background-image: url('../image/bk5.png');
background-size: 100% 100%;
border:1px solid transparent;
position: relative;
box-shadow: 0 0 12px rgba(92, 102, 193, 0.05);
.task-hide-2 {
word-break: break-all;
}
.color-424 {
color: #42464e;
}
.a-i-center {
align-items: center;
}
.author_img {
width: 54px;
height: 54px;
margin-right: 15px;
border-radius: 6px;
}
.download-icon {
color:#8284a4;
position: absolute;
bottom: 10px;
}
.hover-light.color-grey-6,
.hover-light.color-grey-6 a {
color: #666 !important;
}
&:hover {
border-color:#2149d4;
}
.proListTopics {
display: flex;
.proListTopic {
background-color:#f7f9fd;
border-radius: 4px;
max-width: 158px;
padding: 0 10px;
height: 22px;
line-height: 22px;
color: #737a87;
&:first-of-type{
color:#2149d4;
background-color:rgba(33, 73, 212, 0.05);
}
}
}
.detail-but-black{
width: 88%;
color:#ffffff;
background-color:#2149d4;
border: none;
display: none;
position: absolute;
bottom: 10px;
}
&:hover{
.download-icon{
display: none;
}
.detail-but-black{
display: block;
}
.detail-but-black::after{
content: '';
position: absolute;
top: 0;
left: -150%;
width: 100%;
height: 100%;
background: linear-gradient(120deg, rgba(255,255,255,0)0%, rgba(255,255,255,0.5)50%,rgba(255,255,255,0)100%);
animation: flowLight 0.5s ease-in-out;
}
}
}
}
}
}
@keyframes flowLight {
0% {
left: -150%;
}
100% {
left: 100%;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

View File

@ -0,0 +1,262 @@
import React, { Fragment, useEffect, useState } from "react";
import './index.scss'
import { Badge, Collapse, Divider, Input, Pagination, Tooltip, Spin } from "antd";
import axios from "axios";
import { Link } from "react-router-dom";
import { getImageUrl, timeAgo } from "educoder";
import Nodata from "../../Nodata";
const { Panel } = Collapse;
//
function ProjectList() {
const LIMIT = 10;
const [cateList, setCateList] = useState([]);
const [projectsList, setProjectsList] = useState([]);
const [searchValue, setSearchValue] = useState(undefined);
const [search, setSearch] = useState(undefined);
const [cateID, setCateID] = useState(undefined);
const [isSpin, setIsSpin] = useState(true);
const [bannerActiveId, setBannerActiveId] = useState(undefined);
const [bannerProjects, setBannerProjects] = useState([]);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [userList, setUserList] = useState([]);
const [projectsListByHot, setProjectsListByHot] = useState([]);
const [hotTime, setHotTime] = useState(7);
const bannerProjects2 = bannerProjects.slice(4, 7);
console.log('bannerProjects2', bannerProjects2, bannerProjects);
useEffect(() => {
getCate();
getList();
getUserList();
document.title = `开源协作`
}, [])
useEffect(() => {
setIsSpin(true);
getProject();
}, [cateID, search, page])
useEffect(() => {
axios.get(`/project_rank.json`, { params: { time: hotTime } }).then(result => {
if (result && result.data) {
setProjectsListByHot(result.data.projects);
}
}).catch(error => { })
}, [hotTime])
function getCate() {
const url = `/project_categories/pinned_index.json`;
axios.get(url).then(result => {
if (result && result.data) {
setCateList(result.data.project_categories);
}
}).catch(error => { })
}
function getList() {
axios.get(`/projects/banner_recommend.json`).then(result => {
if (result && result.data) {
setBannerProjects(result.data.projects);
if (result.data.projects[0]) {
setBannerActiveId(result.data.projects[1].id)
}
}
}).catch(error => { })
}
function getUserList() {
axios.get(`/user_rank.json`, { params: { time: 7 } }).then(result => {
if (result && result.data) {
setUserList(result.data.users);
}
}).catch(error => { })
}
function getProject() {
const url = `/projects.json`;
let params = {
pinned: "d",
category_id: cateID,
limit: LIMIT,
search: search,
page: page,
sort_by: cateID ? undefined : "praises_count",
language_id: undefined
};
axios.get(url, { params }).then(result => {
if (result && result.data) {
setTotal(result.data.total_count);
setProjectsList(result.data.projects);
setIsSpin(false);
}
}).catch(error => { })
}
const bannerProject = (detail) => {
return <div className="font-12 bannerProject edu-txt-left">
<span className="icon-66">66</span>
<div>{detail.author.name}/{detail.name}</div>
<div className="opacity6">{detail.description}</div>
</div>
}
return <div className="project_home">
{/* 推荐仓库 */}
<div className="center pt80 project_home_banner width1600">
<div className="font-60 p_h_title">开源协作·<span className="p_h_title_text">共建生态</span></div>
<Input.Search placeholder={`输入名称关键字(共${total}个)`} className="search_p_h" onChange={(e)=>{setSearchValue(e.target.value)}} suffix={<span className="search_icon" onClick={()=>{setSearch(searchValue)}}>
<i className="iconfont icon-svg_jiantou1 font-14"></i>
</span>} onSearch={(value)=>{
setSearch(value)
}}/>
<img src={require('../image/icon3.png').default} width={144} className="project_home_banner_img1" />
<img src={require('../image/icon4.png').default} width={78} className="project_home_banner_img2" />
{bannerProjects[0] && <div className="project_home_banner_project1">
<img src={require('../image/icon7.png')} width={78} className="mr5" />
{bannerProject(bannerProjects[0])}
<div className="edu-txt-right mt15">
{bannerProjects[0].author && <img src={getImageUrl(`${bannerProjects[0].author.image_url}`)} alt="" className="author_img" />}
</div>
</div>}
{bannerProjects[1] && <div className="project_home_banner_project2">
{bannerProject(bannerProjects[1])}
{bannerProjects[1].author && <img src={getImageUrl(`${bannerProjects[1].author.image_url}`)} alt="" className="author_img" />}
<img src={require('../image/icon5.png')} width={26} className="ml20" />
</div>}
{bannerProjects[2] && <div className="project_home_banner_project3">
{bannerProject(bannerProjects[2])}
<div className="edu-txt-left">
{bannerProjects[2].author && <img src={getImageUrl(`${bannerProjects[2].author.image_url}`)} alt="" className="author_img" />}
</div>
<img src={require('../image/icon8.png')} width={78} className="ml5 icon8_img" />
</div>}
{bannerProjects[3] && <div className="project_home_banner_project4">
{bannerProject(bannerProjects[3])}
{bannerProjects[3].author && <img src={getImageUrl(`${bannerProjects[3].author.image_url}`)} alt="" className="author_img" />}
<img src={require('../image/icon6.png')} width={26} className="ml20" />
</div>}
</div>
{/* 推荐仓库列表一行三个 */}
{bannerProjects2 && !!bannerProjects2.length && <div className="project_list_top width1600 pt70 mb35">
{bannerProjects2.map((i, index) => {
const url = i.author ? `/${i.author.login}/${i.identifier}${i.author.login === "gh_mirrors" ? "/about" : "/about"}` : ``
const { author = {} } = i;
return <div key={index} className="project_list_top_item">
{i.topics && <div className='proListTopics df mb20'>
{i.topics.map(item => <Tooltip title={item.name}><Link to={`/explore/topic/${item.id}/${encodeURIComponent(item.name)}`} className='proListTopic task-hide'>{item.name}</Link></Tooltip>)}
</div>}
<Link to={url}><div className="task-hide font-22" title={i.name}>{author.name}/{i.name}</div></Link>
{i.description && <Tooltip title={i.description}>
<div className="task-hide font-15 opacity8 mt5">
{i.description}
</div>
</Tooltip>}
{author && <div className="mt25">
{author.image_url && <img src={getImageUrl(`${author.image_url}`)} alt="" className="author_img mr10" />}
{author.name}&nbsp;&nbsp;
{timeAgo(i.updated_on)}更新
{(i.parises_count > 0 || i.forked_count > 0) && <Divider type="vertical" />}
{/* 点赞数 */}
{i.parises_count > 0 ? <span className='mr10'><i className="iconfont icon-dianzan1 mr3 font-12"></i>{i.parises_count}</span> : ""}
{/* fork数 */}
{i.forked_count > 0 ? <span><i className="iconfont icon-yifuke_icon mr3 font-14"></i>{i.forked_count}</span> : ""}
</div>}
</div>
})}
</div>}
{/* 项目列表 */}
<div className="project_list_all_box">
<div className="width1600 mb30">
<div className="cate_list_box">
<span className={`cate_item font-15 font-bd ${cateID ? '' : 'active'}`} onClick={() => {setPage(1); setCateID(undefined) }}>最近更新</span>
{cateList.map(cate => {
const isActive = cate.id === cateID;
return <span key={cate.id} className={`cate_item font-15 ${isActive ? 'active' : ''}`} onClick={() => {setPage(1); setCateID(cate.id) }}>{cate.name}</span>
})}
</div>
</div>
<div className="df width1600">
<div className="project_list_all flex1 mr20">
<div className="project_list_all_title font-18">开源项目</div>
<div className="project_list_all_list">
<Spin spinning={isSpin}>
{projectsList.map(i => {
const { author = {} } = i;
const url = i.author ? `/${i.author.login}/${i.identifier}${i.author.login === "gh_mirrors" ? "/about" : "/about"}` : ``
return <div key={i.id} className="project_list_all_list_item">
<div className="FlexAJ">
<div className="AlignCenter flex1">
{author.image_url && <img src={getImageUrl(`${author.image_url}`)} alt="" className="author_img mr10" />}
<Link to={url} className="task-hide font-22 title-border-to-right" title={i.name}>{author.name}/{i.name}</Link>
</div>
<span className="count_box ml30">
{/* 点赞数 */}
{i.praises_count > 0 ? <span className='mr12'><i className="iconfont icon-dianzan1 mr5 font-14"></i>{i.praises_count}</span> : ""}
{/* fork数 */}
{i.forked_count > 0 ? <span><i className="iconfont icon-yifuke_icon mr5 font-14"></i>fork{i.forked_count}</span> : ""}
</span>
</div>
<div className="task-hide-2 font-15 opacity8 mt5 mb10">
{i.description}
</div>
<div className="opacity8">
{i.language && <span className="mr15">
<Badge color="#f50" />
{i.language.name}
</span>}
{timeAgo(i.last_update_time)}更新
</div>
</div>
})}
{!isSpin && projectsList && !projectsList.length && <div className="mt100"><Nodata _html="暂无数据"/></div>}
</Spin>
</div>
<Pagination pageSize={LIMIT} total={total} hideOnSinglePage={true} current={page} onChange={(page) => { setPage(page) }} className='center mt10' />
</div>
<div className="project_home_right">
{/* 热门开发者 */}
<div className="project_home_right-user mb20">
<div className="font-18 project_home_right-title">
<img src={require('../image/icon1.png')} width={24} className="mr8" />
热门开发者
</div>
{userList.map(user => {
return <div key={user.id} className="project_home_right-user-item font-15 opacity8">
<img src={getImageUrl(`${user.avatar_url}`)} alt="" className="author_img mr10" />
<Link to={`/${user.login}`}>{user.name}</Link>
</div>
})}
</div>
{/* 热门项目 */}
<div className="project_home_right-project project_home_right-user pb30">
<div className="font-18 clearfix project_home_right-title">
<img src={require('../image/icon2.png')} width={24} className="mr8" />
热门项目
<span className="fr cursor font-14">
{[{ key: 7, name: "本周" }, { key: 31, name: "本月" }].map((item, index) => {
return <Fragment>
<span className={`${hotTime === item.key ? 'font-bd' : 'opacity6'}`} onClick={() => setHotTime(item.key)}>{item.name}</span>
{index < 1 && <Divider type="vertical" />}
</Fragment>
})}
</span>
</div>
<Collapse expandIconPosition="right" className="hot_project_Collapse">
{projectsListByHot.map(project => {
return <Panel header={project.name} key={project.id}>
<div>{project.description || '暂无数据'}</div>
</Panel>
})}
</Collapse>
</div>
</div>
</div>
</div>
</div>
}
export default ProjectList;

View File

@ -0,0 +1,433 @@
.project_home {
font-family: "alibabaReg";
color: #091221;
background-color: #f1f6fd;
background-image: url('../image/bk1.png');
background-size: 100% auto;
background-repeat: no-repeat;
a:hover {
color: #2149d4;
}
// 标题悬停下划线从左到右滑出
.title-border-to-right {
display: inline-block;
max-width: 100%;
position: relative;
&::after {
position: absolute;
bottom: 0;
left: 0;
content: '';
width: 0;
height: 1px;
background-color: #2149d4;
transition: all 0.5s ease;
}
&:hover {
padding-right: 30px;
&+.hot-tag {
display: none;
}
}
&:hover::after {
width: 100%;
}
&:hover::before {
content: "\e9c4";
font-family: 'iconfont';
font-weight: normal;
position: absolute;
right: 0px;
font-size: 16px;
top: 5px;
}
}
.author_img {
width: 24px;
height: 24px;
border-radius: 50%;
}
.p_h_title {
font-family: "DouyinSansBold";
letter-spacing: 4px;
}
.p_h_title_text {
background-image: linear-gradient(313.07deg, #27d1ff 0%, #352eff 46.85%, #091221 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.search_p_h {
width: 660px;
height: 52px;
.ant-input {
padding-left: 20px;
border-radius: 26px;
border: none;
color: #091221;
&:focus::placeholder{
opacity: 0.6;
}
&::placeholder {
color: #091221;
}
}
.ant-input-search-icon {
display: none;
}
.search_icon {
width: 32px;
height: 32px;
background-color: #091221;
border-radius: 50%;
color: white;
text-align: center;
line-height: 32px;
}
}
.project_home_banner {
position: relative;
&_img1 {
position: absolute;
top: 5%;
left: 18%;
}
&_img2 {
position: absolute;
top: 45%;
right: 14%;
}
&_project1 {
position: absolute;
top: 43%;
left: 10%;
.bannerProject {
right: 45px;
top: 44px;
}
}
&_project2 {
position: absolute;
bottom: -10%;
left: 21.3%;
.bannerProject {
right: 90px;
top: 0px;
animation-delay: 4s !important;
}
.author_img{
animation-delay: 4s !important;
}
}
&_project3 {
position: absolute;
top: 22%;
right: 22%;
.icon8_img {
margin-top: -20px;
}
.bannerProject {
left: 47px;
top: 0px;
animation-delay: 8s !important;
}
.author_img{
animation-delay: 8s !important;
}
}
&_project4 {
position: absolute;
bottom: -10%;
right: 20.3%;
.bannerProject {
left: 47px;
top: 0px;
animation-delay: 12s !important;
}
.author_img{
animation-delay: 12s !important;
}
}
.author_img {
width: 38px;
height: 38px;
border: 1.5px solid white;
background-color: #F6F6F6;
animation: scalemax 2s forwards;
}
.bannerProject {
position: absolute;
background-color: #ffffff;
border-radius: 15px 6px 15px 15px;
padding: 10px 12px;
width: 238px;
opacity: 0;
animation: slideLeftFadeIn 3s forwards;
.icon-66 {
background-image: linear-gradient(180deg, rgba(33, 73, 212, 0.04) 0%, rgba(33, 73, 212, 0.14) 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
position: absolute;
top: 0px;
left: 10px;
font-family: "DouyinSansBold";
font-size: 22px;
}
}
}
.project_list_top {
display: grid;
gap: 20px;
grid-template-columns: repeat(3, 1fr);
}
.project_list_top_item {
padding: 30px;
background-image: url('../image/pro_item1.png');
background-size: 100% 100%;
overflow: hidden;
&:nth-of-type(3n+1),
&:nth-of-type(3n+1) a {
color: #ffffff;
}
&:nth-of-type(3n+2) {
background-image: url('../image/pro_item2.png');
}
&:nth-of-type(3n+3) {
background-image: url('../image/pro_item3.png');
}
.proListTopics {
gap: 7px;
}
.proListTopic {
height: 24px;
line-height: 24px;
padding: 0 10px;
background-color: rgba(255, 255, 255, 0.4);
border-radius: 4px;
}
.ant-divider-vertical {
width: 1.5px;
height: 0.8em;
background-color: #d8d8d8;
}
}
}
.project_list_all_box {
min-height: 50vh;
padding: 40px 0 100px;
background-image: linear-gradient(179.88deg, #ffffff 0%, rgba(255, 255, 255, 0.62) 16.1%, rgba(255, 255, 255, 0) 100%);
border-radius: 40px 40px 0 0;
.cate_list_box {
display: flex;
gap: 18px;
flex-wrap: wrap;
}
.cate_item {
cursor: pointer;
padding: 2px 25px;
background-color: #f7f9fd;
border-radius: 17px;
&.active {
font-weight: normal;
font-size: 16px;
color: #ffffff;
background-color: #091221;
}
}
}
.project_home_right {
width: 21%;
&-title {
padding: 14px 20px;
background-image: url('../image/bk2.png');
background-size: 100% 100%;
}
&-user {
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0px 0px 10px rgba(35, 44, 121, 0.07);
&-item {
padding: 15px 22px;
&:hover {
background-color: #f7f9fd;
font-weight: bold;
}
&:not(:last-of-type) {
position: relative;
&::after {
content: '';
position: absolute;
bottom: 0;
left: 22px;
right: 22px;
height: 1px;
border-bottom: 1px dashed rgba(130, 132, 164, 0.4);
}
}
}
}
.hot_project_Collapse {
border: none;
padding: 0 20px;
background: none;
.ant-collapse-item {
background-color: white;
border-radius: 6px;
margin-top: 20px;
border: 1px solid rgba(130, 132, 164, 0.18);
transition: all 0.5s;
.ant-collapse-header {
color: #091221;
opacity: 0.8;
font-size: 15px;
}
&-active {
background-image: url('../image/bk3.png');
background-size: 100% 100%;
border: none;
.ant-collapse-header {
font-weight: 700;
opacity: 1;
}
}
}
.ant-collapse-content {
border-top: none;
background: none;
color: #091221;
opacity: 0.7;
.ant-collapse-content-box {
padding-top: 0;
}
}
}
}
.project_list_all {
.project_list_all_title {
padding: 5px 0 40px 30px;
background-image: linear-gradient(135.72deg, #f2e8e9 0%, #b3a7ff 100%);
border-radius: 15px 15px 0px 0px;
}
&_list {
background-color: #ffffff;
border-radius: 15px;
position: relative;
top: -34px;
padding: 30px;
min-height: 800px;
&_item {
.author_img {
width: 30px;
height: 30px;
border-radius: 6px;
}
.count_box span {
padding: 4px 12px;
background-color: #f7f9fd;
border-radius: 12px;
.icon-dianzan1 {
color: #d18733;
}
.icon-yifuke_icon {
color: #5545BD;
}
}
&:not(:last-of-type) {
margin-bottom: 10px;
padding-bottom: 12px;
border-bottom: 1px dashed rgba(130, 132, 164, 0.4);
}
}
}
}
@keyframes scalemax {
0%{
scale: 1;
}
40%{
scale: 1.28;
}
100%{
scale: 1;
}
}
@keyframes slideLeftFadeIn {
0%{
opacity: 0.4;
width: 200px;
}
20%{
width: 238px;
}
50%{
opacity: 1;
}
100%{
opacity: 0;
}
}

View File

@ -98,7 +98,7 @@ function Index(props) {
<ul className="topEditionUl">
{
['《全军软件供应链安全治理指南》正式发布,我院牵头打造首个统一治理平台',
'重磅发布:平台首批“可信军用级”基础软件镜像库上线,护航关键系统开发',
'重磅发布:平台首批“可信JY级”基础软件镜像库上线,护航关键系统开发',
'案例深度解析“雷霆”后勤保障信息系统如何通过平台实现依赖组件100%可信治理'
].map((i,k)=>{
return(

View File

@ -185,7 +185,7 @@ function SecondEdition({setValue}) {
<div className={multipleAnalyse ? "multipleAnalyse activeCode":"multipleAnalyse"} id="multipleAnalyse">
<span className="title">军事数智生态市场</span>
<div className="maContent"></div>
<p className="desc">汇聚国内优秀的可信智能应用构建开放创新的军用软件在线体验与推广平台助力军事智能化成果快速转化和部署</p>
<p className="desc">汇聚国内优秀的可信智能应用构建开放创新的JY软件在线体验与推广平台助力军事智能化成果快速转化和部署</p>
</div>
<div className={"multidimensional"} style={{opacity:multidimensional?"1":"0.3"}}>
<div style={{height:"168px"}}></div>

View File

@ -50,9 +50,9 @@ function detail(props) {
<Link to="/news" className="opacity7">社区动态<i className="iconfont icon-youjiantou font-12 ml5 mr5"></i></Link>
{detail.name}
</div>
<div className="df width1600 pb50" style={{ gap: '20px' }}>
<div className="df width1600" style={{ gap: '20px' }}>
{/* 正文 */}
<div className="news-detail-center flex1">
<div className="news-detail-center flex1 pb100">
<div className="news-detail-content pr30">
<div className="font-22 font-bd">
{detail.name}