数据集

This commit is contained in:
caishi 2024-04-07 09:32:53 +08:00
parent 0f3d4532e5
commit 4bd0d67f87
11 changed files with 428 additions and 31 deletions

View File

@ -3373,8 +3373,8 @@ a.edu-greyline-btn:hover {
.defalutSubmitbtn {
display: block;
border: 1px solid #4CACFF;
background-color: #4CACFF;
border: 1px solid #466aff;
background-color: #466aff;
color: #fff !important;
width: 120px;
text-align: center;
@ -3382,7 +3382,6 @@ a.edu-greyline-btn:hover {
border-radius: 2px;
width: 130px;
height: 40px;
background: rgba(76, 172, 255, 1);
border-radius: 4px;
font-size: 16px;
font-family: MicrosoftYaHei;

View File

@ -1,63 +1,130 @@
import React, { useState , useEffect } from 'react';
import { Button , Table } from 'antd';
import { getImageUrl } from 'educoder';
import NewModal from './component/new';
import { Link } from 'react-router-dom';
import "./index.scss";
import axios from 'axios';
function Index(){
function Index(props){
const { project , match } =props;
const { owner ,projectsId } = match && match.params;
const [ dataSource , setDataSource ] = useState([]);
const [ empty , setEmpty ] = useState(project && (!project.has_dataset));
const [ total , setTotal ] = useState(0);
const [ page , setPage ] = useState(1);
const [ visible , setVisible ] = useState(false);
const [ detail , setDetail ] = useState({});
const pageSize = 20;
useEffect(()=>{
if(!empty){
Init();
}
},[empty,page])
function Init(){
const url = `/v1/${owner}/${projectsId}/dataset`;
axios.get(url,{
params:{
page,limit:pageSize
}
}).then((result) => {
if (result) {
setDetail(result.data);
setDataSource(result.data && result.data.attachments);
setTotal(result.data.attachment_total_count);
}
}).catch((error) => { })
}
const columns=[
{
title:"文件名称",
dataIndex:"name",
dataIndex:"title",
key:1,
ellipsis:true,
width:"25%"
},
{
title:"描述",
dataIndex:"desc",
dataIndex:"description",
key:2,
ellipsis:true,
width:"25%"
width:"30%"
},
{
title:"创建者",
dataIndex:"creator",
key:3,
width:"10%"
width:"10%",
render:(value,item)=>{
return <img src={getImageUrl(`/${value.image_url}`)} alt="" style={{borderRadius:"50%"}} width="32px" height="32px" />
}
},
{
title:"上传时间",
dataIndex:"uploadTime",
dataIndex:"created_on",
key:4,
width:"15%"
},
{
title:"大小",
dataIndex:"size",
dataIndex:"filesize",
key:5,
width:"10%"
},
{
title:"操作",
dataIndex:"operate",
dataIndex:"url",
key:6,
width:"10%",
render:(value,item)=>{
return <a href={value} className="color-blue">下载</a>
}
},
]
//
function addFunc(){
setEmpty(false);
setVisible(false);
detail && detail.id && Init();
}
return(
<div className={`dataset`}>
<NewModal visible={visible} detail={detail} owner={owner} repo={projectsId} onCancel={()=>setVisible(false)} onOk={addFunc}/>
<div className={`mnistData`}>
<div>
<p className="font-17">MNISTData_mindspore</p>
<p>MNISTData数据集是由10类28*28的灰度图片组成训练数据集包含60000张图片测试数据集包含10000张图片</p>
</div>
<div>
<Button type="primary" ghost><i className="iconfont icon-a-bianji12 color-blue mr5 font-12"></i>编辑</Button>
<Button type="primary" className="ml20"><i className="iconfont icon-a-shangchuan2x color-white mr5 font-13"></i>上传文件</Button>
</div>
{empty ?
<span className="font-16">数据集</span>
:
<React.Fragment>
<div>
<p className="font-16 weight500">{detail.title}</p>
<p>{detail.description}</p>
</div>
<div className="df">
<Button type="primary" ghost onClick={()=>{setVisible(true)}}><i className="iconfont icon-a-bianji12 color-blue mr5 font-12"></i>编辑</Button>
<Link className="ml20 operateButton" to={`/${owner}/${projectsId}/dataset/upload`}><i className="iconfont icon-a-shangchuan2x color-white mr5 font-13"></i>上传文件</Link>
</div>
</React.Fragment>
}
</div>
<Table
columns={columns}
/>
{
empty?
<div className={"emtpyData"}>
<img src={require('./image/empty.png')} alt="" width="68px"/>
<span className="font-22 weight400 color-grey-3">暂无数据集</span>
<p className="mt25 font-15 color-grey-6 weight400">我们非常欢迎您创建并分享您的数据集以便与其他用户共同促进开源社区的发展</p>
<Button type="primary" className="mt15" onClick={()=>{setVisible(true)}}>创建数据集</Button>
</div>
:
<Table
className={`datasetTable`}
columns={columns}
dataSource={dataSource}
pagination={{total,pageSize,current:page,hideOnSinglePage:true,onChange:(p)=>setPage(p)}}
/>
}
</div>
)
}

View File

@ -0,0 +1,155 @@
import React, { useEffect, useState } from 'react';
import { Modal ,Form ,Input , AutoComplete , Button , Select } from 'antd';
import '../index.scss';
import axios from 'axios';
const { TextArea } = Input;
const Option = Select.Option;
function New(props){
const { form , visible , onCancel , onOk , owner , repo , detail } = props;
const [ licenseId , setLicenseId ] =useState(undefined);
const [ licensesList , setLicensesList] =useState([]);
const [ filterLicensesList , setFilterLicensesList ] =useState([]);
const { getFieldDecorator , setFieldsValue } = form;
useEffect(()=>{
if(detail && detail.id){
setFieldsValue({...detail,license_id:detail.license_name});
setLicenseId(detail.license_id);
}
},[detail])
useEffect(()=>{
getLicenses();
},[])
function getLicenses(){
const url = `/licenses.json`
axios.get(url).then((result) => {
if (result) {
setLicensesList(result.data.licenses);
setFilterLicensesList(result.data.licenses);
}
}).catch((error) => { })
}
function submit(){
form.validateFields((err, values) => {
if(!err){
const url = `/v1/${owner}/${repo}/dataset.json`;
if(detail && detail.id){
axios.put(url,{
...values,license_id:licenseId
}).then((result) => {
if (result) {
onOk && onOk();
}
}).catch((error) => { })
}else{
axios.post(url,{
...values,license_id:licenseId
}).then((result) => {
if (result) {
onOk && onOk();
}
}).catch((error) => { })
}
}
})
}
function ChangePlatform(value){
let _data = [];
if (licensesList.length>0) {
_data = licensesList.filter(item => item.name.toLowerCase().indexOf(value.toLowerCase()) > -1);
}
setFilterLicensesList(_data);
}
function checkId(rule, value, callback, list, title){
let filter = list.filter(item => item.name === value);
if(!value){
callback();
}
if (filter && filter.length > 0) {
callback();
} else {
callback('请在下拉选项中选择正确的' + title + "!");
}
callback();
}
return(
<Modal
title={`${detail && detail.id?"编辑":"新建"}数据集`}
width="648px"
visible={visible}
footer={null}
className="newBoxForm"
centered={true}
closable={true}
onCancel={onCancel}
>
<Form>
<Form.Item label="名称">
{getFieldDecorator('title', {
rules: [
{
required:true,
message:"请输入数据集名称"
}
],
})(
<Input placeholder="请输入数据集名称" />,
)}
</Form.Item>
<Form.Item label="开源许可证">
{getFieldDecorator('license_id', {
rules: [{
validator: (rule, value, callback) => checkId(rule, value, callback, licensesList, '开源许可证')
}],
})(
<AutoComplete
placeholder="请选择开源许可证"
onChange={ChangePlatform}
className="plateAutoComplete"
onSelect={(e,e1)=>{e1.props && setLicenseId(e1.props.id)}}
>
{
filterLicensesList && filterLicensesList.map((item) => (
<Option key={item.id} value={item.name} id={item.id}>
{item.name}
</Option>
))
}
</AutoComplete>
)}
</Form.Item>
<Form.Item label="描述">
{getFieldDecorator('description', {
rules: [
{
required:true,
message:"请输入描述内容"
}
]})(
<TextArea placeholder="请输入描述内容" autosize={{ minRows: 5, maxRows: 5 }} showCount/>,
)}
</Form.Item>
<Form.Item label="研究论文">
{getFieldDecorator('paper_content', {rules:[]})(
<TextArea placeholder="请输入研究论文" autosize={{ minRows: 5, maxRows: 5 }} showCount/>,
)}
</Form.Item>
<div className="center">
<Button style={{width:"95px"}} onClick={onCancel}>取消</Button>
<Button type="primary" className="ml20" style={{width:"95px"}} onClick={submit}>确定</Button>
</div>
</Form>
</Modal>
)
}
export default Form.create({ name: 'New' })(New);;

View File

@ -0,0 +1,111 @@
import React, { useEffect, useState } from 'react';
import { Upload ,Form ,Input , Button } from 'antd';
import '../index.scss';
import { Link } from 'react-router-dom';
import axios from 'axios';
const { Dragger } = Upload;
const { TextArea } = Input;
function UploadModal(props){
const { match , form ,history } =props;
const { owner ,projectsId } = match && match.params;
const [fileList, setFileList] = useState([]);
const [ detail , setDetail ] = useState({});
const [ loading , setLoading ] = useState(false);
const { getFieldDecorator } = form;
useEffect(()=>{
Init();
},[])
function Init(){
const url = `/v1/${owner}/${projectsId}/dataset`;
axios.get(url).then((result) => {
if (result) {
setDetail(result.data);
}
}).catch((error) => { })
}
function submit(){
form.validateFields((err, values) => {
if(!err){
const url = `/attachments.json`;
const { description ,files } = values;
setLoading(true);
const formData = new FormData();
formData.append("container_type","ProjectDataset");
formData.append("description",description);
formData.append("container_id",detail && detail.id);
formData.append("file",files.file);
const config = {
headers: { "Content-Type": "multipart/form-data" }
};
axios.post(url,formData,config).then((result) => {
if (result) {
setLoading(false);
history.push(`/${owner}/${projectsId}/dataset`);
}
}).catch((error) => { })
}
})
}
const upload= {
name: 'file',
multiple: false,
maxCount:1,
beforeUpload: file => {
setFileList([file]);
return false;
},
onRemove: file => {
const index = fileList.indexOf(file);
const newFileList = fileList.slice();
newFileList.splice(index, 1);
setFileList(newFileList);
},
fileList,
};
return(
<div className={`dataset`}>
<p className="font-18 fileTitle">上传数据集文件</p>
<Form className="newBoxForm">
<Form.Item label="文件描述">
{getFieldDecorator('description', {
rules: [
{
required:true,
message:"请输入文件描述"
}
],
})(
<TextArea autosize={{minRows:5,maxRows:5}} placeholder="描述字数不超过255个字符" maxLength={255} />,
)}
</Form.Item>
<Form.Item label="数据上传">
{getFieldDecorator('files', {
rules: [
{
required:true,
message:"请上传文件"
}
],
})(
<Dragger {...upload} className={"drag"}>
<p className="ant-upload-hint font-15">点击添加文件或直接拖拽文件到此处</p>
</Dragger>,
)}
</Form.Item>
<div>
<Link className="btn-83" to={`/${owner}/${projectsId}/dataset`}>取消</Link>
<Button loading={loading} type="primary" className="ml5" style={{width:"95px"}} onClick={submit}>确定</Button>
</div>
</Form>
</div>
)
}
export default Form.create({ name: 'UploadModal' })(UploadModal);;

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -20,4 +20,43 @@
}
}
}
.datasetTable{
.ant-table-thead > tr > th{
background-color: #fff;
}
}
.emtpyData{
background: #FAFCFF;
border-radius: 4px 4px 0px 0px;
min-height: 356px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-top: 25px;
}
}
.newBoxForm{
.ant-row.ant-form-item{
margin-bottom: 20px!important;
position: relative;
}
.ant-col.ant-form-item-label{
line-height: unset;
font-weight: 400;
font-size: 15px;
color: #4C5B76;
}
.ant-form-explain{
position: absolute;
}
}
.fileTitle{
line-height: 25px;
padding-bottom: 22px;
margin-bottom: 15px!important;
border-bottom:1px solid rgba(167,178,194,0.44);
}
.drag{
height: 110px!important;
}

