【GLCC】开源项目评估画像 #586
|
|
@ -0,0 +1,100 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import echarts from 'echarts/lib/echarts'
|
||||
import 'echarts/lib/chart/radar';
|
||||
import { Popover } from 'antd';
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
const radarChartOption = {
|
||||
color: ["#f8e367", "#99dfff"],
|
||||
title: {
|
||||
show: true
|
||||
},
|
||||
legend: {
|
||||
show: false
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
},
|
||||
radar: {
|
||||
indicator: [
|
||||
{ name: '影响力', max: 100 },
|
||||
{ name: '活跃度', max: 100 },
|
||||
{ name: '开发度', max: 100 },
|
||||
{ name: '健康度', max: 100 },
|
||||
{ name: '流行度', max: 100 },
|
||||
],
|
||||
center: ["50%", "55%"]
|
||||
},
|
||||
series: [{
|
||||
name: '',
|
||||
type: 'radar'
|
||||
}]
|
||||
};
|
||||
|
||||
function Radar({ fullName }) {
|
||||
const [score, setScore] = useState(undefined);
|
||||
useEffect(() => {
|
||||
let url = `/${fullName}/score.json`;
|
||||
axios.get(url).then(response => {
|
||||
if ('updated_at' in response.data) {
|
||||
setScore(response.data);
|
||||
const properties = ['influence', 'community', 'vitality', 'health', 'trend'];
|
||||
const scoreList = properties.map(property => Number((response.data[`${property}_norm_score`] * 100).toFixed(2)));
|
||||
var radarContainer = document.getElementById("radar");
|
||||
var myEcharts = echarts.init(radarContainer);
|
||||
radarChartOption.series[0].data = [{
|
||||
value: scoreList,
|
||||
name: '项目得分'
|
||||
}];
|
||||
myEcharts.setOption(radarChartOption);
|
||||
}
|
||||
});
|
||||
}, [])
|
||||
|
||||
return (
|
||||
|
||||
<div className="halfs" style={{ width: '100%', overflow: 'hidden' }}>
|
||||
<style>
|
||||
{
|
||||
`
|
||||
.ant-popover-title{
|
||||
padding:12px 16px 0px 16px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
border-bottom: none;
|
||||
}
|
||||
`
|
||||
}
|
||||
</style>
|
||||
<div className="font-16 color-ooo f-wrap-between">
|
||||
<span>项目画像</span>
|
||||
|
||||
{score &&
|
||||
<Popover content={<div>
|
||||
<ul className="mb15">
|
||||
<li><span className="font-bd mr8">影响力 :</span>
|
||||
与star、fork等社交指标相关</li>
|
||||
<li><span className="font-bd mr8">活跃度 :</span>
|
||||
与issue、pr响应率相关</li>
|
||||
<li><span className="font-bd mr8">流行度 :</span>
|
||||
与近期讨论度相关</li>
|
||||
<li><span className="font-bd mr8">开发度 :</span>
|
||||
与近期代码提交数相关</li>
|
||||
<li><span className="font-bd mr8">健康度 :</span>
|
||||
与贡献者人数相关</li>
|
||||
</ul>
|
||||
<span className="font-8 color-grey-8 ">更新于 {score['updated_at']}</span>
|
||||
</div>} title="维度说明" trigger="hover" placement="bottomRight" overlayStyle={{ width: '270px' }}>
|
||||
<i className="iconfont icon-xiaowenhao color-grey-8"></i>
|
||||
</Popover>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
{score ? <div id="radar" style={{ height: "200px", width: "100%" }}></div> : <div>预计将于一周后更新数据 </div>}
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
export default Radar;
|
||||
|
|
@ -15,6 +15,7 @@ import ReadMe from './CoderDepotReadme';
|
|||
import CoderRootFileDetail from './CoderRootFileDetail';
|
||||
import './Index.scss';
|
||||
import Releases from '../Component/Releases';
|
||||
import Radar from '../Component/Radar';
|
||||
import Contributors from '../Component/Contributors';
|
||||
import LanguagePower from '../Component/LanguagePower';
|
||||
import DrawerPanel from '../Component/DrawerPanel';
|
||||
|
|
@ -646,6 +647,8 @@ function CoderDepot(props){
|
|||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
{/* 项目画像 */}
|
||||
{!projectDetail.private && <Radar fullName={projectDetail.full_name} />}
|
||||
{/* 贡献者 */}
|
||||
{mirror_status ===0 && <Contributors owner={owner} projectsId={projectsId} /> }
|
||||
{/* 语言 */}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import more from '../img/index/more.png';
|
|||
import axios from 'axios';
|
||||
import { getImageUrl } from 'educoder';
|
||||
import Nodata from '../../Nodata';
|
||||
import TopIcon from '../img/index/hotAuthor.png';
|
||||
import TopProjectSelect from './TopProjectSelect'
|
||||
|
||||
const { Search } = Input;
|
||||
|
||||
|
|
@ -28,8 +30,10 @@ function Index() {
|
|||
},[])
|
||||
|
||||
useEffect(()=>{
|
||||
setIsSpin(true);
|
||||
getProject();
|
||||
if(cateID != -1){
|
||||
setIsSpin(true);
|
||||
getProject();
|
||||
}
|
||||
},[cateID, search])
|
||||
|
||||
function getCate() {
|
||||
|
|
@ -58,6 +62,10 @@ function Index() {
|
|||
}).catch(error=>{})
|
||||
}
|
||||
|
||||
const handleTopProjectData = (data) => {
|
||||
setProjectsList(data);
|
||||
};
|
||||
|
||||
function searchFun(value){
|
||||
setSearch(value);
|
||||
}
|
||||
|
|
@ -70,6 +78,7 @@ function Index() {
|
|||
<div className="left">
|
||||
<ul className="leftTypes">
|
||||
<a className={cateID ? "" : "active"} onClick={()=>setCateID(undefined)}><img src={Icon} alt="" /><span>最近更新</span></a>
|
||||
<a className={cateID != -1 ? "" : "active"} onClick={() => setCateID(-1)}><img src={TopIcon} alt="" /><span>高分项目</span></a>
|
||||
{
|
||||
cateList && cateList.length>0?
|
||||
cateList.map((i,k)=>{
|
||||
|
|
@ -95,6 +104,7 @@ function Index() {
|
|||
/>
|
||||
<Link to={`/explore/all${search ? '?search='+search : ''}`}>更多<i className="iconfont icon-triangle font-12"></i></Link>
|
||||
</div>
|
||||
{cateID == -1 && <TopProjectSelect onData={handleTopProjectData} />}
|
||||
<Spin spinning={isSpin}>
|
||||
<div style={{minHeight:"400px"}}>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,76 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import axios from 'axios';
|
||||
import { Radio, Select } from 'antd';
|
||||
|
||||
const { Option } = Select
|
||||
|
||||
function TopProjectSelect(props) {
|
||||
const [interval, setInterval] = useState(0);
|
||||
const [periodList, setPeriodList] = useState([]);
|
||||
const [selectedPeriod, setSelectedPeriod] = useState("暂无数据");
|
||||
const onChangeInterval = (e) => {
|
||||
setInterval(e.target.value);
|
||||
getTopProjects(0, e.target.value);
|
||||
};
|
||||
|
||||
const onChangePeriod = (value) => {
|
||||
console.log(value);
|
||||
setSelectedPeriod(value);
|
||||
getTopProjects(value, interval);
|
||||
};
|
||||
|
||||
function getTopProjects(period, time_interval) {
|
||||
let url = `/projects/top.json`;
|
||||
axios.get(url, {
|
||||
params: {
|
||||
period: period,
|
||||
time_interval: time_interval
|
||||
}
|
||||
}).then(result => {
|
||||
if (result && result.data) {
|
||||
if (period == 0) {
|
||||
var period_info = result.data.period_info
|
||||
var optionsData = period_info.reverse().map((item) => ({
|
||||
value: item.period,
|
||||
label: `第${item.period}期(${item.updated_at})`,
|
||||
}));
|
||||
setPeriodList(optionsData)
|
||||
console.log(optionsData)
|
||||
if (optionsData) {
|
||||
setSelectedPeriod(optionsData[0].value)
|
||||
getTopProjects(optionsData[0].value, time_interval)
|
||||
}
|
||||
|
||||
} else {
|
||||
props.onData(result.data.projects);
|
||||
}
|
||||
}
|
||||
|
||||
}).catch(error => { })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getTopProjects(0, 0)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="leftTitles">
|
||||
<Radio.Group onChange={onChangeInterval} value={interval}>
|
||||
<span>时间跨度:</span>
|
||||
<Radio value={0}>每周</Radio>
|
||||
<Radio value={1}>每月</Radio>
|
||||
<Radio value={2}>季度</Radio>
|
||||
<Radio value={3}>年度</Radio>
|
||||
</Radio.Group>
|
||||
|
||||
<Select style={{ width: 200 }} defaultValue="暂无数据" value={selectedPeriod} onChange={onChangePeriod}>
|
||||
{periodList && periodList.map((option) => (
|
||||
<Option key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default TopProjectSelect;
|
||||
Loading…
Reference in New Issue