项目列表页面

This commit is contained in:
caishi 2021-07-15 15:20:13 +08:00
parent 27883febe1
commit 7e6bb2ada9
13 changed files with 428 additions and 72 deletions

View File

@ -0,0 +1,40 @@
import React , { FC , useEffect } from 'react';
import {
connect,
ProjectHomeState,
Dispatch
} from 'umi';
import styles from './index.less';
import Item from './item';
export interface PageProps{
projectHome:ProjectHomeState,
dispatch:Dispatch
}
const Categore:FC<PageProps>=({
projectHome,
dispatch
})=>{
useEffect(()=>{
dispatch({
type:"projectHome/getCategoryList",
payload:{}
})
},[projectHome.name])
if(projectHome.categoryList && projectHome.categoryList.length>0){
return(
<div className={styles.leftListItems}>
<p className="leftTitle"><i className="iconfont icon-xiangmuleibie"></i></p>
<Item list={projectHome.categoryList} />
</div>
)
}else{
return <></>
}
}
export default connect(
({projectHome}:{projectHome:ProjectHomeState})=>({projectHome})
)(Categore)

View File

@ -0,0 +1,108 @@
.listbox{
display: flex;
}
.boxItem{
width:208px;
margin-right: 30px;
outline: none;
box-sizing: border-box;
background-color: #fff;
border-radius: 4px;
cursor: pointer;
border: 1px solid #eee;
div[class~='mainInfo']{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 160px;
border-bottom: 1px solid #eee;
padding: 20px;
box-sizing: border-box;
img{
width: 50px;
height: 50px;
border-radius: 50%;
}
span[class~="name"]{
margin-top: 12px;
color: #333;
font-size: 16px;
height: 22px;
line-height: 22px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 100%;
}
span[class~="author"]{
font-size: 13px;
color: #666;
height: 18px;
line-height: 18px;
margin-top: 12px;
}
}
div[class~="baseInfo"]{
padding: 18px 15px;
display: flex;
font-size: 12px;
color: #888;
justify-content: space-between;
}
}
.leftListItems{
border:1px solid #eee;
margin-bottom: 15px;
p[class~="leftTitle"]{
height: 60px;
line-height: 60px;
border-bottom: 1px solid #eee;
padding:0px 20px;
margin-bottom: 0px;
font-size: 16px;
i{
margin-right: 5px;
color: #666;
}
}
div[class~="ant-list"]{
font-size: 16px;
li[class~="ant-list-item"]{
height: 60px;
line-height: 60px;
padding-right: 20px;
margin-left: 20px;
cursor: pointer;
}
}
}
.rightListData{
padding:0px 20px!important;
li[class~="ant-list-item"]{
padding:22px 0px;
align-items: flex-start;
&>a>img{
width: 60px;
height: 60px;
border-radius: 50%;
margin-right: 18px;
}
&>div{
flex:1;
}
a[class~="dataTitle"]{
font-size: 18px;
max-width: 470px;
display: block;
color: #333;
}
div[class~="dataDesc"]{
max-height: 44px;
line-height: 22px;
word-break: break-all;
word-wrap: break-word;
color: #666;
}
}
}

View File

@ -0,0 +1,30 @@
import React , { FC } from 'react';
import { List } from 'antd';
interface Props{
list:any
}
const Item:FC<Props>=({list})=>{
if(list && list.length>0){
return(
<List>
{
list.map(function(
i:any,k:any
){
return(
<List.Item key={k}>
<span>{i.name}</span>
<span className="blue">{i.projects_count}</span>
</List.Item>
)
})
}
</List>
)
}else{
return <></>
}
}
export default Item;

View File

