仓库首页×2
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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": "箭头",
|
||||
|
|
|
|||
10
src/App.css
|
|
@ -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;
|
||||
}
|
||||
21
src/App.js
|
|
@ -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={
|
||||
|
|
|
|||
|
|
@ -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}`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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} />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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) => {
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
||||
{/* 底部统计数据 */}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
After Width: | Height: | Size: 112 KiB |
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.4 MiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 8.7 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 8.7 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 8.3 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 12 KiB |
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
// 三方组件,topicId要作为language_id参数进行查询,查询maven、python、npm的语言仓库列表
|
||||
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
|
||||
|
|
@ -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%;
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 2.6 MiB |
|
After Width: | Height: | Size: 336 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 48 KiB |
|
After Width: | Height: | Size: 172 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 917 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 605 B |
|
After Width: | Height: | Size: 46 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 404 KiB |
|
After Width: | Height: | Size: 283 KiB |
|
After Width: | Height: | Size: 316 KiB |
|
|
@ -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}
|
||||
{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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +98,7 @@ function Index(props) {
|
|||
<ul className="topEditionUl">
|
||||
{
|
||||
['《全军软件供应链安全治理指南》正式发布,我院牵头打造首个统一治理平台',
|
||||
'重磅发布:平台首批“可信军用级”基础软件镜像库上线,护航关键系统开发',
|
||||
'重磅发布:平台首批“可信JY级”基础软件镜像库上线,护航关键系统开发',
|
||||
'案例深度解析:“雷霆”后勤保障信息系统如何通过平台实现依赖组件100%可信治理'
|
||||
].map((i,k)=>{
|
||||
return(
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||