diff --git a/src/forge/Utils/locData.js b/src/forge/Utils/locData.js
index f1d38dbf3..5ebba6ccb 100644
--- a/src/forge/Utils/locData.js
+++ b/src/forge/Utils/locData.js
@@ -5338,10 +5338,10 @@ export const locData = Array.from(province.keys()).map(p=>({
label:p,
children:Array.from(province.get(p).keys()).map((c,key)=>({
value:c,
- label:c,
- children:Array.from(area.keys())[key].map(a=>({
- value:a,
- label:a,
- }))
+ label:c,
+ // children:Array.from(area.keys())[key].map(a=>({
+ // value:a,
+ // label:a,
+ // }))
}))
}));
\ No newline at end of file
diff --git a/src/forge/users/Echart/Calendar.jsx b/src/forge/users/Echart/Calendar.jsx
new file mode 100644
index 000000000..743a0a551
--- /dev/null
+++ b/src/forge/users/Echart/Calendar.jsx
@@ -0,0 +1,145 @@
+import React ,{ useEffect, useState } from 'react';
+import * as echarts from 'echarts';
+import moment from 'moment';
+import Axios from 'axios';
+
+function Calendar({ userLogin , time , chooseTime }) {
+ const [ endT, setEndT ] = useState("");
+ const [ baginT, setBaginT ] = useState("");
+
+ useEffect(()=>{
+ if(time){
+ let e,b = "";
+ if(parseInt(time,0) === parseInt(moment().get('year'),0)){
+ let y = moment().get('year');
+ let m = moment().get('month');
+ let d = moment().get('date');
+ e = `${y}-${m+1}-${d}`;
+ b = `${y-1}-${m+1}-${d}`;
+ }else{
+ e = `${time}-12-31`;
+ b = `${time}-01-01`;
+ }
+ setEndT(e);
+ setBaginT(b);
+ }
+ },[time])
+
+ useEffect(()=>{
+ if(baginT && endT){
+ getData();
+ }
+ },[baginT,endT])
+
+ function getData() {
+ const url = `/users/${userLogin}/headmaps.json`;
+ Axios.get(url).then(result=>{
+ if(result && result.data){
+ let m = result.data.headmaps;
+ m.sort(compare('contributions'));
+ let max = m[m.length -1].contributions;
+ Init(m,max);
+ }
+ }).catch(error=>{})
+ }
+
+ function compare(property){
+ return function(a,b){
+ var value1 = a[property];
+ var value2 = b[property];
+ return value1 - value2;
+ }
+ }
+
+ function getVirtulData(data) {
+ var date = +echarts.number.parseDate(baginT);
+ var end = +echarts.number.parseDate(endT);
+ var dayTime = 3600 * 24 * 1000;
+ var array = [];
+ for (var time = date; time <= end; time += dayTime) {
+ let stamp = timestampToTime(time);
+ let stampFilter = data.filter(i=>i.date === stamp);
+ if(stampFilter && stampFilter.length > 0){
+ array.push([stampFilter[0].date,stampFilter[0].contributions]);
+ }else{
+ array.push([stamp,0]);
+ }
+ }
+ return array;
+ }
+
+ function timestampToTime(timestamp) {
+ var date = new Date(timestamp);
+ var Y = date.getFullYear() + '-';
+ var M = (date.getMonth()+1 < 10 ? '0'+(date.getMonth()+1) : date.getMonth()+1) + '-';
+ var D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();
+ return Y+M+D;
+ }
+
+ function Init(data,max) {
+ var huan_val = document.getElementById("Calendar");
+ var myEcharts = echarts.init(huan_val);
+ let option = {
+ title: {
+ show:false
+ },
+ tooltip: {
+ formatter:function(params){
+ return params.data[0] + ': ' + params.data[1] + '个贡献';
+ }
+ },
+ visualMap: {
+ min: 0,
+ max: max,
+ type: 'piecewise',
+ orient: 'horizontal',
+ left: 'center',
+ bottom: 40,
+ inRange:{
+ color:['#fafafa', '#216e39']
+ }
+ },
+ calendar: {
+ top: 50,
+ left: 40,
+ right: 30,
+ cellSize: ['auto', 13],
+ range: [baginT, endT],
+ splitLine:{
+ show:false,
+ lineStyle:{
+ color:"#fff",
+ width:1,
+ type:"solid"
+ }
+ },
+ itemStyle: {
+ borderWidth: 0.5
+ },
+ yearLabel: {show: false},
+ monthLabel:{
+ nameMap:"cn"
+ },
+ dayLabel:{
+ nameMap:"cn",
+ firstDay:1
+ }
+ },
+ series: {
+ type: 'heatmap',
+ coordinateSystem: 'calendar',
+ data: getVirtulData(data)
+ }
+ };
+ myEcharts.setOption(option);
+ myEcharts.on('click', function (params) {
+ chooseTime(params.data);
+ });
+ }
+
+
+ return(
+
+ )
+}
+export default Calendar;
\ No newline at end of file
diff --git a/src/forge/users/Echart/Cloud.jsx b/src/forge/users/Echart/Cloud.jsx
index cbe182a26..778b30e74 100644
--- a/src/forge/users/Echart/Cloud.jsx
+++ b/src/forge/users/Echart/Cloud.jsx
@@ -4,41 +4,48 @@ import Js2WordCloud from 'js2wordcloud/dist/js2wordcloud.js'
function Cloud({data}) {
useEffect(()=>{
- optionChart1();
- },[])
+ if(data){
+ optionChart1(data);
+ }
+ },[data])
- function optionChart1(){
+ function optionChart1(d){
var div = new Js2WordCloud(document.getElementById('cloud'))
- let textList=[
- ['服务'], ['细致'], ['意识'], ['踏实'],['开发'], ['反馈'], ['协助'],['使用'],['谈判']
- ]
+ let textList= d.categories;
let cyList=[]
- for(let i=0;i<60;i++){
- cyList.push([textList[parseInt(Math.random()*textList.length)],Math.round(Math.random()*10)+1])
+ for(let i=0;i
=12 && fontSize<=20) {
- return 'rgb(29,227,250,0.3)';
- } else if(fontSize>20 && fontSize<=30){
- return 'rgb(29,227,250,0.6)';
- }else if(fontSize>30 && fontSize<=40){
- return 'rgb(29,227,250)';
+ switch(fontSize){
+ case 21:
+ return "#f8e367"
+ case 20:
+ return "#99dfff"
+ case 19:
+ return "#ff9e48"
+ case 18:
+ return "#5ea6ff"
+ case 17:
+ return "#58c0f0"
+ default:
+ return "#bcbcbc"
}
},
})
}
return(
-
+
)
}
export default Cloud;
\ No newline at end of file
diff --git a/src/forge/users/Echart/Line.jsx b/src/forge/users/Echart/Line.jsx
index 2092b87c1..e8c9ac644 100644
--- a/src/forge/users/Echart/Line.jsx
+++ b/src/forge/users/Echart/Line.jsx
@@ -2,88 +2,75 @@ import React ,{ useEffect } from 'react';
import * as echarts from 'echarts';
function Line({data}) {
- useEffect(()=>{
- Init();
- },[])
useEffect(()=>{
if(data){
- Init();
+ Init(data);
}
},[data])
- function Init() {
+ function Init(d) {
var huan_val = document.getElementById("Line");
var myEcharts = echarts.init(huan_val);
let option = {
- color: ["#f8e367", "#99dfff", "#58c0f0", "#5ea6ff", "#ff9e48", "#bcbcbc"],
+ color: ["#f8e367", "#58c0f0", "#ff9e48"],
title: {
- text: '近期活动统计',
- left: '3%'
+ show:false
},
tooltip: {
trigger: 'axis'
},
legend: {
- data: ['邮件营销', '联盟广告', '视频广告', '直接访问', '搜索引擎'],
- right: '3%'
+ data: ['提交数', '易修数', '合并请求数'],
+ right: 'center',
+ bottom: '4%',
},
grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
+ left: '4%',
+ right: '5%',
+ bottom: '16%',
containLabel: true
},
toolbox: {
- feature: {
- // saveAsImage: {}
- }
+ feature: {
+ // saveAsImage: {}
+ }
},
xAxis: {
- type: 'category',
- boundaryGap: false,
- data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
+ type: 'category',
+ boundaryGap: false,
+ data: d.dates,
+ axisTick:{
+ show:false
+ }
},
yAxis: {
- type: 'value',
- axisLine:{
- show:false
- },
- axisTick:{
- show:false
- }
+ type: 'value',
+ axisLine:{
+ show:false
+ },
+ axisTick:{
+ show:false
+ },
+ minInterval:1,
+ splitNumber: 5,
},
series: [
- {
- name: '邮件营销',
- type: 'line',
- stack: '总量',
- data: [120, 132, 101, 134, 90, 230, 210]
- },
- {
- name: '联盟广告',
- type: 'line',
- stack: '总量',
- data: [220, 182, 191, 234, 290, 330, 310]
- },
- {
- name: '视频广告',
- type: 'line',
- stack: '总量',
- data: [150, 232, 201, 154, 190, 330, 410]
- },
- {
- name: '直接访问',
- type: 'line',
- stack: '总量',
- data: [320, 332, 301, 334, 390, 330, 320]
- },
- {
- name: '搜索引擎',
- type: 'line',
- stack: '总量',
- data: [820, 932, 901, 934, 1290, 1330, 1320]
- }
+ {
+ name: '提交数',
+ type: 'line',
+ data: d.commits_count
+ },
+ {
+ name: '易修数',
+ type: 'line',
+ data: d.issues_count
+ },
+ {
+ name: '合并请求数',
+ type: 'line',
+ data: d.pull_requests_count
+ }
]
};
myEcharts.setOption(option);
diff --git a/src/forge/users/Echart/Pie.jsx b/src/forge/users/Echart/Pie.jsx
index 460d7f001..d5489b981 100644
--- a/src/forge/users/Echart/Pie.jsx
+++ b/src/forge/users/Echart/Pie.jsx
@@ -3,32 +3,27 @@ import echarts from 'echarts/lib/echarts';
import 'echarts/lib/chart/pie';
function Pie({data}) {
- useEffect(()=>{
- Init();
- },[])
useEffect(()=>{
if(data){
- Init();
+ Init(data);
}
},[data])
- function Init() {
+ function Init(d) {
var huan_val = document.getElementById("Pie");
var chart = echarts.init(huan_val);
let option = {
- color: ["#f8e367", "#99dfff", "#58c0f0", "#5ea6ff", "#ff9e48", "#bcbcbc"],
+ color: ["#f8e367", "#5ea6ff", "#ff9e48", "#99dfff"],
title: {
- text: '角色定位',
- top:"5%",
- left:"3%"
+ show:false
},
tooltip: {
trigger: 'item'
},
legend: {
top: '5%',
- right: '3%'
+ right: 'center'
},
series: [
{
@@ -56,11 +51,10 @@ function Pie({data}) {
show: false
},
data: [
- {value: 1048, name: '搜索引擎'},
- {value: 735, name: '直接访问'},
- {value: 580, name: '邮件营销'},
- {value: 484, name: '联盟广告'},
- {value: 300, name: '视频广告'}
+ {value: d.developer && d.developer.count, name: '开发者'},
+ {value: d.manager && d.manager.count, name: '管理员'},
+ {value: d.owner && d.owner.count, name: '创建者'},
+ {value: d.reporter && d.reporter.count, name: '报告者'}
]
}
]
diff --git a/src/forge/users/Echart/Radar.jsx b/src/forge/users/Echart/Radar.jsx
index f427442ed..5a75f2c8a 100644
--- a/src/forge/users/Echart/Radar.jsx
+++ b/src/forge/users/Echart/Radar.jsx
@@ -3,58 +3,55 @@ import echarts from 'echarts/lib/echarts'
import 'echarts/lib/chart/radar';
function Radar({data}) {
- useEffect(()=>{
- Init();
- },[])
useEffect(()=>{
if(data){
- Init();
+ Init(data);
}
},[data])
- function Init() {
+ function Init(d) {
var huan_val = document.getElementById("radar");
var myEcharts = echarts.init(huan_val);
let option = {
color: ["#f8e367", "#99dfff", "#58c0f0", "#5ea6ff", "#ff9e48", "#bcbcbc"],
title: {
- text: '开发能力',
- top:"0",
- left:"3%"
+ show:false
},
legend: {
- data: ['预算分配', '实际开销'],
- top:"0",
+ data: ['个人能力(personal)', '社区平均(average)'],
+ top:"3%",
right:"center"
},
+ tooltip: {
+ trigger: 'item'
+ },
radar: {
// shape: 'circle',
indicator: [
- { name: '销售', max: 6500},
- { name: '管理', max: 16000},
- { name: '信息技术', max: 30000},
- { name: '客服', max: 38000},
- { name: '研发', max: 52000},
- { name: '市场', max: 25000}
+ { name: '影响力', max: 100},
+ { name: '贡献度', max: 100},
+ { name: '活跃度', max: 100},
+ { name: '项目经验', max: 100},
+ { name: '语言能力', max: 100},
],
center:["50%","55%"]
},
series: [{
- name: '预算 vs 开销',
+ name: '',
type: 'radar',
data: [
{
- value: [4200, 3000, 20000, 35000, 50000, 18000],
- name: '预算分配'
+ value: d.user && [d.user.influence, d.user.contribution, d.user.activity, d.user.experience, d.user.language],
+ name: '个人能力(personal)'
},
{
- value: [5000, 14000, 28000, 26000, 42000, 21000],
- name: '实际开销'
+ value: d.platform && [d.platform.influence, d.platform.contribution, d.platform.activity, d.platform.experience, d.platform.language],
+ name: '社区平均(average)'
}
]
}]
- };
+ };
myEcharts.setOption(option);
}
diff --git a/src/forge/users/Echart/Round.jsx b/src/forge/users/Echart/Round.jsx
new file mode 100644
index 000000000..ebcb13671
--- /dev/null
+++ b/src/forge/users/Echart/Round.jsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import './style.scss';
+
+
+function Round({num,color,name}) {
+ return(
+
+
+ {num}分
+ {name}
+
+
+ {num > 50 ?
+
+ :
+
+ }
+ {num < 50 ?
+
+ :
+
+ }
+
+ )
+}
+export default Round;
\ No newline at end of file
diff --git a/src/forge/users/Echart/style.scss b/src/forge/users/Echart/style.scss
new file mode 100644
index 000000000..5a2aae387
--- /dev/null
+++ b/src/forge/users/Echart/style.scss
@@ -0,0 +1,69 @@
+.annulusBasics {
+ width : 74px;
+ height : 74px;
+ position : relative;
+ overflow : hidden;
+ border-radius: 50%;
+ text-align : center;
+ z-index : 1;
+}
+//圆环中间的白色
+.centerCircle {
+ position : absolute;
+ z-index : 10;
+ border-radius: 50%;
+ width : 60px;
+ height : 60px;
+ background : #fff;
+ transform : translate(7px, 7px);
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ line-height: 20px;
+ font-size: 12px;
+ .score{
+ font-size: 18px;
+ }
+}
+ //圆环百分比时出现圆环边框的颜色
+.annulusOuter {
+ position : absolute;
+ top : 0;
+ left : 0;
+ width : 74px;
+ height : 74px;
+ border : 12px solid #FF7F69;
+ border-radius: 50%;
+}
+//左边遮住圆环颜色的长方形
+.leftRectangle {
+ position : absolute;
+ background : #EBEEF5;
+ width : 37px;
+ height : 74px;
+ transform-origin: right;
+}
+//右边遮住圆环颜色的长方形
+.rightRectangle {
+ position : absolute;
+ background : #EBEEF5;
+ transform-origin: left;
+ left : 37px;
+ width : 37px;
+ height : 74px;
+ transform : rotate(0deg);
+}
+//弥补hidde在移动端失效的圆环
+.repairAnnulus{
+ position : absolute;
+ width : 74px;
+ height : 74px;
+ z-index : 20;
+ border-radius: 50%;
+ box-sizing : content-box;
+//改外边框的时候,位置也要改下
+ border : 20px solid #ffffff;
+ top : -20px;
+ left : -20px;
+}
\ No newline at end of file
diff --git a/src/forge/users/GeneralView/Activity.jsx b/src/forge/users/GeneralView/Activity.jsx
new file mode 100644
index 000000000..ce09e885f
--- /dev/null
+++ b/src/forge/users/GeneralView/Activity.jsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { AlignCenter } from '../../Component/layout';
+import { TagInfo } from '../../Utils/TagColor';
+import { getImageUrl } from 'educoder';
+
+function Activity({list}) {
+ return(
+
+ {
+ list.map((i,k)=>{
+ return(
+ -
+
+
+
+ {i.user_name}
+ {i.action_time}
+ {i.priority && TagInfo(`${i.priority}`,"")}
+ {i.issue_status && {i.issue_status} }
+
+
{i.action_type}:{i.name}
+
+
+ )
+ })
+ }
+
+ )
+}
+export default Activity;
\ No newline at end of file
diff --git a/src/forge/users/GeneralView/ConcentrateBox.jsx b/src/forge/users/GeneralView/ConcentrateBox.jsx
new file mode 100644
index 000000000..3ee941947
--- /dev/null
+++ b/src/forge/users/GeneralView/ConcentrateBox.jsx
@@ -0,0 +1,172 @@
+import React, { useEffect, useState } from 'react';
+import { Modal , Checkbox , Spin , Input } from 'antd';
+import Axios from 'axios';
+import { Link } from 'react-router-dom';
+
+const { Search } = Input;
+const limit = 20;
+function ConcentrateBox({ visible , onCancel , onSure , username , choosed }) {
+ const [ page , setPage ]= useState(1);
+ const [ total , setTotal ]= useState(0);
+ const [ pageSize , setPageSize ] = useState(false);
+ const [ search , setSearch ] = useState(undefined);
+
+ const [ list , setList ]= useState([]);
+ const [ value , setValue ]= useState([]);
+ const [ isSpin , setIsSpin ]= useState(true);
+ const [ disable , setDisable ] = useState(false);
+
+ const [ copyList , setCopyList ] = useState([]);
+ const [ copyAllList , setCopyAllList ] = useState([]);
+
+ useEffect(()=>{
+ if(visible){
+ setIsSpin(true);
+ getProjectList();
+ }else{
+ setSearch(undefined);
+ setCopyAllList([]);
+ setCopyList([]);
+ setList([]);
+ }
+ },[visible])
+
+ useEffect(()=>{
+ if(page>1){
+ setIsSpin(true);
+ getProjectList(page,undefined);
+ }
+ },[page])
+
+
+ useEffect(()=>{
+ if(visible && choosed && choosed.length >0 ){
+ setValue(choosed);
+ }
+ },[visible,choosed])
+
+ useEffect(()=>{
+ if(value && value.length === 6){
+ setDisable(true);
+ }else{
+ setDisable(false);
+ }
+ },[value])
+
+ function getProjectList(p,s) {
+ const url = `/users/${username}/projects.json`;
+ Axios.get(url,{
+ params:{
+ page:p,limit,is_public: "public",search:s,choosed
+ }
+ }).then(result=>{
+ if(result && result.data){
+ let e = !search ? mergeArrayMerge(list,result.data.projects) : result.data.projects;
+ setCopyAllList(!search ? e : copyAllList);
+ setTotal(result.data.count);
+ setList(e);
+ setIsSpin(false);
+ // 查看更多需要页数
+ let s = parseInt(result.data.count/limit,0);
+ let y = result.data.count%limit;
+ setPageSize(y>0?s+1:s);
+ }
+ }).catch(error=>{})
+ }
+
+ function mergeArrayMerge (array1, array2) {
+ array1.map((v, index) => {
+ if (v !== '') {
+ let idx = array2.indexOf(v);
+ if (idx > -1) {
+ array2.splice(idx, 1)
+ }
+ }
+ });
+ array1 = array1.concat(array2);
+ return array1
+ }
+
+ function saveList(c) {
+ // 将选中的复制下来保存到copyList数组里
+ if(c && c.length > 0){
+ let l = []
+ for(var i=0;ij.id === c[i]);
+ if(filter && filter.length>0){
+ l.push(filter[0]);
+ }
+ }
+ setCopyList(l);
+ }
+ }
+
+ function onOk() {
+ onSure && onSure(value);
+ setValue([]);
+ }
+
+ function chooseProject(e) {
+ setValue(e);
+ }
+
+ // 搜索
+ function onSearch(params) {
+ setCopyAllList(list);
+ value && value.length > 0 ? saveList(value) : setCopyList([]);
+ setPage(1);
+ setSearch(params);
+ getProjectList(1,params);
+ }
+
+
+ return(
+
+
+
+
最多可选取6个公开仓库
+
setSearch(e.target.value)}
+ />
+
+
+
+ {
+ copyList && copyList.length >0 && copyList.map((i,k)=>{
+ return(
+ j === i.id).length===0)}>{i.author && i.author.name}/{i.name}
+ )
+ })
+ }
+ {
+ list && list.length > 0 && list.map((i,k)=>{
+ let c = copyList && copyList.length >0 && copyList.filter(j=>j.id === i.id).length !== 0;
+ return(
+ !c && j === i.id).length===0)}>{i.author && i.author.name}/{i.name}
+ )
+ })
+ }
+
+
+ { total > limit && page < pageSize && setPage(page+1)}>查看更多
}
+ { (list && list.length === 0) && (copyList && copyList.length === 0) && 您还没有公开的{search && `“${search}”`}项目,先去新建项目
}
+
+
+ )
+}
+export default ConcentrateBox;
\ No newline at end of file
diff --git a/src/forge/users/GeneralView/ConcentrateProject.jsx b/src/forge/users/GeneralView/ConcentrateProject.jsx
new file mode 100644
index 000000000..bfcf290d5
--- /dev/null
+++ b/src/forge/users/GeneralView/ConcentrateProject.jsx
@@ -0,0 +1,83 @@
+import React, { useEffect, useState } from 'react';
+import { FlexAJ , AlignCenter } from '../../Component/layout';
+import { Link } from 'react-router-dom';
+import axios from 'axios';
+import Box from './ConcentrateBox';
+
+function ConcentrateProject({userLogin,current}) {
+ const [ list , setList ] = useState(undefined);
+ const [ visible , setVisible ] = useState(false);
+ const [ value , setValue ] = useState([]);
+
+ useEffect(()=>{
+ getList();
+ },[])
+
+ function getList() {
+ const url = `/users/${userLogin}/is_pinned_projects.json`;
+ axios.get(url).then(result=>{
+ if(result && result.data){
+ let p = result.data.projects;
+ setList(p);
+ if(p && p.length > 0){
+ let array = p.map(i=>{
+ return i.project_id
+ })
+ setValue(array);
+ }
+ }
+ }).catch(erroer=>{})
+ }
+
+ function onSure(is_pinned_project_ids) {
+ if(is_pinned_project_ids && is_pinned_project_ids.length===0){
+ setValue([]);
+ }
+ const url = `/users/${userLogin}/is_pinned_projects/pin.json`;
+ axios.post(url,{
+ is_pinned_project_ids
+ }).then(result=>{
+ if(result && result.data){
+ setVisible(false);
+ getList();
+ }
+ }).catch(error=>{})
+ }
+ return(
+
+ setVisible(false)} onSure={onSure} username={userLogin} choosed={value}/>
+ {
+ list && list.length>0 &&
+
+
+ 精选项目
+ { current && setVisible(true)}>自定义精选项目 }
+
+
+
+ {
+ list.map((i,k)=>{
+ return(
+ -
+ {i.name}
+
{i.description}
+
+ { i.category && {i.category.name} }
+ {i.watchers_count}
+ {i.forked_count}
+
+
+ )
+ })
+ }
+
+
+
+ }
+ {
+ list && list.length === 0 && current &&
+ }
+
+ )
+}
+export default ConcentrateProject;
\ No newline at end of file
diff --git a/src/forge/users/GeneralView/Index.jsx b/src/forge/users/GeneralView/Index.jsx
index 9a76e9aa1..ded435827 100644
--- a/src/forge/users/GeneralView/Index.jsx
+++ b/src/forge/users/GeneralView/Index.jsx
@@ -1,22 +1,127 @@
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import './Index.scss';
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/title';
import 'echarts/lib/component/legend'
import 'echarts/lib/component/markPoint';
-import Pie from '../Echart/Pie';
-import Line from '../Echart/Line';
-import Radar from '../Echart/Radar';
-import Cloud from '../Echart/Cloud';
+import { Select , Pagination } from 'antd';
+import { FlexAJ } from '../../Component/layout';
+import Line from '../Echart/Line';
+import Calendar from '../Echart/Calendar';
+import ConcentrateProject from './ConcentrateProject';
+import Activity from './Activity';
+import moment from 'moment';
+import Axios from 'axios';
+import Nodata from '../../Nodata';
+
+const { Option } = Select;
+const aLimit = 5;
function Index(props) {
+ const [ page , setPage ] = useState(1);
+ const [ total , setTotal ] = useState(0);
+ const [ projectTrends , setProjectTrends ] = useState(undefined);
+
+ const [ year , setYear ] = useState(moment().get('year'));
+ const [ yearList , setYearList ] = useState(undefined);
+ const [ activityDate , setActivityDate ] = useState(undefined);
+
+ const [ statisticData , setStatisticData ] = useState(undefined);
+
+ const username = props.match.params.username;
+ const current_user = props.current_user;
+ const user = props.user;
+
+ useEffect(()=>{
+ if(user){
+ let c = user.created_time && user.created_time.split("-")[0];
+ let y = moment().get('year');
+ let array = []
+ for(var i = y ; i >= parseInt(c,0);i--){
+ array.push(i);
+ }
+ setYearList(array);
+ }
+ },[user])
+
+ // 在贡献度日历表中选择一个时间
+ function chooseTime(data) {
+ if(data){
+ setPage(1);
+ setActivityDate(data[0]);
+ }
+ }
+
+ // 年份下拉框option
+ function renderYear(list){
+ return list.map((i,k)=>{
+ return(
+
+ )
+ })
+ }
+
+ useEffect(()=>{
+ getActivity();
+ },[activityDate,page])
+
+ // 获取动态列表
+ function getActivity() {
+ const url = `/users/${username}/project_trends.json`;
+ Axios.get(url,{
+ params:{
+ date:activityDate,
+ limit:aLimit,page
+ }
+ }).then(result=>{
+ if(result && result.data){
+ setProjectTrends(result.data.project_trends);
+ setTotal(result.data.total_count);
+ }
+ }).catch(error=>{})
+ }
+
+ // 获取近期活动统计
+ useEffect(()=>{
+ getStatistics();
+ },[])
+
+ function getStatistics() {
+ const url = `/users/${username}/statistics/activity.json`;
+ Axios.get(url).then(result=>{
+ if(result && result.data){
+ setStatisticData(result.data);
+ }
+ }).catch(error=>{})
+ }
+
return(
-
-
-
-
+
+
+
+
+
+
+ 贡献度
+
+
+
+
+
+
+
+
动态
+ { projectTrends && projectTrends.length > 0 &&
}
+ { projectTrends && projectTrends.length === 0 && }
+ { total > aLimit && }
+
)
}
diff --git a/src/forge/users/GeneralView/Index.scss b/src/forge/users/GeneralView/Index.scss
index e69de29bb..e79f68580 100644
--- a/src/forge/users/GeneralView/Index.scss
+++ b/src/forge/users/GeneralView/Index.scss
@@ -0,0 +1,146 @@
+.concentrate{
+ padding:20px 0px 0px;
+ .concentrateUl{
+ display: flex;
+ flex-wrap: wrap;
+ li{
+ width: 48.5%;
+ margin-right: 3%;
+ margin-top: 20px;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ border:1px solid #dedede;
+ padding:15px 20px;
+ cursor: default ;
+ &:nth-child(2n){
+ margin-right: 0px;
+ }
+ .name{
+ font-size: 16px;
+ color: #4CACFF;
+ }
+ .desc{
+ color: #999;
+ }
+ .tagName{
+ display: block;
+ background-color: #f7f5f5;
+ border-radius: 3px;
+ color: #666;
+ padding:0px 10px;
+ height: 22px;
+ line-height: 22px;
+ font-size: 13px;
+ }
+ .pariseCount,.forkCount{
+ i{
+ font-size: 14px!important;
+ margin-right: 4px;
+ }
+ color: #999;
+ margin-left: 20px;
+ }
+ }
+ }
+}
+.ConcentrateTip{
+ margin:20px 20px 0px;
+ padding:5px 20px;
+ border:1px solid rgb(248, 56, 56);
+ border-radius: 4px;
+ background-color: rgba(248, 56, 56,0.1);
+ color: rgb(248, 56, 56);
+ display: flex;
+ align-items: center;
+ a{
+ color: #4cacff;
+ }
+ i{
+ font-size: 15px!important;
+ margin-right: 5px;
+ }
+}
+.ConcentrateBox{
+ .ant-modal-body{
+ min-height: 258px;
+ padding:0px;
+ padding-bottom: 15px;
+ }
+ .listbox{
+ max-height: 210px;
+ overflow-y: auto;
+ padding-left: 30px;
+ }
+ .operateDiv{
+ padding:20px 30px
+ }
+ .morelist{
+ text-align: center;
+ padding-top:15px;
+ cursor: pointer;
+ }
+ .ant-checkbox-group{
+ display: flex;
+ flex-wrap: wrap;
+ .ant-checkbox-wrapper{
+ width: 50%;
+ margin-left: 0px!important;
+ display: flex;
+ .ant-checkbox{
+ padding-top: 3px;
+ }
+ span:last-child{
+ flex:1;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ }
+ }
+}
+.recentStatic{
+ padding: 30px 0px;
+}
+.calendarStatic,.activeStatic{
+ .infosActivity{
+ padding-bottom: 30px;
+ &>li{
+ display: flex;
+ border-bottom:1px solid #eee;
+ align-items: center;
+ padding:20px 0px;
+ .aImg{
+ width: 48px;
+ height: 48px;
+ margin-right: 20px;
+ border-radius: 50%;
+ }
+ .aInfos{
+ flex: 1;
+ span{
+ margin-left: 20px;
+ margin-right: 0px;
+ }
+ .name{
+ font-size: 16px;
+ color:#333;
+ }
+ .time,.status{
+ color: #999;
+ }
+ .aDesc{
+ color: #666;
+ margin-top: 5px;
+ line-height: 20px;
+ }
+ }
+ &:last-child{
+ border-bottom:none;
+ }
+ }
+ }
+}
+.activeStatic{
+ padding-top: 20px;
+}
\ No newline at end of file
diff --git a/src/forge/users/Index.scss b/src/forge/users/Index.scss
index d8d4ecd4f..71d06226e 100644
--- a/src/forge/users/Index.scss
+++ b/src/forge/users/Index.scss
@@ -1,6 +1,6 @@
$flex:flex;
.headerbox{
- padding:20px 40px;
+ padding:20px;
border-bottom: 1px solid #E0E0E0;
display: $flex;
align-items: center;
@@ -24,8 +24,17 @@ $flex:flex;
margin-right: -1px;
}
}
+
+.echartBox{
+ border:1px solid #DEDEDE;
+ &>p{
+ color: #999;
+ padding:15px 20px;
+ text-align: center;
+ }
+}
.contentBox{
- padding:20px 40px 0px 40px;
+ padding:20px 20px 0px 20px;
& > div{
margin-bottom: 20px;
display: $flex;
@@ -60,7 +69,7 @@ $flex:flex;
}
}
.infosType{
- padding:20px 30px 0px 30px;
+ padding:20px 30px 0px 20px;
display: flex;
justify-content: space-between;
.infoStatus{
@@ -88,7 +97,66 @@ $flex:flex;
}
}
}
-
+.userDescription{
+ color: #666666;
+ line-height: 18px;
+ text-align: left;
+ margin:10px 0px;
+ word-break: break-all;
+ text-align: justify;
+}
+.focusBox,.infoBox{
+ width: 100%!important;
+ display: inline-block;
+ margin-top: 30px;
+ padding-top: 30px;
+ border-top: 1px solid #f1f1f1;
+}
+.infoBox{
+ padding-bottom: 10px;
+ text-align: left;
+ line-height: 28px;
+ color: #666;
+ margin-top: 20px;
+ &>div{
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ i{
+ color: #DEDEDE;
+ font-size: 15px!important;
+ }
+ span{
+ margin-left:10px ;
+ }
+}
+.headimg{
+ position: relative;
+ display: block;
+ img{
+ width: 110px;
+ height: 110px;
+ border-radius: 50%;
+ }
+ span{
+ position: absolute;
+ bottom: -6px;
+ right: 0px;
+ left: 65px;
+ i{
+ font-size: 25px!important;
+ border-radius: 50%;
+ background-color: #fff;
+ &.icon-nan{
+ color: #1890FF;
+ }
+ &.icon-nv{
+ color: pink;
+ }
+ }
+ }
+}
ul.ant-menu.menuStyle{
padding:0px 30px;
font-size: 16px;
@@ -97,6 +165,7 @@ ul.ant-menu.menuStyle{
line-height: 70px;
padding:0px;
margin-right: 30px!important;
+ border-bottom:transparent!important;
}
}
.disposeInfo{
@@ -135,4 +204,36 @@ ul.ant-menu.menuStyle{
padding:28px 0px;
border-bottom: 1px solid #eee;
}
+}
+
+.infosRightMenu{
+ .ant-menu-item{
+ padding:0px;
+ margin:0px 20px!important;
+ font-size: 17px;
+ height: 32px;
+ line-height: 0px;
+ border-bottom: 2px solid transparent!important;
+ position: relative;
+ a{
+ & >i{
+ font-size: 15px!important;
+ margin-right: 8px;
+ }
+ }
+ .menuNum{
+ font-size: 12px;
+ margin-left: 3px;
+ color: #FF6E21;
+ }
+ &.ant-menu-item-selected::before{
+ position: absolute;
+ width: 100%;
+ bottom: -1px;
+ height: 2px;
+ left: 0px;
+ background-color: #1890ff;
+ content:"";
+ }
+ }
}
\ No newline at end of file
diff --git a/src/forge/users/Infos.js b/src/forge/users/Infos.js
index 7e4e660a4..a415b3d58 100644
--- a/src/forge/users/Infos.js
+++ b/src/forge/users/Infos.js
@@ -1,6 +1,6 @@
import React, { Component } from "react";
import { Link } from "react-router-dom";
-import { Avatar, Tag, Button, Spin } from "antd";
+import { Button, Spin , Menu } from "antd";
import FocusButton from "../UsersList/focus_button";
import axios from "axios";
@@ -14,7 +14,10 @@ import './Index.scss';
import Loadable from "react-loadable";
import Loading from "../../Loading";
-
+const UpdateInfo = Loadable({
+ loader: () => import("./Material/Index"),
+ loading: Loading,
+});
const InfosDevOps = Loadable({
loader: () => import("./devOpsCI"),
loading: Loading,
@@ -24,6 +27,10 @@ const InfosDevOpsCD = Loadable({
loading: Loading,
});
+const Statistics = Loadable({
+ loader: () => import("./Statistics/Index"),
+ loading: Loading,
+});
const GeneralView = Loadable({
loader: () => import("./GeneralView/Index"),
loading: Loading,
@@ -59,19 +66,51 @@ class Infos extends Component {
project_type: undefined,
route_type: undefined,
undo_events:0,
- undo_messages:0
+ undo_messages:0,
+ menuKey:"0"
};
}
+ renderPath=(pathname)=>{
+ const { username } = this.props.match.params;
+ if(pathname === `/users/${username}`){
+ this.setState({menuKey:"0",route_type:undefined});
+ }else if(pathname === `/users/${username}/statistics`){
+ this.setState({menuKey:"1",route_type:undefined});
+ }else if(pathname.indexOf(`/users/${username}/projects`)>-1){
+ this.setState({menuKey:"2",route_type:undefined});
+ }else if(pathname.indexOf(`/users/${username}/notice`)>-1){
+ this.setState({menuKey:"3",route_type:undefined});
+ }else if(pathname.indexOf(`/users/${username}/devops`)>-1){
+ this.setState({menuKey:"4",route_type:undefined});
+ }else if(pathname === `/users/${username}/organizes`){
+ this.setState({menuKey:"5",route_type:undefined});
+ }else if(pathname === `/users/${username}/watchers`){
+ this.setState({menuKey:undefined,route_type:"watchers"});
+ }else if(pathname === `/users/${username}/fan_users`){
+ this.setState({menuKey:undefined,route_type:"fan_users"});
+ }else{
+ this.setState({menuKey:undefined,route_type:undefined});
+ }
+ }
+
componentDidMount = () => {
this.fetchUser();
+ const { pathname } = this.props.location;
+ this.renderPath(pathname);
};
+
componentDidUpdate=(prevProps)=>{
const { username } = this.props.match.params;
const prevUser = prevProps.match.params.username;
if(prevUser && username && prevUser !== username){
this.fetchUser();
}
+ const { pathname } = this.props.location;
+ const prevPath = prevProps.location.pathname;
+ if(prevPath && pathname && prevPath !== pathname){
+ this.renderPath(pathname);
+ }
this.props.history.listen(()=>{
if (document.body.scrollTop || document.documentElement.scrollTop > 0) {
window.scrollTo(0, 0)
@@ -89,39 +128,23 @@ class Infos extends Component {
const { notice } = this.state;
let url = `/users/${username || (current_user && current_user.login)}.json`;
- axios
- .get(url)
- .then((result) => {
- let e = result.data && result.data.undo_events;
- let p = result.data && result.data.undo_messages;
- let n = notice || pathname === `/users/${username}/notice` ;
- this.setState({
- user: result.data,
- isSpin: false,
- undo_events:n ? (e-p) : e,
- undo_messages:0,
- notice:n
- });
- })
- .catch((error) => {
- this.setState({
- isSpin: false,
- });
+ axios.get(url).then((result) => {
+ let e = result.data && result.data.undo_events;
+ let p = result.data && result.data.undo_messages;
+ let n = notice || pathname === `/users/${username}/notice` ;
+ this.setState({
+ user: result.data,
+ isSpin: false,
+ undo_events:n ? (e-p) : e,
+ undo_messages:0,
+ notice:n
});
- };
-
- change_project_type = (type) => {
- const {user} = this.state
- this.setState({
- project_type: type ,
- route_type: undefined
})
- let url = `/users/${user && user.login}`
- if (type){
- url = `/users/${user && user.login}/projects/${type}`
- }
- this.props.history.push(url)
-
+ .catch((error) => {
+ this.setState({
+ isSpin: false,
+ });
+ });
};
change_devops_type=(type)=>{
@@ -160,43 +183,50 @@ class Infos extends Component {
this.props.history.push(`/users/${user && user.login}/organizes`)
}
+ resetUser=()=>{
+ const { resetUserInfo } = this.props;
+
+ this.fetchUser();
+ resetUserInfo && resetUserInfo();
+ }
render() {
- const { current_user, mygetHelmetapi } = this.props;
+ const { current_user, mygetHelmetapi , resetUserInfo } = this.props;
const { username } = this.props.match.params;
-
- const { user, isSpin, project_type, route_type , undo_events , undo_messages } = this.state;
+ const { user, isSpin, project_type, route_type , undo_events , undo_messages , menuKey } = this.state;
return (
-
-
- {user && user.user_identity && (
-
- {user && user.user_identity}
-
- )}
-
+
+
+
+
+ {
+ user && user.gender===1?
+
+ :
+
+ }
+
+
+
+
{user && user.username}
-
+
+ {user && user.description}
+
{user && current_user && user.login === current_user.login && (
)}
-
+
{user && user.watched_count}
-
-
- {current_user && user && user.login === current_user.login ? (
-
-
-
- this.undo_link()}>
-
-
- 待办事项
-
-
- {undo_events}
-
-
-
-
-
- ):""}
-
-
-
- - this.change_project_type(undefined)}>
-
- 项目类型
-
-
- - this.change_project_type("common")}>
-
- 开源托管项目
-
- {user && user.common_projects_count}
-
-
-
- - this.change_project_type("mirror")}>
-
- 开源镜像项目
-
- {user && user.mirror_projects_count}
-
-
-
- - this.change_project_type("sync_mirror")}>
-
- 镜像托管项目
-
- {user && user.sync_mirror_projects_count}
-
-
-
-
-
- {
- current_user && current_user.login && current_user.login === username &&
-
- }
-
-
-
- this.organize_link()} >
-
-
- 组织
-
-
- {user && user.user_org_count}
-
-
-
+ {
+ user && (user.province || user.custom_department || user.email) ?
+
+ { user.province &&
{user.province}{user.city}
}
+ { user.custom_department &&
{user.custom_department}
}
+ { user.email &&
{user.email}
}
+
+ :""
+ }
+ { !route_type && menuKey &&
+
+ }
{user && (
-
-
+
+ {
+ return ;
+ }}
+ >
{
- return ;
- }}
- >
- {
- return ;
- }}
- >
- {
- return ;
- }}
- >
- {
- return ;
- }}
- >
- {
- return ;
- }}
- >
- {
- return ;
- }}
- >
- {
- return ;
- }}
- >
- {
- return ;
- }}
- >
- {
- return ;
- }}
- >
-
-
+ path="/users/:username/notice"
+ render={() => {
+ return
;
+ }}
+ >
+ {
+ return ;
+ }}
+ >
+ {
+ return ;
+ }}
+ >
+ {
+ return ;
+ }}
+ >
+ {
+ return ;
+ }}
+ >
+ {
+ return ;
+ }}
+ >
+ {
+ return ;
+ }}
+ >
+ {
+ return ;
+ }}
+ >
+
+ {
+ return ;
+ }}
+ >
+ {
+ return ;
+ }}
+ >
+ {
+ return ;
+ }}
+ >
+
)}
-
+
);
diff --git a/src/forge/users/InfosUser.js b/src/forge/users/InfosUser.js
index 3a185a786..e79e1021e 100644
--- a/src/forge/users/InfosUser.js
+++ b/src/forge/users/InfosUser.js
@@ -100,9 +100,6 @@ class InfosUser extends Component {
const {is_public} = this.state
const new_is_public = is_public === check_is_public ? undefined : check_is_public
- // this.setState({
- // is_public: new_is_public
- // })
this.state.is_public = new_is_public
this.get_projects(new_is_public);
}
@@ -176,7 +173,7 @@ class InfosUser extends Component {
return (
-
+
{
+ const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form;
+ const { username } = props && props.match && props.match.params;
+ const { user , resetUser , current_user } = props;
+
+ useEffect(()=>{
+ if(current_user && current_user.login){
+ setFieldsValue({
+ ...current_user,
+ location:current_user.province && [current_user.province,current_user.city]
+ })
+ }
+ },[current_user])
+
+ function submit() {
+ validateFields((error,values)=>{
+ if(!error){
+ submitFunc(values);
+ }
+ })
+ }
+
+ function submitFunc(values) {
+ const url = `/users/${username}.json`;
+ const params={
+ user: {
+ nickname: values.real_name,
+ user_extension_attributes: {
+ province: values.location && values.location[0],
+ city: values.location && values.location[1],
+ ...values
+ }
+ }
+ }
+ Axios.put(url,params).then(result=>{
+ if(result && result.data){
+ props.showNotification("资料修改成功!")
+ resetUser && resetUser(result.data);
+ }
+ }).catch(error=>{})
+ }
+
+ return(
+
+ {getFieldDecorator("email",{
+ rules:[{required:true,message:"请输入邮箱账号"}]
+ })(
+
+ )}
+
+
+ {getFieldDecorator("show_email",{
+ rules:[],
+ valuePropName:"checked"
+ })(
+ 在个人主页展示
+ )}
+
+
+ {getFieldDecorator("real_name",{
+ rules:[{required:true,message:"请输入姓名"}]
+ })(
+
+ )}
+
+
+
+ {getFieldDecorator("gender",{
+ rules:[{required:true,message:"请选择性别"}]
+ })(
+
+ 男
+ 女
+
+ )}
+
+
+
+ {getFieldDecorator("custom_department",{
+ rules:[{required:true,message:"请输入单位名称"}]
+ })(
+
+ )}
+
+
+ {getFieldDecorator("show_department",{
+ rules:[],
+ valuePropName:"checked"
+ })(
+ 在个人主页展示
+ )}
+
+
+ {getFieldDecorator("location",{
+ rules:[]
+ })(
+
+ )}
+
+
+ {getFieldDecorator("show_location",{
+ rules:[],
+ valuePropName:"checked"
+ })(
+ 在个人主页展示
+ )}
+
+
+ {getFieldDecorator("description",{
+ rules:[]
+ })(
+
+
+
+
+
+
+
+ )
+ })
+)
\ No newline at end of file
diff --git a/src/forge/users/Material/Index.jsx b/src/forge/users/Material/Index.jsx
new file mode 100644
index 000000000..ee0f4eec8
--- /dev/null
+++ b/src/forge/users/Material/Index.jsx
@@ -0,0 +1,50 @@
+import React , { useEffect , useState } from 'react';
+import './Index.scss';
+import { Menu } from 'antd';
+import { Link } from 'react-router-dom';
+import Base from './Base';
+import Password from './Password';
+
+function Index(props){
+ const { username } = props && props.match && props.match.params;
+ const { pathname } = props && props.location;
+ const { current_user } = props;
+
+ useEffect(()=>{
+ if((username && current_user && (current_user.login !== username))){
+ props.history.push(`/users/${username}`);
+ }
+ },[current_user,username])
+
+ const [ key , setKey ] = useState("0");
+
+ useEffect(()=>{
+ if(pathname){
+ if(pathname === `/users/${username}/info`){
+ setKey("0");
+ }else{
+ setKey("1");
+ }
+ }
+ },[pathname])
+
+
+ return(
+
+
+
+ {
+ key === "0" ?
+
+ :
+
+ }
+
+
+
+ )
+}
+export default Index;
\ No newline at end of file
diff --git a/src/forge/users/Material/Index.scss b/src/forge/users/Material/Index.scss
new file mode 100644
index 000000000..07fcc18e7
--- /dev/null
+++ b/src/forge/users/Material/Index.scss
@@ -0,0 +1,14 @@
+.formBase{
+ .ant-form-item-label{
+ width: 80px;
+ display: block;
+ }
+ .ant-form-explain{
+ position: absolute;
+ }
+}
+.formBase.passMan{
+ .ant-form-item-label{
+ width: 92px;
+ }
+}
\ No newline at end of file
diff --git a/src/forge/users/Material/Password.jsx b/src/forge/users/Material/Password.jsx
new file mode 100644
index 000000000..01dad3b74
--- /dev/null
+++ b/src/forge/users/Material/Password.jsx
@@ -0,0 +1,98 @@
+import React , { forwardRef, useState } from 'react';
+import { Form , Input , Button } from 'antd';
+import { AlignCenter } from '../../Component/layout';
+import Axios from 'axios';
+
+
+export default Form.create()(
+ forwardRef((props)=>{
+ const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form;
+ const { username } = props && props.match && props.match.params;
+ const { current_user} = props;
+
+ const [ oldPass , setOldPass ] = useState(undefined);
+ const [ oldPassRepeat , setOldPassRepeat ] = useState(undefined);
+
+ function submit() {
+ validateFields((error,values)=>{
+ if(!error){
+ submitFunc(values);
+ }
+ })
+ }
+
+ function submitFunc(values) {
+ const url = `/accounts/change_password.json`;
+ Axios.post(url,{
+ login:current_user && current_user.login,
+ ...values
+ }).then(result=>{
+ if(result && result.data){
+ props.showNotification("密码重置成功!")
+ }
+ }).catch(error=>{})
+ }
+
+ // 判断两次输入的密码是否一致
+ function checkIdentifier(rule, value, callback , inputValue){
+ if(!value){
+ callback();
+ }
+ if (value && inputValue && value !== inputValue) {
+ callback("两次输入的密码不一致");
+ }
+ callback();
+ }
+ var reg = /(?!.*\s)(?!^[\u4e00-\u9fa5]+$)(?!^[0-9]+$)(?!^[A-z]+$)(?!^[^A-z0-9]+$)^.{8,16}$/;
+
+ function checkNewPass(rule, value, callback) {
+ if(!value){
+ callback();
+ }
+ if (!reg.test(value)) {
+ callback("8-16个字符,不包含空格,必须包含数字,字母或字符至少两种");
+ }
+ callback();
+ }
+
+ return(
+
+ {getFieldDecorator("old_password",{
+ rules:[
+ {required:true,message:"请输入旧密码"},
+ {validator:(rule, value, callback)=>checkIdentifier(rule, value, callback,oldPassRepeat)}
+ ]
+ })(
+ {setOldPass(e.target.value)}}/>
+ )}
+
+
+ {getFieldDecorator("old_password_repeat",{
+ rules:[
+ {required:true,message:"请重新输入旧密码"},
+ {validator:(rule, value, callback)=>checkIdentifier(rule, value, callback,oldPass)}
+ ]
+ })(
+ {setOldPassRepeat(e.target.value)}}/>
+ )}
+
+
+ {getFieldDecorator("password",{
+ rules:[
+ {required:true,message:"请输入新密码"},
+ {validator:checkNewPass}
+ ]
+ })(
+
+ )}
+
+
+
+
+
+
+
+ )
+ })
+)
\ No newline at end of file
diff --git a/src/forge/users/Statistics/Index.jsx b/src/forge/users/Statistics/Index.jsx
new file mode 100644
index 000000000..8c946d4aa
--- /dev/null
+++ b/src/forge/users/Statistics/Index.jsx
@@ -0,0 +1,209 @@
+import React , {useEffect, useState} from 'react';
+import './Index.scss';
+import 'echarts/lib/component/tooltip';
+import 'echarts/lib/component/title';
+import 'echarts/lib/component/legend'
+import 'echarts/lib/component/markPoint';
+
+import Pie from '../Echart/Pie';
+import Cloud from '../Echart/Cloud';
+import Radar from '../Echart/Radar';
+import Round from '../Echart/Round';
+import { DatePicker } from 'antd';
+import moment from 'moment';
+
+import { FlexAJ } from '../../Component/layout';
+import Axios from 'axios';
+
+const { RangePicker } = DatePicker;
+ const dateFormat = 'YYYY-MM-DD';
+function Index(props) {
+ const username = props.match.params.username;
+ const [ dates, setDates] = useState(undefined);
+ const [ pieData, setPieData ] = useState([]);
+ const [ rDates, setRDates ] = useState(undefined);
+ const [ radarData, setRadarData ] = useState([]);
+
+ const [ topThree , setTopThree] = useState(undefined);
+ const [ percentData , setPercentData ] = useState(undefined);
+
+ const [ cData, setCData ] = useState(undefined);
+ const [ cloudData, setCloudData ] = useState(undefined);
+
+ const disabledDate = current => {
+ return current && current > moment().endOf('day');
+ };
+
+ // 获取角色定位接口数据
+ useEffect(()=>{
+ getRoleSta();
+ },[dates])
+
+ function getRoleSta() {
+ const url = `/users/${username}/statistics/role.json`;
+ let b = (dates && dates.length > 0 && dates[0]) ? Date.parse(dates[0])/1000 : undefined;
+ let e = (dates && dates.length > 0 && dates[1]) ? Date.parse(dates[1])/1000 : undefined;
+ Axios.get(url,{
+ params:{
+ start_time:b,
+ end_time:e
+ }
+ }).then(result=>{
+ if(result && result.data){
+ setPieData(result.data.role);
+ }
+ }).catch(error=>{})
+ }
+
+
+ // 获取开发能力接口数据
+ useEffect(()=>{
+ getRadarSta();
+ },[rDates])
+
+ function getRadarSta() {
+ const url = `/users/${username}/statistics/develop.json`;
+ let b = (rDates && rDates.length > 0 && rDates[0]) ? Date.parse(rDates[0])/1000 : undefined;
+ let e = (rDates && rDates.length > 0 && rDates[1]) ? Date.parse(rDates[1])/1000 : undefined;
+ Axios.get(url,{
+ params:{
+ start_time:b,
+ end_time:e
+ }
+ }).then(result=>{
+ if(result && result.data){
+ setRadarData(result.data);
+ let score = result.data.user && result.data.user.each_language_score;
+ if(score){
+ var sortData = [];
+ for (var item in score) {
+ sortData.push([item, score[item]])
+ }
+ sortData.sort(function(a, b) {
+ return b[1] - a[1];
+ });
+ setTopThree(sortData.slice(0,3));
+ }
+
+ let percent = result.data.user && result.data.user.languages_percent;
+ let arr = [];
+ Object.keys(percent).map((item,key)=>{
+ arr.push({name:item,p:parseFloat(percent[item]*100).toFixed(1),color:getColor()});
+ })
+ setPercentData(arr);
+ }
+ }).catch(error=>{})
+ }
+ function getColor(){
+ let str = "#";
+ let arr = ["1","2","3","4","4","5","6","7","8","9","a","b","c","d","e","f"];
+ for(var i=0;i<6;i++){
+ let num = parseInt(Math.random() * 16,0);
+ str+=arr[num];
+ }
+ return str;
+ }
+
+ //用户专业定位
+ useEffect(()=>{
+ getCloudSta();
+ },[cData])
+
+ function getCloudSta() {
+ const url = `/users/${username}/statistics/major.json`;
+ let b = (cData && cData.length > 0 && cData[0]) ? Date.parse(cData[0])/1000 : undefined;
+ let e = (cData && cData.length > 0 && cData[1]) ? Date.parse(cData[1])/1000 : undefined;
+ Axios.get(url,{
+ params:{
+ start_time:b,
+ end_time:e
+ }
+ }).then(result=>{
+ if(result && result.data){
+ setCloudData(result.data);
+ }
+ }).catch(error=>{})
+ }
+
+ return(
+
+
+
+ 开发能力
+ {setRDates(dateString)}}
+ format={dateFormat}
+ />
+
+
+
从五个维度刻画你的开发能力:语言能力、影响力、贡献度、活跃度、项目经验,同时可以查看社区平均数据。
+
+ {
+ topThree && topThree.length > 0 &&
+
+
+ { topThree[1] && }
+ { topThree[2] && }
+
+ }
+ {
+ percentData &&
+
+
+ {
+ percentData.map((i,k)=>{
+ return(
+
+ )
+ })
+ }
+
+
+ {
+ percentData.map((i,k)=>{
+ return(
+
+ {i.name}
+ {`${i.p}%`}
+
+ )
+ })
+ }
+
+
+ }
+
+
+
+
+ 角色定位
+ {setDates(dateString)}}
+ format={dateFormat}
+ />
+
+
+
根据你在项目开发过程中的工作,对你在项目中扮演的角色进行定位,包括:创建者、管理者、开发者、测试者、文档工作者等。
+
+
+
+
+
+ 专业定位
+ {setCData(dateString)}}
+ format={dateFormat}
+ />
+
+
+
展示你擅长、关注、感兴趣的专业范围,通过你参与项目、收藏项目、关注项目、复刻项目等数据来统计。
+
+
+
+
+ )
+}
+export default Index;
\ No newline at end of file
diff --git a/src/forge/users/Statistics/Index.scss b/src/forge/users/Statistics/Index.scss
new file mode 100644
index 000000000..4ea048bfa
--- /dev/null
+++ b/src/forge/users/Statistics/Index.scss
@@ -0,0 +1,64 @@
+.boxes{
+ padding:15px 0px;
+ .roundBox{
+ margin:20px auto;
+ display: flex;
+ justify-content: center;
+ & >div{
+ margin:0px 30px;
+ }
+ }
+ .pBox{
+ width: 400px;
+ margin:40px auto 20px;
+ .progress{
+ width: 360px;
+ margin:0px auto;
+ display: flex;
+ background-color: #fafafa;
+ border-radius: 10px;
+ height: 7px;
+ span:first-child {
+ border-radius: 10px 0px 0px 10px;
+ }
+ span:last-child {
+ border-radius: 0px 10px 10px 0px;
+ }
+ }
+ .progresstip {
+ margin-top: 15px;
+ flex-wrap: wrap;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: justify;
+ -webkit-justify-content: space-between;
+ -ms-flex-pack: justify;
+ justify-content: space-between;
+ & > span {
+ padding-left: 15px;
+ position: relative;
+ min-width: 33%;
+ display: flex;
+ justify-content: flex-start;
+ i.zero {
+ display: block;
+ border-radius: 50%;
+ height: 8px;
+ width: 8px;
+ margin-top:10px;
+ margin-right: 5px;
+ }
+ span {
+ color: #666;
+ }
+ span:last-child {
+ color: #999;
+ margin-left: 5px;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/forge/users/Team.jsx b/src/forge/users/Team.jsx
index a0b70f2f5..9378106e3 100644
--- a/src/forge/users/Team.jsx
+++ b/src/forge/users/Team.jsx
@@ -1,7 +1,6 @@
import React , { useEffect , useState } from 'react';
import { Dropdown, Menu , Pagination } from 'antd';
-import { Link } from 'react-router-dom';
import Search from '../Component/Search';
import Item from './Team-item';
import Nodata from '../Nodata';
@@ -15,7 +14,7 @@ function Team(props){
const [ sort_direction , setSort_direction ] = useState("asc");
const [ sort_by ,setSort_by ] = useState("created_at");
const [ search ,setSearch ] = useState(undefined);
- console.log(props);
+
const { username } = props.match.params;
useEffect(()=>{
if(username){
@@ -47,14 +46,23 @@ function Team(props){
用户数排序
)
+
+ function newFunc() {
+ const { checkIfLogin , showLoginDialog } = props;
+ if(checkIfLogin()){
+ props.history.push(`/organize/new`);
+ }else{
+ showLoginDialog && showLoginDialog();
+ }
+ }
return(
- setSearch(e.target.value)} placeholder="请输入项目名称关键字进行搜索" onSearch={onSearch}/>
+ setSearch(e.target.value)} placeholder="请输入组织名称关键字进行搜索" onSearch={onSearch}/>
- 新建组织
+ 新建组织
排序
diff --git a/src/forge/users/common_lists.js b/src/forge/users/common_lists.js
index 5e238333f..9270d8be1 100644
--- a/src/forge/users/common_lists.js
+++ b/src/forge/users/common_lists.js
@@ -1,6 +1,6 @@
import React, { Component } from "react";
import { Input, Spin, Pagination } from "antd";
-
+import { Link } from 'react-router-dom';
import axios from "axios";
import Nodata from "../Nodata";
import UserList from "../UsersList/user_list";
@@ -29,26 +29,24 @@ class CommonList extends Component {
isSpin: true,
});
axios.get(url, {
- params: {
- page,
- limit,
- search,
- },
- })
- .then((result) => {
- if (result) {
- this.setState({
- users: result.data.users,
- total: result.data.count,
- isSpin: false,
- });
- }
- })
- .catch((error) => {
+ params: {
+ page,
+ limit,
+ search,
+ },
+ }).then((result) => {
+ if (result && result.data) {
this.setState({
- isSpin: false,
+ users: result.data.users,
+ total: result.data.count,
+ isSpin: false
});
+ }
+ }).catch((error) => {
+ this.setState({
+ isSpin: false,
});
+ });
};
//切换页数
@@ -63,6 +61,12 @@ class CommonList extends Component {
});
};
+ successFunc=()=>{
+ const { fetchUser } = this.props;
+ this.get_watchers();
+ fetchUser && fetchUser();
+ }
+
render() {
const { users, isSpin, total, search, limit, page } = this.state;
const { userType, login, current_user } = this.props;
@@ -85,9 +89,9 @@ class CommonList extends Component {
return (
-
+
-
{userType === "watchers" ? `${title_type}关注的` : `关注${title_type}的`}
+
{userType === "watch_users" ? `${title_type}关注的` : `关注${title_type}的`}
0 ? (
-
+
) : (
diff --git a/src/forge/users/fan_users.js b/src/forge/users/fan_users.js
index cf93cdb41..c70630b17 100644
--- a/src/forge/users/fan_users.js
+++ b/src/forge/users/fan_users.js
@@ -3,10 +3,10 @@ import CommonLists from "./common_lists"
class FanUsers extends Component {
render() {
- const {user, current_user} = this.props
+ const {user, current_user , fetchUser} = this.props
return (
- {user && user.login && }
+ {user && user.login && }
);
}
diff --git a/src/forge/users/new_user.css b/src/forge/users/new_user.css
index 27898ae0c..2eb109122 100644
--- a/src/forge/users/new_user.css
+++ b/src/forge/users/new_user.css
@@ -10,7 +10,7 @@
}
.list-left{
width: 26%;
- padding-right: 20px;
+ padding-right: 30px;
box-sizing: border-box;
margin-bottom: 20px;
}
@@ -22,7 +22,7 @@
width:74%;
background: #fff;
padding:0px !important;
- border:1px solid #eee;
+ border:none!important;
}
.text-center{text-align: center;}
@@ -30,7 +30,7 @@
.position-relative{position: relative;}
.mr-5{margin-right: 5px;}
a.text-button-grey{
- color: rgba(0, 0, 0, 0.65)
+ color: #fff;
}
.user-info-star-button{margin: 20px 50px 0 50px}
.list-l-p{
diff --git a/src/forge/users/watch_users.js b/src/forge/users/watch_users.js
index 0e22eba28..fe8a79267 100644
--- a/src/forge/users/watch_users.js
+++ b/src/forge/users/watch_users.js
@@ -2,10 +2,10 @@ import React, { Component } from "react";
import CommonLists from "./common_lists"
class WatcherUsers extends Component {
render() {
- const {user, current_user} = this.props
+ const {user, current_user , fetchUser } = this.props;
return (
- {user && user.login && }
+ {user && user.login && }
);
}
diff --git a/src/modules/tpm/TPMIndexHOC.js b/src/modules/tpm/TPMIndexHOC.js
index 773c07ca3..b5c99ad62 100644
--- a/src/modules/tpm/TPMIndexHOC.js
+++ b/src/modules/tpm/TPMIndexHOC.js
@@ -210,6 +210,7 @@ export function TPMIndexHOC(WrappedComponent) {
const common = {
showLoginDialog: this.showLoginDialog,
checkIfLogin: this.checkIfLogin,
+ resetUserInfo:this.fetchUsers
};
return (