This commit is contained in:
caishi 2024-11-06 18:09:27 +08:00
commit dd668f1bb4
22 changed files with 388 additions and 57 deletions

View File

@ -48,6 +48,7 @@
"dotenv": "4.0.0",
"dotenv-expand": "4.2.0",
"echarts": "^4.9.0",
"echarts-gl": "^1.1.2",
"echarts-wordcloud": "^2.0.0",
"editor.md": "^1.5.0",
"express": "^4.18.2",

View File

@ -0,0 +1,229 @@
import React ,{ Fragment, useEffect, useState } from 'react';
import echarts from 'echarts/lib/echarts'
import 'echarts-gl';
import { getmaturityAnalyse } from '../api/project'
import { Icon, Popover } from 'antd';
function Compass({owner,projectsId}) {
const [mainScore, setMainScore] = useState({})
useEffect(()=>{
getmaturityAnalyse({ owner, repository: projectsId }).then(res => {
if (res.data && res.data.main_score && res.data.main_score.score > 0) {
setMainScore(res.data.main_score)
Init(res.data)
}
})
},[])
function Init(data) {
let huan_val = document.getElementById("compass");
let myEcharts = echarts.init(huan_val);
const a = 3;
const n = 3;
const o = false;
const l = o ? "white" : "#333"
, r = o ? "rgba(255,255,255,0.8)" : "#aaa";
let option = {
tooltip: {
textStyle: {
fontWeight: "bolder"
},
formatter: e => "mock" === e.data.validity ? e.name + ": \u5373\u5c06\u4e0a\u7ebf" : e.data.description + ": " + e.data.value[2]
},
xAxis3D: {
name: " ",
type: "category",
data: data.main_score.x_axis,
interval: 2,
axisLine: {
lineStyle: {
width: 1,
color: l
}
},
splitLine: {
show: !0,
interval: a - 1
},
axisLabel: {
interval: a - 1,
textStyle: {
color: r,
padding: [10, 10, 0, 0]
}
},
axisTick: {
interval: a - 1,
length: 1
}
},
yAxis3D: {
name: " ",
type: "category",
data: data.main_score.y_axis,
axisLine: {
lineStyle: {
width: 1,
color: l
}
},
axisTick: {
interval: n - 1,
length: 0
},
splitArea: {
show: !0,
areaStyle: {
color: ["rgba(255,247,207,0.5)", "rgba(255,231,231,0.5)", "rgba(226,226,226,0.5)"]
}
},
axisLabel: {
interval: n - 1,
textStyle: {
color: r,
padding: [10, 0, 0, 0]
}
},
splitLine: {
show: !0,
interval: n - 1
}
},
zAxis3D: {
name: " ",
type: "value",
splitNumber: 4,
axisLine: {
lineStyle: o ? {
width: 1,
opacity: .2,
color: l
} : {
width: .1,
opacity: .5,
color: l
}
},
splitArea: {
show: !0,
areaStyle: {
color: ["#ffffff", "#ffffff", "#ffffff"]
}
},
axisLabel: {
show: !1
},
axisTick: {
show: !1
}
},
grid3D: {
axisLine: {
interval: 1
},
axisPointer: {
lineStyle: {
opacity: .2
},
label: {
show: !1
}
},
splitLine: {
interval: 2
},
viewControl: {
projection: "perspective",
zoomSensitivity: 0,
rotateSensitivity: [1, 0],
distance: 280,
alpha: 20,
beta: 25
},
top: -40,
right: -10,
boxWidth: 150,
boxDepth: 150,
environment: "none",
light: {
main: {
intensity: .8,
alpha: 50
},
ambient: {
intensity: .5
}
}
},
series: [{
type: "bar3D",
data: data.scores,
shading: "realistic",
bevelSize: .1,
bevelSmoothness: 2,
barSize: 13,
label: {
show: !1,
fontSize: 12,
fontWeight: 500,
borderWidth: 1,
color: "#333",
distance: -20,
formatter: function (e) {
for (let t = e.data.description, i = 2, a = Math.ceil(t.length / i), n = "\n", o = 0; o < a; o++) {
let l = o * i
, r = l + i;
n += t.substring(l, r) + "\n"
}
return n
}
},
itemStyle: {
opacity: .95
},
emphasis: {
label: {
show: !1
},
itemStyle: {
color: "#FFB800",
opacity: .7
}
}
}]
};
myEcharts.setOption(option);
}
const content = () => {
return <div>
开源健康成熟度评分评估围绕以下维度对项目展开评估<br/>
稳健性由安全警告开发者数量版本数评分反映<br/>
扩展性由许可证评分fork数评分点赞数评分关注数评分反映<br/>
维护性由未解决 issue 和已解决 issuecommit数评分反映<br/>
<br/>
总体成熟度评分<br/>
80-100: 项目成熟维护良好<br/>
60-80: 项目稳定有待改进<br/>
0-60: 项目成长期需要加强维护<br/>
</div>
}
return(
mainScore.score && mainScore.score > 0 ? <div className='halfs'>
<div className="font-16 color-ooo mb20">
开源健康成熟度评分 ({ mainScore.score && mainScore.score.toFixed(2) })
<Popover content={content()}>
<Icon type="question-circle" theme="filled" className="color-blue ml10 pointer"/>
</Popover>
</div>
<div id="compass" style={{height:"250px"}}></div>
</div> : null
)
}
export default Compass;