View File

@ -103,6 +103,10 @@ const DataSetIndex = Loadable({
loader: () => import('../Dataset/Index'),
loading: Loading,
})
const DataSetUpload = Loadable({
loader: () => import('../Dataset/component/uploadModal'),
loading: Loading,
})
const DevAbout = Loadable({
loader: () => import('../About/Index'),
loading: Loading,
@ -156,6 +160,8 @@ function checkPathname(projectsId, owner, pathname) {
name = "activity"
} else if (url.indexOf("/settings") > -1) {
name = "settings"
} else if (url.indexOf("/dataset") > -1) {
name = "dataset"
} else if (url.indexOf(`/devops`) > -1) {
name = "devops"
} else if (url.indexOf(`/source`) > -1) {
@ -704,10 +710,16 @@ class Detail extends Component {
() => (<DevAbout {...this.props} {...this.state} {...common} />)
}
></Route>
{/* 数据集 */}
<Route path="/:owner/:projectsId/dataset/upload"
render={
(props) => (<DataSetUpload {...this.props} {...props} {...this.state} {...common} />)
}
></Route>
<Route path="/:owner/:projectsId/dataset"
render={
() => (<DataSetIndex {...this.props} {...this.state} {...common} />)
(props) => (<DataSetIndex {...this.props} {...props} {...this.state} {...common}/>)
}
></Route>
{/* wiki新增文件 */}

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

View File

@ -3,6 +3,7 @@ import { Skeleton , Tooltip} from 'antd';
import { Link } from 'react-router-dom';
import { numFormat } from 'educoder';
import QuitBox from './quit';
import datasetImg from '../img/dataset.jpg';
import axios from 'axios';
function DetailBanner({ history,list , owner , projectsId ,showNotification , url , pathname , state , urlFlag , projectDetail , platform ,open_devops ,current_user, showNpsModal }){
@ -104,6 +105,16 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
</li>
:""
}
{
item.menu_name === "dataset" ?
<li className={pathname==="dataset" ? "active" : ""}>
<Link className='newTab' to={{ pathname: `/${owner}/${projectsId}/dataset`, state:{...state,open_devops} }}>
<img src={datasetImg} height={15} alt="" className="mr5 mt5"/>数据集
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
</Link>
</li>
:""
}
{/* {
item.menu_name === "resources" &&
<li className={pathname==="source" ? "active" : ""}>
@ -168,12 +179,7 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
)
})
}
{/* <li className={pathname==="dataset" ? "active" : ""}>
<Link className='newTab' to={{ pathname: `/${owner}/${projectsId}/dataset`, state:{...state,open_devops} }}>
<i className="iconfont icon-gongzuoliuicon font-13 mr5 color-grey-3"></i>数据集
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
</Link>
</li> */}
</ul>
:
<Skeleton paragraph={false} active={true}/>

View File

@ -16,6 +16,7 @@ const menu = [
{name:"疑修 (Issue)",index:"issues"},
{name:"合并请求 (PR)",index:"pulls"},
{name:"引擎 (Engine)",index:"devops"},
{name:"数据集",index:"dataset"},
// {name:"资源库",index:"resources"},
{name:"里程碑",index:"versions"},
{name:"维基 (Wiki)",index:"wiki"},
@ -397,7 +398,7 @@ class Setting extends Component {
{getFieldDecorator("project_units", {
rules: [],
})(
<Checkbox.Group>
<Checkbox.Group className="unitStyle">
{
menu.map((item,key)=>{
return(

View File

@ -349,3 +349,10 @@
}
}
}
.unitStyle{
.ant-checkbox-wrapper + .ant-checkbox-wrapper{
margin-left: 0px;
margin-right: 8px;
margin-bottom: 10px;
}
}