From f5df464d90d68077bcf56ef3d8e69316f131ceb3 Mon Sep 17 00:00:00 2001 From: caishi <1149225589@qq.com> Date: Mon, 12 Apr 2021 17:58:46 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B5=84=E6=BA=90=E5=BA=93=E6=A8=A1=E5=9D=97+?= =?UTF-8?q?=E5=90=88=E5=B9=B6=E8=AF=B7=E6=B1=82=E5=88=86=E9=A1=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/forge/Main/Detail.js | 19 ++ src/forge/Merge/merge.js | 6 +- src/forge/Source/AddTag.jsx | 47 +++++ src/forge/Source/Index.jsx | 288 ++++++++++++++++++++++++++++++ src/forge/Source/Index.scss | 109 +++++++++++ src/forge/Source/Upload.jsx | 82 +++++++++ src/forge/Source/UploadSource.jsx | 150 ++++++++++++++++ 7 files changed, 698 insertions(+), 3 deletions(-) create mode 100644 src/forge/Source/AddTag.jsx create mode 100644 src/forge/Source/Index.jsx create mode 100644 src/forge/Source/Index.scss create mode 100644 src/forge/Source/Upload.jsx create mode 100644 src/forge/Source/UploadSource.jsx diff --git a/src/forge/Main/Detail.js b/src/forge/Main/Detail.js index 9886b7e2..1df5784d 100644 --- a/src/forge/Main/Detail.js +++ b/src/forge/Main/Detail.js @@ -104,6 +104,10 @@ const TrendsIndex = Loadable({ loading: Loading, }) +const Source = Loadable({ + loader: () => import('../Source/Index'), + loading: Loading, +}) const DevAbout = Loadable({ loader: () => import('../About/Index'), loading: Loading, @@ -133,6 +137,8 @@ function checkPathname(projectsId,owner,pathname){ name="setting" }else if(url.indexOf(`/devops`)>-1){ name="devops" + }else if(url.indexOf(`/source`)>-1){ + name="source" } } return name; @@ -544,6 +550,13 @@ class Detail extends Component { } +
  • + + + 资源库 + {projectDetail && projectDetail.source_count ? {projectDetail.source_count} :""} + +
  • {/* { platform &&
  • @@ -590,6 +603,12 @@ class Detail extends Component { : + {/* 资源 */} + () + } + > {/* 主页 */} - {search_count > limit ? ( + {search_count > select_params.limit ? (
    diff --git a/src/forge/Source/AddTag.jsx b/src/forge/Source/AddTag.jsx new file mode 100644 index 00000000..8b94b5a6 --- /dev/null +++ b/src/forge/Source/AddTag.jsx @@ -0,0 +1,47 @@ +import React , { forwardRef, useEffect } from 'react'; +import { Modal , Form , Input } from 'antd'; + +function AddTag({form , visible , onCancel ,onOk}){ + const { getFieldDecorator, validateFields , setFieldsValue } = form; + + useEffect(()=>{ + setFieldsValue({tagName:undefined}) + },[visible]) + + function submit(){ + validateFields((error,values)=>{ + if(!error){ + onOk(values); + } + }) + } + const layout = { + labelCol: { span: 5 }, + wrapperCol: { span: 18 }, + }; + return( + +
    + + {getFieldDecorator("tagName",{ + rules:[{required:true,message:"请输入标签名"}] + })( + + )} + +
    +
    + ) + +} +export default Form.create()(forwardRef(AddTag)); \ No newline at end of file diff --git a/src/forge/Source/Index.jsx b/src/forge/Source/Index.jsx new file mode 100644 index 00000000..f3c68217 --- /dev/null +++ b/src/forge/Source/Index.jsx @@ -0,0 +1,288 @@ +import React, { useEffect, useState } from 'react'; +import './Index.scss'; +import { AlignCenter, Blueback , FlexAJ } from '../Component/layout'; +import { Dropdown, Input , Menu , Pagination, Spin , Popconfirm, Button } from 'antd'; +import { Link } from 'react-router-dom'; +import UploadSource from './UploadSource'; +import AddTag from './AddTag'; +import { getImageUrl } from 'educoder'; +import Nodata from '../Nodata'; +import axios from 'axios'; + +const { Search } = Input; +const sort = [ + "按上传时间排序", + "按下载次数排序", + "按引用排序" +] +const limit = 15; +const https = 'https://testfiles.trustie.net'; +function Index(props){ + const [ sortValue , setSortValue ] = useState(0); + const [ page , setPage ] = useState(1); + const [ total , setTotal ] = useState(0); + const [ search , setSearch ] = useState(undefined); + const [ data , setData ] = useState(undefined); + const [ isSpin , setIsSpin ] = useState(true); + const [ error , setError ] = useState(false); + const [ attachments , setAttachments ] = useState(undefined); + + const [ id , setId ] = useState(undefined); + + const [ visible , setVisible ] = useState(false); + const [ addVisible , setAddVisible ] = useState(false); + + const repo_id = props.projectDetail && props.projectDetail.repo_id; + const owner = props.match.params.owner; + const current_user = props.current_user; + + useEffect(()=>{ + if(owner && repo_id){ + setIsSpin(true); + getData(); + } + },[repo_id,owner,search,sortValue,page]) + + function getData(){ + const url = https +`/api/project/achievement/`; + axios.get(url,{ + params:{ + projectId:repo_id, + curPage:page, + pageSize:limit, + name:search, + sort:sortValue+1, + } + }).then(result=>{ + if(result && result.data){ + setData(result.data.data.rows); + setTotal(result.data.data.total); + setIsSpin(false); + setError(false); + } + }).catch(error=>{setIsSpin(false);setError(true);}) + } + + // 搜索 + function onSearch(value){ + setSearch(value); + } + + // 切换排序方式 + function changeSort(e,index){ + setSortValue(index); + } + + + const menu=( + + { + sort && sort.map((item,key)=>{ + return( + changeSort(e,key)} value={key} className={key=== sortValue ?"color-blue":""}>{item} + ) + }) + } + + ) + + function listmenu(id,attachments,isPublic){ + return( + + {setId(id);setVisible(true);setAttachments(attachments)}}>更新版本 + changeStatus(id,isPublic===1?0:1)}>{isPublic === 1 ? "设为私有":"设为公开"} + deleteSourceFunc(id)}>删除资源 + + ) + } + // 更细私有状态 + function changeStatus(id,isPublic){ + const url = https+`/api/project/achievement/updateStatus`; + axios.put(url,{ + id,status:isPublic + }).then(result=>{ + if(result && result.data){ + props.showNotification(`资源${isPublic === 1 ? "设为公开":"设为私有"}成功!`); + setIsSpin(true); + getData(); + } + }).catch({}) + } + + // 删除资源方法 + function deleteSourceFunc(id){ + props.confirm({ + content: "是否确认删除所选资源文件?", + onOk: () => { + const url = https + `/api/project/achievement/${id}`; + axios.delete(url).then(result=>{ + if(result && result.data && result.data.code === "1"){ + props.showNotification("资源删除成功"); + setIsSpin(true); + getData(); + } + }) + } + }) + + } + + + // 上传资源成功 + function onOk(){ + setVisible(false); + setIsSpin(true); + getData(); + } + + // 确认删除标签 + function removeTagFunc(id,tag){ + const url = https + `/api/project/achievement/deleteTag`; + axios.delete(url,{ + params:{id,tagName:tag} + }).then(result=>{ + if(result && result.data){ + props.showNotification("标签删除成功"); + setIsSpin(true); + getData(); + } + }).then(error=>{}) + } + + function addPanel(id){ + setAddVisible(true); + setId(id); + } + + function onCancelAdd(){ + setId(undefined); + setAddVisible(false); + } + + // 添加标签 + function sureAddTag(values){ + const url = https+`/api/project/achievement/addTag?id=`+id+`&tagName=`+values.tagName; + axios.put(url).then(result=>{ + if(result){ + setId(undefined); + setAddVisible(false); + setIsSpin(true); + getData(); + } + }) + } + + return( +
    + + setVisible(false)} + onOk={onOk} + showNotification={props.showNotification} + owner={owner} + projectsId={repo_id} + id={id} + attachments={attachments} + /> +
    + + 资源库(18) + { current_user && current_user.login && (props.projectDetail && props.projectDetail.permission) ? + {setId(undefined);setVisible(true);}}>上传资源:"" + } + +
    + + + + {sort[sortValue]} + + + +
    + { + data && data.length> 0 && +
      + { + data.map((item,key)=>{ + return( +
    • + +
      + + + {item.fileName} + + {item.isPublic === 0 && 私有} + + { current_user && current_user.login && + listmenu(item.id,item.attachments,item.isPublic)} placement={'bottomRight'}> + + + } + +

      + 上传时间:{item.uploadTime} + 文件大小:{item.fileSize} + 下载:{item.download} +

      +

      {item.remark}

      +
      + { + item.tags && item.tags.length>0 && item.tags.map((i,k)=>{ + return( + {i} + { + current_user && (current_user.login === item.login) ? + removeTagFunc(item.id,i)} okText="是" cancelText="否"> + + :"" + } + + ) + }) + } + { + current_user && (current_user.login === item.login) && + addPanel(item.id)} style={{height:"20px",lineHeight:"20px"}}>+新增标签 + } +
      +
      +
    • + ) + }) + } +
    + } + { + ((data && data.length === 0) || error) && + } + { + total > limit && +
    + {setPage(p)}} + /> +
    + } +
    +
    +
    + ) +} +export default Index; \ No newline at end of file diff --git a/src/forge/Source/Index.scss b/src/forge/Source/Index.scss new file mode 100644 index 00000000..57b122ae --- /dev/null +++ b/src/forge/Source/Index.scss @@ -0,0 +1,109 @@ +.sourcePanel{ + width: 1200px; + margin: 20px auto; + background: #fff; + border-radius: 2px; + box-shadow: 0px 0px 4px rgba(0,0,0,0.1); + .headtitle{ + padding:15px 20px; + border-bottom: 1px solid #eee; + } + .subHeadtitle{ + padding:15px 20px; + border-bottom: 1px solid #eee; + .ant-input-group-wrapper{ + width:320px; + .ant-btn.ant-input-search-button{ + margin: 0px; + margin-top: -1px; + } + } + } + .bodycontent{ + padding:0px 20px; + min-height: 500px; + & > ul.bodycontentul > li{ + display: flex; + border-bottom: 1px solid #eee; + padding:20px 0px; + align-items: flex-start; + &:last-child{ + border-bottom: none; + } + .infoImg{ + img{ + width: 50px; + height: 50px; + border-radius: 50%; + } + margin-right: 15px; + } + .infoname{ + font-size: 16px; + } + .privateTip{ + display: block; + font-size: 12px; + margin-left: 10px; + background-color: orange; + height: 18px; + line-height: 18px; + padding:0px 3px; + color: #fff; + } + .infos{ + & > span{ + margin-right: 20px; + color: #999; + & >span{ + color: #666; + } + } + } + .infodesc{ + color: #666; + line-height: 20px; + margin:5px 0px!important; + } + .infotag{ + display: flex; + flex-wrap: wrap; + span{ + display: block; + padding:0px 4px; + height: 20px; + line-height: 20px; + font-size: 12px; + margin-right: 10px; + border: 1px solid #f8df8c; + background: #fffce6; + color: #0d90c3; + border-radius: 2px; + cursor: pointer; + } + } + } + } +} +.versionTable{ + .currentTip{ + display: block; + padding:0px 3px; + border-radius: 2px; + border:1px solid #68c7ec; + font-size: 12px; + color: #68c7ec; + height: 18px; + line-height: 18px; + margin-left: 5px; + } + .ant-table-body{ + margin:0px!important; + thead{ + background-color: #eee; + } + thead >tr >th,tbody > tr > td{ + padding:4px 5px!important; + } + } +} \ No newline at end of file diff --git a/src/forge/Source/Upload.jsx b/src/forge/Source/Upload.jsx new file mode 100644 index 00000000..de2c8ecb --- /dev/null +++ b/src/forge/Source/Upload.jsx @@ -0,0 +1,82 @@ +import React, { useEffect, useState } from "react"; +import { Upload, Button } from 'antd'; +import { appendFileSizeToUploadFileAll } from 'educoder'; + +import axios from 'axios'; +function Uploads({ className , size , actionUrl,fileList,showNotification , load}) { + const [ files , setFiles ] = useState(undefined); + + useEffect(()=>{ + if(fileList){ + init(); + } + },[fileList]); + + function init(){ + let f = appendFileSizeToUploadFileAll(fileList); + setFiles(f); + } + function onAttachmentRemove(file){ + if (!file.percent || file.percent === 100) { + deleteAttachment(file); + return false; + } + } + function deleteAttachment(file){ + let id = file.response && file.response.data && file.response.data.id; + const url = actionUrl + `/busiAttachments/${id}`; + axios.delete(url).then((response) => { + if (response.data) { + if (response.data.code === "1") { + let nf = files.filter(item=>item.response.data.id !== id); + setFiles(nf); + fileIdList(nf); + } else { + showNotification(response.data.message) + } + } + }).catch(function (error) { + console.log(error); + }); + } + + + function handleChange (info) { + if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') { + let fileList = info.fileList; + let len = info.fileList && info.fileList.length; + setFiles(appendFileSizeToUploadFileAll([fileList[len-1]])); + fileIdList(fileList[len-1]); + } + } + + function fileIdList (fileList) { + let data = fileList.response && fileList.response.data; + fileList && load && load(data && data.id,data && data.fileName); + } + + function beforeUpload(file){ + const isLt100M = file.size / 1024 / 1024 < size; + if (!isLt100M) { + showNotification(`文件大小必须小于${size}MB!`); + } + return isLt100M; + } + + const upload = { + name: 'file', + fileList: files, + action: actionUrl+`/busiAttachments/upload`, + onChange:handleChange, + onRemove:onAttachmentRemove, + beforeUpload:beforeUpload, + maxCount:1 + }; + return ( + + + (你可以上传小于{size}MB的文件) + + ) +} +export default Uploads; \ No newline at end of file diff --git a/src/forge/Source/UploadSource.jsx b/src/forge/Source/UploadSource.jsx new file mode 100644 index 00000000..64bd5b7c --- /dev/null +++ b/src/forge/Source/UploadSource.jsx @@ -0,0 +1,150 @@ +import React , { forwardRef, useEffect, useState } from 'react'; +import { Modal , Form , Checkbox , Input , Table } from 'antd'; +import Upload from './Upload'; +import { AlignCenter } from '../Component/layout'; +import axios from 'axios'; +const { TextArea } = Input; + +const https = 'https://testfiles.trustie.net'; +function UploadSource({ form , visible , onCancel , onOk , showNotification , attachments , id ,owner,projectsId}){ + const [ tableData , setTableData ] = useState(undefined); + const [ fileId , setFilesId ] = useState(undefined); + const [ fileName , setFileName ] = useState(undefined); + const { getFieldDecorator, validateFields , setFieldsValue } = form; + + useEffect(()=>{ + if(id && attachments){ + setTableData(attachments); + } + },[id,attachments]) + // 上传附件后得到的文件id数组 + function UploadFunc(id,name){ + setFilesId(id); + setFileName(name); + } + + const columns = [ + { + dataIndex:"fileName", + key:"fileName", + title:"资源名称", + width:"42%", + ellipsis:true, + render:(value,item,key)=>{ + return +
    {value}
    + { key === 0 && 当前版本 } +
    + } + }, + { + dataIndex:"downloads", + key:"downloads", + title:"下载数", + width:"14%", + className:"edu-txt-center" + }, + { + dataIndex:"fileSizeString", + key:"fileSizeString", + title:"文件大小", + width:"16%", + className:"edu-txt-center" + }, + { + dataIndex:"createdAt", + key:"createdAt", + title:"上传时间", + } + ] + + // 确定 + function submit(){ + if(fileId){ + validateFields((error,values)=>{ + if(!error){ + postInfo(values); + } + }) + }else{ + showNotification("请先上传文件!"); + } + } + + function postInfo(values){ + const url = https+`/api/project/achievement/`; + if(id){ + // 修改 + axios.put(url,{ + id,fileName,fileId:`${fileId}`, + remark:values.remark + }).then(result=>{ + if(result && result.data){ + onOk(); + } + }).catch(error=>{}) + }else{ + // 上传 + axios.post(url,{ + fileId:`${fileId}`, + fileName, + login:owner, + projectId:projectsId, + ...values + }).then(result=>{ + if(result && result.data){ + onOk(); + } + }).catch(error=>{}) + } + + } + return( + +
    +
    + {id && } + + {getFieldDecorator("tagNames",{ + rules:[] + })( + + 软件版本 + 文档 + 代码 + 媒体 + 论文 + 其它 + + )} + + + + {getFieldDecorator("remark",{ + rules:[] + })( +