View File

@ -141,7 +141,7 @@ function HeaderPageJCC(props){
</div>
{
data.introductionImage &&
<img src={data.introductionImage} alt="" width="600px" height="361px"/>
<img src={data.introductionImage.split(",")[0]} alt="" width="600px" height="361px"/>
}
</div>
}

View File

@ -79,8 +79,8 @@ function HeaderPage(props){
<p className="z_desc task-hide-2" style={{WebkitLineClamp:data.introductionTitle?"4":"7"}} dangerouslySetInnerHTML={{ __html: data.introductionContent }} ></p>
</div>
{
data.introductionImage &&
<img src={data.introductionImage} alt="" width="300px"/>
data.introductionImage &&
<img src={data.introductionImage.split(",")[0]} alt="" width="300px"/>
}
</div>
}

View File

@ -237,7 +237,7 @@ function HeaderPageCCF(props) {
</div>
{
data.introductionImage &&
<img src={data.introductionImage} alt="" width="300px" />
<img src={data.introductionImage.split(",")[0]} alt="" width="300px" />
}
</div>
}

View File

@ -1,6 +1,7 @@
import React , { useEffect, useState } from 'react';
import { getZoneStatistics } from '../../../api';
import '../index.scss';
import { Carousel } from 'antd';
//
// statistics:
@ -28,11 +29,15 @@ function Introduction({data, statistics=true}) {
{firstTitle}
<span className='firstTitle_back font-34'>ABOUT US</span>
</div>
<div>
{introductionImage && <img src={introductionImage} alt="" width="526px" align="right" hspace="35" vspace="10"/>}
{introductionContent && <span dangerouslySetInnerHTML={{ __html: introductionContent }} className='font-16' style={{lineHeight: '40px'}}></span>}
<div className='clearfix'>
{introductionImage && <Carousel className='intro_1_carousel zone_1_carousel' autoplay={true}>
{introductionImage.split(",").map((item, index) => {
return <img key={index} src={item} alt="" className='intro_image'/>;
})}
</Carousel>}
{introductionContent && <span dangerouslySetInnerHTML={{ __html: introductionContent }} className='font-16 intro_1_I' style={{lineHeight: '40px'}}></span>}
</div>
{statistics && <div className='df wrap mt50 between'>
{statistics && <div className='df wrap pt50 between width1200'>
{Object.keys(label).map(item=>{
return <div className='align font-16'>
<span className='font-34 color-blue font-bd'>{data1[item]}</span><br/>

View File

@ -131,8 +131,8 @@ function News({data, subTitle, firstDirIntro, secondDirIntro}) {
{/* 第一个顺序栏目 */}
{firstDir && <div className='firstDir clearfix'>
<p className='font-16 task-hide'>
{firstDir.name}
<Link style={{color: 'white'}} className='fr font-15' to={`/zone/uos/news/${firstDir.id}`}>更多<Icon type="arrow-right" className="ml5"/></Link>
<Link style={{color: 'white'}} to={`/zone/uos/news/${firstDir.id}`} onClick={()=>{window.scrollTo(0,450)}}>{firstDir.name}</Link>
<Link style={{color: 'white'}} className='fr font-15' to={`/zone/uos/news/${firstDir.id}`} onClick={()=>{window.scrollTo(0,450)}}>更多<Icon type="arrow-right" className="ml5"/></Link>
</p>
<div style={{fontFamily:"FangSong", height: 200}} className='font-24 ml85 mr80 flexCenter font-bd'>{firstDirIntro}</div>
{docListByFirstDir[0] && <div className='pt10 pb10 pl20 docByFirstDir task-hide'>
@ -147,7 +147,9 @@ function News({data, subTitle, firstDirIntro, secondDirIntro}) {
<img src={dirpng}/>
</div>
<div>
<p className='font-17 font-bd task-hide'>{secondDir.name}</p>
<p className='font-17 font-bd task-hide'>
<Link to={`/zone/uos/news/${secondDir.id}`} onClick={()=>{window.scrollTo(0,450)}}>{secondDir.name}</Link>
</p>
<p className='color627'>{secondDirIntro}</p>
</div>
</div>
@ -164,9 +166,9 @@ function News({data, subTitle, firstDirIntro, secondDirIntro}) {
</Row>
</div>}
</div>
<div className='df wrap backWhite pt15 pb15 pl10 pr10'>
{dirs && !!dirs.length && <div className='df wrap backWhite pt30 pb15 pl10 pr10'>
{renderItems()}
</div>
</div>}
</div>
</div>
}

View File

@ -1,6 +1,7 @@
import React , { useEffect, useState } from 'react';
import { getPartnerList } from '../../../api';
import '../index.scss';
import Nodata from '../../../../Nodata';
function Partner({data}) {
const {id, key, homepagePartnersTitle} = data || {};
@ -46,6 +47,7 @@ function Partner({data}) {
<div className='partner_1 width1200 pt50 pb60'>
<p className='font-bd font-30 mb10 task-hide center mb50'>{homepagePartnersTitle}</p>
<div>{gridItems}</div>
{list && !list.length && <Nodata _html="暂无数据"/>}
</div>
</div>
}

View File

@ -3,6 +3,43 @@ import '../index.scss';
import { getProjectListByScore, getProjectsTypeLists } from '../../../api';
import { Carousel, Divider, Spin } from 'antd';
import Nodata from '../../../../Nodata';
import Slider from 'react-slick';
export function TypeCarousel({pageSize=4, list=[], typeId, onClick}) {
const setting = {
prevArrow: <img src={require('../image/left.png')} alt=''/>,
nextArrow: <img src={require('../image/right.png')} alt=''/>,
afterChange: (currentSlide)=>{onClick(list[currentSlide*pageSize].id)}
}
const pages = []
for (let i = 0; i < Math.ceil(list.length / pageSize); i++) {
const start = i * pageSize;
const end = start + pageSize;
pages.push(list.slice(start, end));
}
return <Slider {...setting} className='mb60'>
{pages.map((page, index)=>{
return <div key={index}>
<div className='flexCenter align'>
{page.map((item, i) => {
const order = index*pageSize+i
return <div key={i} className={`proTypeBox flexCenter ml15 mr15 pl10 pr10 pointer ${typeId === item.id && "active"}`} onClick={() => { onClick(item.id) }}>
{/* 项目 */}
<span className={`p_1_icon icon${i} mr5`}></span>
{/* 专项项目 */}
<span className={`s_p_order font-25 mr10 color-blue`}>
<span className='s_p_order_1'>{order < 9 ? `0${order+1}` : order+1}</span>
<span className={`s_p_order_icon s_p_order_icon${i}`}></span>
<img src={require('../image/s_project3.png')} width="18"/>
</span>
<span className='font-17 font-bd task-hide' title={item.name}>{item.name}</span>
</div>
})}
</div>
</div>
})}
</Slider>
}
function Project({ data, subTitle }) {
const { id, homepageProjectTitle } = data || {};
@ -15,7 +52,10 @@ function Project({ data, subTitle }) {
const pages = [];
useEffect(() => {
id && getProjectsTypeLists(id).then(result => {
id && getProjectsTypeLists(id, {
pageNum: 1,
pageSize: 100,
}).then(result => {
if (result) {
const rows = result.data.rows;
rows[0] && setTypeId(rows[0].id)
@ -52,19 +92,12 @@ function Project({ data, subTitle }) {
<div className='project_1 width1200 pt50 pb60'>
<p className='font-bd font-30 mb15 align task-hide'>{homepageProjectTitle}</p>
<p className='font-16 align color212 mb30'>{subTitle}</p>
<div className='flexCenter align'>
{typeList.slice(0, 3).map((item, index) => {
return <div className={`proTypeBox flexCenter font-17 mr30 pointer ${typeId === item.id && "active"}`} onClick={() => { setTypeId(item.id); setPage(1) }}>
<span className={`icon${index} mr5`}></span>
{item.name}
</div>
})}
</div>
<TypeCarousel pageSize={5} list={typeList} typeId={typeId} onClick={(id)=>{setTypeId(id); setPage(1)}}/>
<Spin spinning={loading}>
<Carousel className='zone_1_carousel' afterChange={(current)=>{setLoading(true);setPage(current+1)}}>
{pages.map((page1, index) => (
<div key={index}>
<div className='df wrap between mt60 pl10 pr10 mb25'>
<div className='df wrap between pl10 pr10 mb25'>
{lists.map((i, index) => {
const { extra: { commitCount, contributorsCount, lastWeekScore, scoreChange } } = i || {}
const order = page >= 2 ? (page-1)*6+index+1 : index+1;

View File

@ -3,6 +3,7 @@ import { getSpecialProjectDetail, getSpecialProjectList, getSpecialProjectTypeLi
import { Col, Divider, Row, Tag } from 'antd';
import Nodata from '../../../../Nodata';
import '../index.scss';
import { TypeCarousel } from './project';
function SpecialProjects({data, subTitle}) {
const {key, homepageSpecialProjectTitle, id} = data || {};
@ -15,7 +16,7 @@ function SpecialProjects({data, subTitle}) {
useEffect(()=>{
id && getSpecialProjectTypeList(id, {
pageNum: 1,
pageSize: 4,
pageSize: 100,
}).then(res=>{
if(res){
const rows = res.data.rows;
@ -120,13 +121,13 @@ function SpecialProjects({data, subTitle}) {
currentRow.push(
<div
key={item.id}
className={`s_p_detail ${selectedItem === item.id ? 'active' : ''}`}
className={`s_p_detail df between ${selectedItem === item.id ? 'active' : ''}`}
onClick={() => handleItemClick(item.id)}
>
<span className={`font-bd font-22 s_p_d_order align s_p_d_order${index+1}`}>{index+1}</span>
<div className='font-bd font-17 task-hide-2 mb5'>{item.name}</div>
<div className='task-hide-2 color6B7' style={{minHeight: '56px'}}>摘要{item.description}</div>
<p style={{color: '#75798A'}} className='mt3'><i className='iconfont icon-chengyuan2 font-15 mr5'></i>{item.projectLeader}</p>
<div className='task-hide-2 color6B7'>摘要{item.description}</div>
<p style={{color: '#75798A'}} className='mt6'><i className='iconfont icon-chengyuan2 font-15 mr5'></i>{item.projectLeader}</p>
</div>
);
@ -146,7 +147,7 @@ function SpecialProjects({data, subTitle}) {
<div className='s_p_head'>
<Tag color='#466AFF' style={{padding: '0 2px'}}>项目</Tag><span className='font-20 font-bd'>{name}</span>
<p className='mt10 font-15 pb5'>项目负责人<span className='color212'>{projectLeader}</span></p>
<p className='font-15 pb5'>奖项<span className='color-blue'>{awards}</span></p>
{ awards && <p className='font-15 pb5'>奖项<span className='color-blue'>{awards}</span></p> }
<p className='font-15 pb5'>摘要<span className='color212'>{description}</span></p>
</div>
<div style={{padding: '22px 33px'}}>
@ -171,18 +172,7 @@ function SpecialProjects({data, subTitle}) {
<div className='specialProjects_1 width1200 pt50 pb60'>
<p className='font-bd font-30 mb15 align task-hide'>{homepageSpecialProjectTitle}</p>
<p className='font-16 align color212 mb50'>{subTitle}</p>
<div className='flexCenter align mb50'>
{typeList.map((item, index)=>{
return <div className={`proTypeBox flexCenter mr30 color212 pointer pl5 pr5 ${typeId === item.id && "active"}`} onClick={()=>{setTypeId(item.id)}}>
<span className={`s_p_order font-25 mr10 color-blue`}>
<span className='s_p_order_1'>{index < 9 ? `0${index+1}` : index+1}</span>
<span className={`s_p_order_icon s_p_order_icon${index}`}></span>
<img src={require('../image/s_project3.png')} width="18"/>
</span>
<span className='font-17 font-bd task-hide'>{item.name}</span>
</div>
})}
</div>
<TypeCarousel pageSize={3} list={typeList} typeId={typeId} onClick={(id)=>{setTypeId(id);}}/>
<div className='df wrap between'>
{renderItems()}
<div style={{margin: '0 auto'}}>{!projectList.length && <Nodata _html="暂无数据"/>}</div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -65,6 +65,20 @@
color: #D9D9D9;
}
}
.intro_1_carousel{
width: 526px;
float: right;
margin-left: 35px;
.slick-dots li button:before{
font-size: 10px;
top: -12px;
}
}
.intro_image{
width: 526px;
height: 272px;
object-fit: scale-down;
}
}
.news_1_bg{
background-image: url('./image/new1.png');
@ -147,8 +161,9 @@
}
}
.pd_desc{
min-height: 55px;
// min-height: 55px;
color: #6B707C;
margin-bottom: 10px;
}
.pd_tag{
display: flex;
@ -186,7 +201,7 @@
}
}
.project_1_bg .proTypeBox, .specialProjects_1_bg .proTypeBox{
width: 280px;
min-width: 275px;
height: 63px;
background: #F5F6F7;
border-radius: 8px;
@ -207,6 +222,12 @@
.icon2{
background-image: url('./image/proType3_active.png');
}
.icon3{
background-image: url('./image/proType4_active.png');
}
.icon4{
background-image: url('./image/proType5_active.png');
}
.s_p_order_1, .s_p_order>img{
display: none;
}
@ -225,7 +246,7 @@
background-image: url('./image/s_project7.png');
}
}
.icon1, .s_p_order_icon, .icon0, .icon2{
.s_p_order_icon, .p_1_icon{
width: 22px;
height: 22px;
background-size: 100% 100%;
@ -239,12 +260,30 @@
background-image: url('./image/proType2.png');
}
.icon2{
width: 25px;
height: 19px;
height: 18px;
background-image: url('./image/proType3.png');
}
.icon3{
width: 24px;
height: 24px;
background-image: url('./image/proType4.png');
}
.icon4{
background-image: url('./image/proType5.png');
}
}
.project_1_bg .proTypeBox{
min-width:200px;
.s_p_order{
display: none;
}
}
.specialProjects_1_bg .proTypeBox{
.p_1_icon{
display: none;
}
}
.source_1_bg{
background-color: white;
background-image: url('./image/source1.png');
@ -350,6 +389,7 @@
margin: 0 0 35px 0 !important;
}
.s_p_detail{
flex-direction: column;
flex: 0 0 calc(33.333% - 20px);
background: #FFFFFF;
box-shadow: 0px 0px 10px 1px rgba(28,48,175,0.08);

View File

@ -26,6 +26,7 @@ import RenderHtml from '../../components/render-html';
import Loadable from 'react-loadable';
import Loading from '../../Loading';
import ProjectPortrait from '../Component/projectPortrait';
// import ProjectCompass from '../Component/projectCompass';
import imNoneImg from './img/importNone.png';
import moment from 'moment';
@ -694,6 +695,7 @@ function CoderDepot(props){
/>
</React.Fragment>
}
{/* {__CLIENT__ && <ProjectCompass owner={owner} projectsId={projectsId} />} */}
{/* 贡献者 */}
{mirror_status ===0 && <Contributors owner={owner} projectsId={projectsId} /> }
{/* 项目画像: 导入/fork项目不展示, open_portrait后台配置是否开启仓库 */}

View File

@ -38,11 +38,21 @@ function CompanyData({ data }){
useEffect(()=>{
if(c1userValue && c1 && c1.length > 0){
let fil = c1.filter(i=>i.Module === c1userValue);
let fil = c1.filter(i=> i.Module === c1userValue);
const companyArray = Array.from(new Set(fil.map(i => i.Company)));
let monthList = fil.map(obj => obj.Month);
let valueList = fil.map(obj => obj['Weight Ratio']);
setC1Keys(monthList);
setC1Values(valueList);
if(companyArray && companyArray.length>0 && fil.length>0){
const arr = companyArray.map(item=>{
let v = fil.filter(i=> i.Company == item);
let valueList = v.map(obj => obj['Weight Ratio']);
return {name :item , type: 'line',stack: 'Total',data:valueList}
})
setC1Values(arr);
}else{
setC1Values(valueList);
}
}
},[c1,c1userValue])
@ -127,7 +137,7 @@ function CompanyData({ data }){
</Select>
</div>
}
<StackImg x={keys} values={values} title={'每月公司总贡献'} id={"c2"}/>
<StackImg x={keys} values={[{name:"", type: 'line',stack: 'Total',data:values}]} title={'每月公司总贡献'} id={"c2"}/>
</div>
<div className='dropEchartPanel'>
{
@ -145,7 +155,7 @@ function CompanyData({ data }){
</Select>
</div>
}
<StackImg x={c3keys} values={c3values} title={'每月公司贡献最高模块中总贡献'} id={"c3"}/>
<StackImg x={c3keys} values={[{name:"", type: 'line',stack: 'Total',data:c3values}]} title={'每月公司贡献最高模块中总贡献'} id={"c3"}/>
</div>
<div className='dropEchartPanel'>
<Pie title={'公司总提交数'} values={pieValues}/>

View File

@ -47,14 +47,7 @@ function StackImg({x,values,title,id}){
yAxis: {
type: 'value'
},
series: [
{
name: name,
type: 'line',
stack: 'Total',
data: values
}
]
series: values
};
myEcharts.setOption(option);
}

10
src/forge/api/project.js Normal file
View File

@ -0,0 +1,10 @@
import javaFetch from '../javaFetch';
const service = javaFetch();
export function getmaturityAnalyse(params) {
return service({
url: `https://testbd.trustie.net/maturityAnalyse/`,
method: 'get',
params: window.location.hostname === 'testforgeplus.trustie.net' ? { ...params, env_url: 'testforgeplus' } : params
});
}

View File

@ -17,13 +17,27 @@ const Iframe = (props) => {
if (!current_user?.login) {
history.push("/login?go_page=/hiagent");
}
document.title = "GitLink-AI"
}, [])
function iframeLoad() {
let myIframe = document.getElementById("iframe");
const toastRight = myIframe?.contentWindow?.document?.getElementsByClassName("arco-notification-wrapper-topRight")[0]
const toastTop = myIframe?.contentWindow?.document?.getElementsByClassName("arco-notification-wrapper-top")[0]
if (toastRight) {
toastRight.style.top = '60px'
}
if (toastTop) {
toastTop.style.top = '80px'
}
}
return current_user?.login ? <iframe
id="iframe"
width="100%"
className="test-iframe"
src={ settings?.common?.hiAgent }
onLoad={iframeLoad}
></iframe> : ''
}