@ -0,0 +1,73 @@
import React , { FC } from 'react';
import styles from './index.less';
import {
Link
}from 'umi';
import { List , Tooltip } from 'antd';
import ENV from '@/utils/env';
interface Props{
list:any
}
const ListItem:FC<Props>=({list})=>{
if(list &&ListItem.length>0){
return(
<List className={styles.rightListData}>
{
list.map(function(i:any,k:number){
return(
<List.Item key={k}>
{
i.platform === "educoder" ?
<a href="javascript:void(0)" style={{cursor:"default"}}>
<img alt="" src={i.author && i.author.image_url} />
</a>
:
<Link to={i.author && (i.author.type === "Organization" ? `/organize/${i.author.login}`:`/users/${i.author.login}`)}>
<img src={`${ENV.IMG_SERVER}/${i.author && i.author.image_url}`} />
</Link>
}
<div>
<div className="alignCenterJSB mb10">
<span className="alignCenter">
<Link to={`/projects/${i.author && i.author.login}/${i.identifier}`} title={`${i.author && i.author.name}/${i.name}`} className="dataTitle hide">{i.author && i.author.name}/{i.name}</Link>
{ !i.is_public && <span className="privateTag ml10"></span> }
{ i.forked_from_project_id ?<i className="iconfont icon-fork font18 orange ml5" />:""}
{
i.type && i.type === 2 ?
<Tooltip title="该项目是一个镜像">
<i className="iconfont icon-banbenku font20 green ml5" />
</Tooltip>:""
}
{ i.type && i.type === 1 ?<i className="iconfont icon-jingxiang font18 green ml5" />:""}
</span>
<span className="alignCenter">
{i.praises_count && i.praises_count>0 ?
<span className="pariseTag ml15"><i className="iconfont icon-shoucangyiji mr3 font14 yellow"></i> {i.praises_count}</span>
:""}
{
i.forked_count && i.forked_count>0 ?
<span className="forkTag ml15"><i className="iconfont icon-fork mr3 font16 blue" />fork {i.forked_count}</span>
:""
}
</span>
</div>
<div className="hide2 dataDesc">{i.description}</div>
<div className="c-g-9 mt10">
<span className="mr30">{i.time_ago}</span>
<span>{i.language && i.language.name}</span>
</div>
</div>
</List.Item>
)
})
}
</List>
)
}else{
return <></>
}
}
export default ListItem

View File

@ -0,0 +1,42 @@
import React , { FC , useEffect , useState } from 'react';
import {
connect,
ProjectHomeState,
Dispatch
}
from 'umi';
import { List } from 'antd';
import styles from './index.less';
import Item from './item';
interface PageProps{
projectHome:ProjectHomeState,
dispatch:Dispatch
}
const type:FC<PageProps>=({
projectHome,
dispatch
})=>{
useEffect(()=>{
dispatch({
type:"projectHome/getGroupTypeList",
payload:{}
})
},[projectHome.name])
if(projectHome.typeList && projectHome.typeList.length>0){
return(
<div className={styles.leftListItems}>
<p className="leftTitle"><i className="iconfont icon-xiangmuleixing"></i></p>
<Item list={projectHome.typeList} />
</div>
)
}else{
return <></>
}
}
export default connect(
({projectHome}:{projectHome:ProjectHomeState})=>({projectHome}))(type)

View File

@ -1,53 +0,0 @@
.listbox{
display: flex;
}
.boxItem{
width:208px;
margin-right: 30px;
outline: none;
box-sizing: border-box;
background-color: #fff;
border-radius: 10px;
cursor: pointer;
border: 1px solid #eee;
div[class~='mainInfo']{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 160px;
border-bottom: 1px solid #eee;
padding: 20px;
box-sizing: border-box;
img{
width: 50px;
height: 50px;
border-radius: 50%;
}
span[class~="name"]{
margin-top: 12px;
color: #333;
font-size: 16px;
height: 22px;
line-height: 22px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
max-width: 100%;
}
span[class~="author"]{
font-size: 13px;
color: #666;
height: 18px;
line-height: 18px;
margin-top: 12px;
}
}
div[class~="baseInfo"]{
padding: 18px 15px;
display: flex;
font-size: 12px;
color: #888;
justify-content: space-between;
}
}

View File

@ -1,10 +1,18 @@
import { Effect , Reducer , Subscription } from 'umi';
import { getProjectList , getRecommand } from '@/service/projectHome';
import {
getProjectList ,
getRecommand ,
getGroupType ,
getcategory
} from '@/service/projectHome';
export interface ProjectHomeState{
name:string,
projectList?:any,
recommandList?:any
total:number,
recommandList?:any,
typeList?:any,
categoryList?:any
}
export interface ProjectHomeType{
@ -12,7 +20,9 @@ export interface ProjectHomeType{
state:ProjectHomeState,
effects:{
getProjectList:Effect,
getRecommandList:Effect
getRecommandList:Effect,
getGroupTypeList:Effect,
getCategoryList:Effect
},
reducers:{
save:Reducer<ProjectHomeState>
@ -24,6 +34,7 @@ const ProjectHomeModel:ProjectHomeType = {
namespace:"projectHome",
state:{
name:"项目列表",
total:0,
projectList:{}
},
effects:{
@ -32,7 +43,7 @@ const ProjectHomeModel:ProjectHomeType = {
const response = yield call(getProjectList,params);
yield put({
type: 'save',
payload: { projectList: response },
payload: { projectList: response.projects , total: response.total_count},
});
},
*getRecommandList({payload},{call,put}){
@ -41,6 +52,20 @@ const ProjectHomeModel:ProjectHomeType = {
type:"save",
payload:{ recommandList : response}
})
},
*getGroupTypeList({payload},{call,put}){
const response = yield call(getGroupType,payload);
yield put({
type:"save",
payload:{ typeList : response}
})
},
*getCategoryList({payload},{call,put}){
const response = yield call(getcategory,payload);
yield put({
type:"save",
payload:{ categoryList : response}
})
}
},
reducers:{

View File

@ -1,5 +1,17 @@
.slickBox {
}
.boxwidth{
padding:20px 0px;
}
.datas{
display: flex;
justify-content: space-between;
padding:20px 0px;
align-items: flex-start;
div[class=~"leftList"]{
width: 26%;
}
div[class=~"rightList"]{
width:72%;
border:1px solid #eee;
}
}

View File

@ -6,8 +6,11 @@ import { Loading ,
Dispatch,
ProjectHomeState
} from 'umi';
import Recommand from '@/components/Recommand';
import Recommand from '@/components/ProjectHome/recommand';
import Type from '@/components/ProjectHome/type';
import Category from '@/components/ProjectHome/category';
import banner from '@/images/banner.jpg';
import ListItem from '@/components/ProjectHome/listItem';
const setting={
dots: true,
@ -42,12 +45,24 @@ const Projectlist:FC<PageProps>=({
payload:{page,limit}
})
},[page])
return (
<div>
<img src={banner} width="100%"/>
<div className={`${styles.boxwidth} boxWidth`}>
<Recommand />
<div className={styles.datas}>
<div className={"leftList"}>
<Type />
<Category />
</div>
<div className={"rightList"}>
{
projectHome.projectList && projectHome.projectList.length>0 ?
<ListItem list={projectHome.projectList} />
:""
}
</div>
</div>
</div>
</div>
);

View File

@ -5,18 +5,12 @@ export async function getProjectList(params: any) {
return get('/api/projects.json' , params );
}
// 项目类型
export async function getGroupTypeList(params: any) {
return Fetch('/api/projects/group_type_list.json', {
method: 'get',
body: params ,
});
export async function getGroupType(params: any) {
return get('/api/projects/group_type_list.json', params );
}
// 项目类别
export async function getGroupList(params: any) {
return Fetch('/api/project_categories/group_list.json', {
method: 'get',
body: params ,
});
export async function getcategory(params: any) {
return get('/api/project_categories/group_list.json',params);
}
// 项目语言
export async function getLanguages(params: any) {

View File

@ -4,10 +4,56 @@
[class*=' icon-'] {
font-size: 16px;
}
.blue{
color: @primary;
}
.orange{
color: @light-orange;
}
.green{
color: @green-29b;
}
.yellow{
color: @yellow;
}
.font12 {
font-size: 12px;
}
.privateTag {
display: inline-block;
padding: 0px 6px;
border-radius: 12px;
border: 1px solid @green-29b;
height: 18px;
line-height: 18px;
font-size: 12px;
color: @green-29b;
}
.pariseTag{
padding: 0px 10px;
border-radius: 15px;
background: @little-orange;
color: #333;
height: 24px;
line-height: 24px;
display: block;
font-size: 12px;
display: -ms-flexbox;
display: flex;
}
.forkTag{
padding: 0px 10px;
border-radius: 15px;
background: @little-blue;
color: #333;
height: 24px;
line-height: 24px;
display: block;
font-size: 12px;
display: -ms-flexbox;
display: flex;
}
.font13 {
font-size: 13px;
@ -322,3 +368,24 @@
width: 1200px;
margin:0px auto;
}
.hide{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.hide2{
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.alignCenter{
display: flex;
align-items: center;
}
.alignCenterJSB{
display: flex;
align-items: center;
justify-content: space-between;
}

View File

@ -15,20 +15,23 @@
@cyan: #006b75;
@grey-ede: #ededed;
// @light-green: #7ad58b;
@light-orange: #e99695;
@light-orange: #ff6800;
@light-blue-purple: #5e5fb9;
@light-blue: #84b6eb;
@little-blue:#EBF4FE;
@sky-blue: #f4faff;
@cyan-blue: #18d0e7;
@brilliant-blue: #aed5ff;
@light-pink: #fc2b6a;
@orange: #ff6800;
@yellow:#ffc14b;
@purple-8C1: #8c18ff;
@orange-ff9: #ff954c;
@orange-ff7: #ff7500;
@little-orange:#FFF3DC;
@red-ee4: #ee4a1f;