Merge branch 'dev_military_qz2022_temparary' of https://code.gitlink.org.cn/tongChong/forgeplus-react into dev_military_osredm

This commit is contained in:
何童崇 2022-12-13 09:28:30 +08:00
commit f2b2e7716d
248 changed files with 12738 additions and 3210 deletions

View File

@ -1,6 +1,6 @@
{
"presets": [
"es2015",
"env",
"react",
"stage-2"
],

View File

@ -104,6 +104,7 @@ module.exports = {
src: path.join(paths.appSrc), // 整个源代码目录
forge: path.join(paths.appSrc, 'forge'),
military: path.join(paths.appSrc, 'military'),
components: path.join(paths.appSrc, 'components'),
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
"react-native": "react-native-web",
@ -210,6 +211,12 @@ module.exports = {
{
loader: require.resolve("sass-loader"),
},
{
loader: 'sass-resources-loader',
options: {
resources: ['src/global.scss']
}
}
],
},
{

View File

@ -19,7 +19,9 @@ const getClientEnvironment = require("./env");
let publicPath = "/react/build/";
const publicUrl = publicPath.slice(0, -1);
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
// const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false";
const shouldUseSourceMap = process.env.NODE_ENV !== "production";
const env = getClientEnvironment(publicPath);
// This is the production configuration.
@ -54,7 +56,8 @@ module.exports = {
},
bail: true,
mode: "production",
devtool: false, //测试版
// devtool: false, //测试版
devtool: shouldUseSourceMap?'source-map':false,
entry: [require.resolve("./polyfills"), paths.appIndexJs],
output: {
path: paths.appBuild,
@ -90,6 +93,7 @@ module.exports = {
src: path.join(paths.appSrc),
forge: path.join(paths.appSrc, 'forge'),
military: path.join(paths.appSrc, 'military'),
components: path.join(paths.appSrc, 'components'),
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
"react-native": "react-native-web",
@ -209,6 +213,12 @@ module.exports = {
{
loader: require.resolve("sass-loader"),
},
{
loader: 'sass-resources-loader',
options: {
resources: ['src/global.scss']
}
}
],
},
{

View File

@ -5,6 +5,7 @@
"educoder": ["./src/common/educoder.js"],
"forge":["./src/forge"],
"military":["./src/military"],
"components":["./src/components"],
}
},
"exclude": [

2866
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -105,7 +105,7 @@
"redux": "^4.0.5",
"redux-thunk": "2.3.0",
"rsuite": "^4.3.4",
"sass-loader": "7.3.1",
"sass-loader": "^7.3.1",
"save-dev": "0.0.1-security",
"scroll-into-view": "^1.14.2",
"showdown": "^1.9.1",
@ -116,7 +116,7 @@
"styled-components": "^4.4.1",
"sw-precache-webpack-plugin": "0.11.4",
"url-loader": "0.6.2",
"wangeditor-for-react": "^1.4.0",
"wangeditor-for-react": "^1.5.6",
"webpack-cli": "^3.3.11",
"webpack-dev-server": "^3.10.3",
"webpack-manifest-plugin": "^2.2.0",
@ -216,9 +216,13 @@
"react-json-view": "^1.21.3",
"reqwest": "^2.0.5",
"resize-observer-polyfill": "^1.5.1",
"sass-resources-loader": "^2.2.5",
"terser-webpack-plugin": "^2.3.5",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.42.1",
"webpack-bundle-analyzer": "^3.7.0"
},
"volta":{
"node":"8.12.0"
}
}

View File

@ -1,14 +1,9 @@
@font-face {
font-family: "iconfont"; /* Project id 2340181 */
<<<<<<< HEAD
src: url('iconfont.woff2?t=1644907653340') format('woff2'),
url('iconfont.woff?t=1644907653340') format('woff'),
url('iconfont.ttf?t=1644907653340') format('truetype');
=======
src: url('iconfont.woff2?t=1648801178933') format('woff2'),
url('iconfont.woff?t=1648801178933') format('woff'),
url('iconfont.ttf?t=1648801178933') format('truetype');
>>>>>>> a58c7403 (修改样式)
}
.iconfont {
@ -19,8 +14,6 @@
-moz-osx-font-smoothing: grayscale;
}
<<<<<<< HEAD
=======
.icon-kaiyuanxiangmu:before {
content: "\e91d";
}
@ -93,7 +86,6 @@
content: "\e915";
}
>>>>>>> a58c7403 (修改样式)
.icon-icon2:before {
content: "\e912";
}

File diff suppressed because one or more lines are too long

View File

@ -6,8 +6,6 @@
"description": "",
"glyphs": [
{
<<<<<<< HEAD
=======
"icon_id": "28163416",
"name": "开源项目",
"font_class": "kaiyuanxiangmu",
@ -134,7 +132,7 @@
"unicode_decimal": 59669
},
{
>>>>>>> a58c7403 ()
"icon_id": "27299393",
"name": "icon",
"font_class": "icon2",

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -16,13 +16,13 @@ import marked from './common/marked';
import moment from 'moment'
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
import SiderBar from './forge/Component/SiderBar'
// import SiderBar from './forge/Component/SiderBar'
import { SnackbarHOC } from 'educoder';
import { initAxiosInterceptors } from './AppConfig'
import { Provider } from 'react-redux';
import configureStore from './redux/stores/configureStore';
import { indexOf } from 'lodash';
import './phone.scss';
const store = configureStore();
window.marked = marked;
const theme = createMuiTheme({
@ -74,6 +74,11 @@ const Competition = Loadable({
loader: () => import('./military/competition'),
loading: Loading,
})
// 我关注的竞赛列表
const MyFocusCompetitions = Loadable({
loader: () => import('./military/competition/myFocus'),
loading: Loading,
})
//403页面
const Shixunauthority = Loadable({
loader: () => import('./modules/403/Shixunauthority'),
@ -134,10 +139,15 @@ const AboutUs = Loadable({
// loading: Loading,
// });
const NeedApply = Loadable({
loader: () => import("./managements/needApply"),
loading: Loading,
})
// 管理页面
const Managements = Loadable({
loader: () => import('./military/managements'),
loader: () => import('./managements/index'),
loading: Loading,
})
// const CreateMerge = Loadable({
@ -146,7 +156,7 @@ const Managements = Loadable({
// })
// 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize", "login", "register", "resetPassword", "aboutus","educoder","task","notice","managements","expert","competition"];
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize", "login", "register", "resetPassword", "aboutus","educoder","task","notice","managements","expert","competition","administration", "needs"];
class App extends Component {
constructor(props) {
@ -321,6 +331,12 @@ class App extends Component {
{/* <SiderBar /> */}
{/* <Router> */}
<Switch>
{/* 需求申请 */}
<Route path="/needs/new" render={
(props) => {
return (<NeedApply {...this.props} {...props} {...this.state} />)
}
} />
{/* wiki预览 */}
<Route path="/:owner/:projectsId/wiki/preview/:projectName/:projectId" render={
(props) => {
@ -376,6 +392,8 @@ class App extends Component {
<Route path="/task" component={Task} />
{/*专家评审*/}
<Route path="/expert" component={Expert} />
{/* 我关注的竞赛列表 */}
<Route path="/competition/myFocus" component={MyFocusCompetitions} />
{/*启智2022*/}
<Route path="/competition/:competitionId" component={Competition} />
@ -405,8 +423,12 @@ class App extends Component {
path="/register"
render={(props) =><LoginRegisterPage {...this.props} {...props}/>}
></Route>
{/*管理页面*/}
{/*管理页面 三个路由分别对应本环境管理、原测试ruby模板管理、原项目管理*/}
<Route path="/managements" component={Managements} />
<Route path="/admin" component={Managements} />
<Route path="/administration" component={Managements} />
{/*403*/}
<Route path="/403" component={Shixunauthority} />

View File

@ -34,7 +34,7 @@ export function initAxiosInterceptors(props) {
// var proxy = "http://192.168.1.40:3000";
var proxy = "http://111.8.36.180:8000";
// var proxy = "http://117.50.100.12:49999";
// var proxy = "https://www.osredm.com";
//响应前的设置
axios.interceptors.request.use(

View File

@ -1,9 +0,0 @@
import React from 'react'
import MiniPagination from './components/mini-pagination'
export default () => {
function onPageChange(page) {
console.log(page, '-----------')
}
return <MiniPagination onChange={onPageChange} current={1} total={100} pageSize={16} />
}

View File

@ -305,4 +305,31 @@ export function returnbar(str){
}
}
return s;
}
// 手动添加/修改mate标签
export function addMeta(name, content){
if(document.querySelector(`meta[name='${name}']`)){
document.querySelector(`meta[name='${name}']`).content=content;
}else{
const meta = document.createElement('meta');
meta.content = content;
meta.name = name;
document.getElementsByTagName('head')[0].appendChild(meta);
}
};
export function IsPC(){
var userAgentInfo = navigator.userAgent;
var Agents = ["Android", "iPhone",
"SymbianOS", "Windows Phone",
"iPad", "iPod"];
var flag = true;
for (var v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
}

View File

@ -7,7 +7,7 @@ export {
getImageUrl as getImageUrl,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl,getTestImage as getTestImage,getLogoImageUrl as getLogoImageUrl,
turnbar,returnbar,getUrlToken as getUrlToken
turnbar,returnbar,getUrlToken,addMeta,IsPC
} from './UrlTool';
export { setmiyah as setmiyah } from './Component';

View File

@ -0,0 +1,125 @@
/* eslint-disable react/jsx-no-duplicate-props */
import React, { useState } from 'react';
import * as ReactDOM from 'react-dom';
import { Modal, Button } from 'antd';
import './index.scss';
//
InitModal.defaultProps = {
okText: '确认', //
cancelText: '取消', //
className: '', //
inputId: 'copyText', //ID
onCancel:()=>{}, //
onOk:()=>{}, //
title:'提示', //
contentTitle:'', //
content:'', //
afterClose:()=>{}, //
};
// 使
export default function DelModal(props) {
renderModal({ ...props, type: 'delete' })
}
// 使
export function Confirm(props) {
renderModal({ ...props, type: 'confirm' })
}
function renderModal(props) {
const { type, afterClose } = props;
const div = document.createElement('div');
document.body.appendChild(div);
function destroy() {
afterClose && afterClose();
const unmountResult = ReactDOM.unmountComponentAtNode(div);
if (unmountResult && div.parentNode) {
div.parentNode.removeChild(div);
}
}
function modalType(type) {
if (type === 'delete') {
return <InitModal
title="删除"
contentTitle="确定要删除吗?"
okText="确认删除"
{...props}
afterClose={destroy}
contentTitle={<React.Fragment>
<i className="red-circle iconfont icon-shanchu_tc_icon mr3"></i>
{props.contentTitle}
</React.Fragment>}
/>
} else if (type === 'confirm') {
return <InitModal title="选择" afterClose={destroy} {...props} />
} else {
return <InitModal title="选择" afterClose={destroy} {...props} />
}
}
function render() {
setTimeout(() => {
ReactDOM.render(
modalType(type),
div,
);
});
}
render();
}
//
function InitModal({
onCancel,
onOk,
title,
contentTitle,
content,
okText,
cancelText,
afterClose,
className,
}) {
const [visible, setVisible] = useState(true);
function onCancelModal() {
setVisible(false);
onCancel && onCancel()
}
function onSuccess() {
setVisible(false);
onOk && onOk();
}
return (
<Modal
visible={visible}
onCancel={onCancelModal}
afterClose={afterClose}
title={title}
className={`myself-modal ${className}`}
centered
footer={[
<Button type="default" key="back" onClick={onCancelModal}>
{cancelText}
</Button>,
<Button className="foot-submit" key="submit" onClick={onSuccess}>
{okText}
</Button>,
]}
>
<div>
{contentTitle && <p className="content-title">{contentTitle}</p>}
<p className="content-descibe">{content}</p>
</div>
</Modal>
)
}

View File

@ -0,0 +1,63 @@
.myself-modal {
.ant-modal-header {
padding: 9px 24px;
background: #f8f8f8;
border-bottom: 1px solid #eee;
}
.ant-modal-title {
text-align: left;
}
.ant-modal-close {
top: 0px !important;
}
.ant-modal-close-x {
font-size: 24px;
}
.ant-modal-body {
text-align: center;
}
.content-title {
display: flex;
justify-content: center;
align-items: center;
margin: 2rem 0 1rem !important;
font-size: 16px;
color: #333;
letter-spacing: 0;
line-height: 29px;
font-weight: 400;
}
.red-circle {
align-self: flex-start;
color: #ca0002;
font-size: 1.5rem !important;
}
.content-descibe {
font-size: 14px;
color: #666;
line-height: 33px;
font-weight: 400;
}
.ant-modal-footer {
padding: 2rem 0;
text-align: center;
border: 0;
.ant-btn {
width: 6rem;
}
}
.foot-submit {
margin-left: 3rem;
color: #df0002;
&:hover {
border-color: #df0002;
}
}
.ant-btn-default:hover,
.ant-btn-default:active,
.ant-btn-default:focus {
background: #f3f4f6;
color: #333;
border-color: #d0d0d0;
}
}

View File

@ -0,0 +1,24 @@
import React from 'react';
import { Modal , Button } from 'antd';
import './index.scss';
function Modals({visible,title,content,onOk,onCancel}){
return(
<Modal
className="modalsStyle"
visible={visible}
title={title}
onCancel={onCancel}
closable={true}
footer={
<div>
<Button onClick={onCancel}>取消</Button>
<Button type={"primary"} style={{marginLeft:"20px"}} onClick={onOk}>确定</Button>
</div>
}
>
<div>{content}</div>
</Modal>
)
}
export default Modals;

View File

View File

@ -0,0 +1,27 @@
import React, { Fragment } from 'react';
import { Table, Pagination } from 'antd';
import './index.scss';
export default (props) => {
const {handleRow, total, setCurPage, current, onShowSizeChange, showSizeChanger, pagination} = props;
return (
<div className='pagination-table'>
<Table
{...props}
pagination={false}
onRow={handleRow}
/>
{total > 10 && (!pagination) &&
<Pagination
showQuickJumper
onShowSizeChange={onShowSizeChange}
onChange={setCurPage}
current={current}
total={total}
showSizeChanger={showSizeChanger}
/>}
</div>
)
}

View File

@ -0,0 +1,38 @@
.pagination-table {
margin-top: 1rem;
padding: 1.5rem;
background-color: #ffffff;
box-shadow:0px 0px 10px rgba(88, 116, 255, 0.18);
.ant-table {
border-radius: 0 0 4px 4px;
tr > td{
border-bottom: none;
border-top: 1px solid #e2e6f5;
}
tr:first-child > td{border-top: none;}
tr:last-child > td{border-bottom: 1px solid #e2e6f5;}
.ant-table-expanded-row td{border-top: none;}
}
.ant-table-thead tr th div {
color: #181818;
font-weight: 500;
}
.ant-table-wrapper {
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
.ant-table-hide-scrollbar {
margin-bottom: -5px;
overflow-y: hidden !important;
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
}
}
.ant-pagination {
margin: 2rem 1.5rem;
text-align: right;
}
}

View File

@ -0,0 +1,46 @@
import React, { forwardRef, useState } from 'react';
import { Upload , Icon , message } from "antd";
import { getUploadActionUrl } from 'educoder';
let chromeSettingArray = JSON.parse(localStorage.getItem('chromesetting'));
function UploadImage({ getImageId , imageId }){
//
function beforeUpload(file){
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
message.error('上传的图片只能是JPG或者PNG格式!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('上传的图片不能超过2MB!');
}
return isJpgOrPng && isLt2M;
}
//
function handleChange(info){
if(info && info.file && info.file.status === "done"){
getImageId(info.file.response.id);
}
}
return(
<Upload
listType="picture-card"
className="avatar-uploader"
showUploadList={false}
action={getUploadActionUrl()}
accept=".png,.jpg,.jpeg"
beforeUpload={beforeUpload}
onChange={handleChange}
>
{
imageId ? <img src={`${chromeSettingArray.current_main_site_url}/api/attachments/${imageId}`} alt="avatar" style={{ width: '100%' }} /> :
<div>
<Icon type={'plus'} />
<div className="ant-upload-text">点击上传</div>
</div>
}
</Upload>
)
}
export default forwardRef(UploadImage);

View File

@ -9,10 +9,10 @@ function Cards({img , title, desc , rightBtn , src , bottomInfos}){
{img &&<div className="img"><img src={getImageUrl(`/${img}`)} alt=""/></div>}
<div className="content">
<p className="titles">
<Link to={src}>{title}</Link>
<a href={src} className='organizationName font-18'>{title}</a>
{rightBtn}
</p>
<div className="desc">
<div className="desc font-15 pr10">
{desc}
</div>
{bottomInfos}

View File

@ -16,15 +16,13 @@ li.ant-menu-item{
.cards{
display: flex;
align-items: center;
padding:20px 34px;
padding:35px 30px;
background-color: #fff;
margin-bottom:18px;
min-height: 130px;
border:1px solid #eee;
.img{
margin-right: 20px;
width: 190px;
height: 90px;
width: 100px;
height: 100px;
border:1px solid rgba(238,238,238,1);
display: flex;
justify-content: center;
@ -41,13 +39,16 @@ li.ant-menu-item{
.titles{
display: flex;
justify-content: space-between;
margin-bottom: 10px!important;
margin-bottom: 15px!important;
align-items: center;
height: 22px;
line-height: 22px;;
&>a{
font-size:18px ;
color: #333;
line-height: 22px;
.organizationName{
color: #1e2941;
font-weight: 700;
}
.settingsLink{
color:#104fd9;
}
}
.desc{
@ -56,7 +57,10 @@ li.ant-menu-item{
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
line-height: 20px;
line-height: 1.5;
}
.bottomInfos{
color:#67738e;
}
}
}

View File

@ -6,12 +6,21 @@ import RenderHtml from '../../../components/render-html';
import cookie from 'react-cookies';
// import axios from 'axios';
function SystemNotice({showNotice,system_notification,history,login,hideSystemNotice}){
function SystemNotice({showNotice,system_notification,history,login,hideSystemNotice,location}){
const [ visible , setVisible ] = useState(false);
useEffect(()=>{
if(system_notification && !cookie.load('notice_stage')){
setVisible(true);
let pathname=history.location.pathname;
let isCompetition=pathname.indexOf('/competition/')>-1;
let openNotice=true;
//
if(isCompetition&&system_notification.subject.indexOf('启智')&&!(pathname.indexOf('/competition/qz2022')>-1)){
openNotice=false;
}
openNotice&&setVisible(true);
}
},[system_notification,history.location])
// useEffect(()=>{

View File

@ -5,7 +5,7 @@ export const getBranch = async (id,owner)=>{
}
//
export const getTag = async (id,owner)=>{
return (await axios.get(`/${owner}/${id}/tags.json`)).data;
return (await axios.get(`/${owner}/${id}/tags.json`,{params:{only_name:true}})).data.tags;
}
// hooks-web
export const getHooks = async (id,params)=>{

View File

@ -1,7 +1,7 @@
import React, { useState , forwardRef, useEffect } from 'react';
import { Form , Modal , Input , Radio } from 'antd';
import { Form , Modal , Input , Radio ,Button} from 'antd';
import Axios from 'axios';
import CheckProfile from '../Component/ProfileModal/Profile';
// import CheckProfile from '../Component/ProfileModal/Profile';
function AddProjectModal(props){
const { getFieldDecorator, validateFields , setFieldsValue } = props && props.form;
const [ visible , setVisible ] = useState(false);
@ -78,7 +78,9 @@ function AddProjectModal(props){
</Form.Item>
</Form>
</Modal>
<CheckProfile {...props} sureFunc={()=>setVisible(true)}>加入项目</CheckProfile>
{/* 红山无资料要求限制,暂时注释 */}
{/* <CheckProfile {...props} sureFunc={()=>setVisible(true)}>加入项目</CheckProfile> */}
<Button type="primary" onClick={()=>setVisible(true)}>加入项目</Button>
</React.Fragment>
)
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 993 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 873 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

View File

@ -41,7 +41,7 @@ class Index extends Component {
return (
<div className="newMain clearfix">
{window.location.href.indexOf('osredm.jk') < 0&&<Handbook/>}
{/* {window.location.href.indexOf('osredm.jk') < 0&&<Handbook/>} */}
<Switch {...this.props}>
<Route
path="/projects/:projectsType/new/:OIdentifier"

View File

@ -233,11 +233,12 @@ function CoderDepot(props){
let checkvalue = turnbar(b);
return (
<Menu className="fileMenu">
<Menu.Item>
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</CheckProfile>
<Menu.Item onClick={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>
上传文件
{/* <CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</CheckProfile> */}
</Menu.Item>
<Menu.Item>
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</CheckProfile>
<Menu.Item onClick={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件
{/* <CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/newfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>新建文件</CheckProfile> */}
</Menu.Item>
</Menu>
)
@ -434,8 +435,8 @@ function CoderDepot(props){
{
<div className="addOptionBtn">
{
baseOperate &&
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/compare/master...${turnbar(branchName || defaultBranch)}`)} >+ 合并请求</CheckProfile>
baseOperate &&<a onClick={()=>urlLink(`/${owner}/${projectsId}/compare/master...${turnbar(branchName || defaultBranch)}`)}>+ 合并请求</a>
// <CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/compare/master...${turnbar(branchName || defaultBranch)}`)} >+ </CheckProfile>
}
<a onClick={createIssue}>+ 疑修</a>
{/* {

View File

@ -11,8 +11,8 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){
const [ content ,setContent ] = useState(undefined);
useEffect(()=>{
if(readme && readme.content){
setContent(readme.content);
if(readme && readme.replace_content){
setContent(readme.replace_content);
}else{
setContent(undefined);
}

View File

@ -14,10 +14,10 @@ export default (( props, { projectDetail }) => {
useEffect(() => {
if (projectsId) {
const url = `/${owner}/${projectsId}/tags.json`;
axios.get(url).then((result) => {
if (result) {
axios.get(url,{params:{page:1,limit:1000}}).then((result) => {
if (result.data) {
setSpin(false);
setData(result.data);
setData(result.data.tags);
}
}).catch(error => {
console.log(error);

View File

@ -527,6 +527,17 @@ class Detail extends Component {
</div> : ""
}
hideModal = () => {
this.setState({
visible: false
});
this.props.history.push('/projects');
}
sureModal = () => {
const { getListData } = this.props;
getListData && getListData(1);
}
render() {
const { projectDetail, watchers_count, praises_count,
@ -550,7 +561,7 @@ class Detail extends Component {
}
return (
<div>
<SpecialModal {...this.props} visible={visible} hideModal={this.sureModal} user_apply_signatures={user_apply_signatures} project_id={project_id} sureModal={this.sureModal}></SpecialModal>
<SpecialModal {...this.props} visible={visible} hideModal={this.hideModal} user_apply_signatures={user_apply_signatures} project_id={project_id} sureModal={this.sureModal}></SpecialModal>
<div className="detailHeader-wrapper open-sourse">
<div className="normal">
<AlignTop style={{ padding: "18px 0px 10px", justifyContent: "space-between" }}>

View File

@ -11,7 +11,22 @@ import axios from 'axios';
import img_new from '../Images/new.png';
import img_array from '../Images/array.png';
import banner from '../Images/banner_list.png';
import CheckProfile from '../Component/ProfileModal/Profile';
// import CheckProfile from '../Component/ProfileModal/Profile';
import Slider from 'react-slick';
import left from './img/left.png';
import right from './img/right.png';
import explore1 from '../Images/explore1.png';
import explore2 from '../Images/explore2.png';
import explore3 from '../Images/explore3.png';
import explore4 from '../Images/explore4.png';
import explore5 from '../Images/explore5.png';
import explore6 from '../Images/explore6.png';
import explore7 from '../Images/explore7.png';
import explore8 from '../Images/explore8.png';
import explore9 from '../Images/explore9.png';
import explore10 from '../Images/explore10.png';
import { getImageUrl } from 'educoder';
import { Link } from 'react-router-dom';
const Search = Input.Search;
@ -27,18 +42,19 @@ class Index extends Component {
total: 0,
isSpin: true,
category_id: undefined,
typeList: undefined,
categoryList: undefined,
recommendList:undefined,
recommendOriList:undefined,
languageList:undefined,
languageId:undefined,
CategoryList:undefined
CategoryList:undefined,
bannerList: undefined,
// 今日、本周热门项目
hotProjectTime: 7,
hotProjectList: undefined,
// 热门开发者
authorList: undefined
}
}
@ -46,16 +62,53 @@ class Index extends Component {
componentDidMount = () => {
const { page,search, sort,category_id , languageId } = this.state;
this.getListData(page,search, sort,category_id , languageId);
this.getType();
this.getCategory();
// this.getRecommand();
this.getLanguage();
this.getBannerList();
// this.getRecommandOri();
this.getList(7);
this.getAuthorList();
}
// 获取热门开发者
getAuthorList = ()=>{
axios.get(`/user_rank.json`,{
params:{
time: 30
}
}).then(result=>{
if(result && result.data){
this.setState({authorList: result.data.users.slice(0,10)})
}
}).catch(error=>{})
}
// 获取热门项目
getList = (time) => {
const url = `/project_rank.json`;
axios.get(url,{
params:{
time
}
}).then(result=>{
if(result && result.data){
this.setState({hotProjectList: result.data.projects})
}
}).catch(error=>{})
}
// 获取banner图列表
getBannerList = ()=>{
const url = '/topics.json?topic_type=banner&limit=5';
axios.get(url).then(result=>{
if(result){
this.setState({
bannerList:result.data.topics
})
}
}).catch(error=>{})
}
// 获取语言列表
@ -144,7 +197,7 @@ class Index extends Component {
<li key={key} className={ parseInt(active_type) === item.id ? 'active' : ''} onClick={() => this.changeType(`${item.id}`, list)}>
<p>
<span className="font-16">{item.name}</span>
<span className="color-blue">{item.projects_count}</span>
{/* <span className="color-blue">{item.projects_count}</span> */}
</p>
</li>
)
@ -187,7 +240,7 @@ class Index extends Component {
<li key={key} className={parseInt(active_id) === item.id ? 'active' : ''} onClick={() => this.changeCategory(`${item.id}`, list)}>
<p>
<span className="font-16">{item.name}</span>
<span className="color-blue">{item.projects_count}</span>
{/* <span className="color-blue">{item.projects_count}</span> */}
</p>
</li>
)
@ -263,12 +316,12 @@ class Index extends Component {
newItem = ()=>{
return(
<ul>
<li>
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/deposit/new')}}>新建项目</CheckProfile>
<ul className='newProject'>
<li onClick={()=>{this.props.history.push('/projects/deposit/new')}}>新建项目
{/* <CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/deposit/new')}}>新建项目</CheckProfile> */}
</li>
<li>
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/mirror/new')}}>导入项目</CheckProfile>
<li onClick={()=>{this.props.history.push('/projects/mirror/new')}}>导入项目
{/* <CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/mirror/new')}}>导入项目</CheckProfile> */}
</li>
</ul>
)
@ -283,116 +336,170 @@ class Index extends Component {
)
}
render() {
const { current_user } = this.props;
const { projectsList , recommendList , languageList , languageId ,
isSpin, total, search, limit, page, typeList, categoryList ,
recommendOriList , CategoryList , category_id } = this.state;
render() {
const { current_user, mygetHelmetapi} = this.props;
const { projectsList ,isSpin, total, search, limit, page, typeList, categoryList ,bannerList, hotProjectTime, hotProjectList, authorList } = this.state;
let settings={
dots:true,
infinite: true,
speed: 2000,
slidesToShow: 1,
slidesToScroll: 1,
pauseOnDotsHover:true,
autoplaySpeed:5000,
pauseOnFocus:true,
autoplay:true,
arrows:true,
prevArrow:<button type='button' className='changeImgBut'><img src={left} width="70px" alt=""/></button>,
nextArrow:<button type='button' className='changeImgBut'><img src={right} width="70px" alt=""/></button>
}
return (
<div>
<p className="t_project_banner">
<img src={banner} width="100%" alt=""/>
</p>
{/* {
recommendOriList && recommendOriList.length>0?
<Slider {...settings} className="recommandOri">
{
recommendOriList.map((i,k)=>{
return(
<li><Link to={''}><img src={getImageUrl(`/${i.avatar_url}`)} alt={i.name} title={i.name} width="80px"/></Link></li>
)
})
}
</Slider>
:""
} */}
{/* {
recommendList && recommendList.length>0 &&
<Slider {...setting} className={recommendList.length>5 ? "recommandProjects":"recommandProjects mb20"}>
{
recommendList.map((item,key)=>{
return(
<div className="items" onClick={()=>this.getoDetail(item.author && item.author.login,item.identifier)}>
<div className="mainInfo">
<img src={getImageUrl(`/${item.author && item.author.image_url}`)} width="50px" height="50px"alt=""/>
<p className="school">{item.name}</p>
<p className="name">{item.author && item.author.name}</p>
</div>
<div className="baseInfo">
<span className="look"><i className="iconfont icon-dianjiliang font-12"></i>{item.visits}</span>
<span className="type">{item.category && item.category.name}</span>
</div>
</div>
)
})
}
</Slider>
} */}
<div className="ProjectListIndex">
<Affix className="affix-list-left" offsetTop={90}>
<div className="affix-list-content">
<ul className="list-l-Menu">
<li className="MenuTitle" onClick={() => {this.getType();this.changeType(undefined, this.state.typeList);}}>
<span><i className="iconfont icon-bianchengyuyan color-grey-9 font-15 mr5"></i>
语言</span></li>
<div className="list-affix">{typeList}</div>
</ul>
<ul className="list-l-Menu">
<li className="MenuTitle" onClick={() => {this.getCategory();this.changeCategory(undefined, this.state.categoryList);}}>
<span><i className="iconfont icon-xiangmuleibie color-grey-9 font-15 mr5"></i></span>
</li>
<div className="list-affix">{categoryList}</div>
</ul>
</div>
<div style={{backgroundColor: '#f5f7fa'}}>
{/* banner图 */}
{bannerList ? bannerList.length === 1 ? bannerList[0].url ? <a href={bannerList[0].url} target={'_blank'}><img alt={bannerList[0].title} src={bannerList[0].image ? `${ mygetHelmetapi && mygetHelmetapi.current_main_site_url }${bannerList[0].image}` : banner} width='100%' height='100%' className='imgBox'/></a> :
<img alt={bannerList[0].title} src={bannerList[0].image ? `${ mygetHelmetapi && mygetHelmetapi.current_main_site_url }${bannerList[0].image}` : banner} width='100%' height='100%' className='imgBox'/> :
<Slider {...settings} className="projectBannerBox">
{bannerList.map((item) => {
return item.url ? (
<a href={item.url} target={'_blank'}>
<img alt={item.title} src={item.image ? `${ mygetHelmetapi && mygetHelmetapi.current_main_site_url }${item.image}` : banner} width='100%' height='100%' className='imgBox'/>
</a>
) : <img src={item.image ? `${ mygetHelmetapi && mygetHelmetapi.current_main_site_url }${item.image}` : banner} alt="" width="100%" height='100%' className='imgBox'/>
;
})}
</Slider>: <img src={banner} width="100%" alt=""/>}
{bannerList && bannerList.length === 0 && <img src={banner} width="100%" alt=""/>}
{/* 项目列表 */}
<div className="ProjectListIndex exploreBox">
<Affix className="affix-list-left" offsetTop={90}>
<div className="affix-list-content">
<ul className="list-l-Menu">
<li className="MenuTitle">
<img src={explore1} alt="" width={18} className='mr5'/>语言
</li>
<div className="list-affix">{typeList}</div>
</ul>
<ul className="list-l-Menu">
<li className="MenuTitle">
<img src={explore2} alt="" width={18} className='mr5'/>项目类别
</li>
<div className="list-affix">{categoryList}</div>
</ul>
</div>
</Affix>
<div className="list-right boxShandow radius-2" style={{padding:0}}>
<div className="list-right boxShandow radius-2" style={{ padding: 0 }}>
<Spin spinning={isSpin}>
<div className="list-r-operation">
<div>
<Search
placeholder="输入项目名称关键字进行搜索"
enterButton="搜索"
enterButton={<img src={explore9} alt="" width={20}/>}
size="large"
onSearch={this.searchFun}
className="list-r-Search"
className="list-r-Search searchBox"
value={search}
onChange={this.changeSearchValue}
allowClear
/>
</div>
<div>
{
current_user && current_user.login &&
{current_user && current_user.login && (
<Popover
overlayClassName="newPopUl"
content={this.newItem()}
trigger={["click"]}
placement='bottom'
overlayClassName="newPopUl"
content={this.newItem()}
trigger={["click"]}
placement="bottom"
className="mr50"
>
<a className="ant-dropdown-link">
<span className="color-blue font-16"><img src={img_new} alt="" width="13px" /> 新建</span>
<a className="ant-dropdown-link font-15 actionBtnBox">
<i className='iconfont icon-jiashang1 mr5'></i>
</a>
</Popover>
}
)}
<Popover content={this.menu()} trigger={['click']} placement='bottom'>
<a className="ant-dropdown-link">
<span className="color-blue font-16">排序 <img src={img_array} alt="" width="10px" /></span>
<Popover
content={this.menu()}
trigger={["click"]}
placement="bottom"
>
<a className="ant-dropdown-link font-15 actionBtnBox top">
排序 <i className='iconfont icon-sanjiaoxing-down ml5'></i>
</a>
</Popover>
</div>
</div>
<ListItem {...this.props} {...this.state} projects={projectsList} getListData={this.getListData}></ListItem>
{this.pagination(total,limit,page)}
<ListItem
{...this.props}
{...this.state}
projects={projectsList}
getListData={this.getListData}
></ListItem>
{this.pagination(total, limit, page)}
</Spin>
</div>
<div style={{width: '320px'}} className='ml20'>
{/* 帮助手册 */}
{window.location.href.indexOf('osredm.jk') < 0 &&<div className='helpText font-28'>
<a href="https://help.osredm.com/#/git" target='_blank'>
<img src={explore10} alt="" className="helpImg1"/>
</a>
</div>}
{/* 热门项目(本周/本月) */}
<div className='hotProjects mt20'>
<div className='hotProjectsTitle font-17'>
<div className={`oneItemTil ${hotProjectTime === 7 ? 'activeHot' : ''}`} onClick={()=>{this.setState({hotProjectTime: 7}); this.getList(7)}}>
<img src={explore3} alt="" className="helpImg2 mr10" width={18}/>
<span>本周热门</span>
</div>
<div className={`oneItemTil ${hotProjectTime === 30 ? 'activeHot' : ''}`} onClick={()=>{this.setState({hotProjectTime: 30}); this.getList(30)}}>
<img src={explore4} alt="" className="helpImg2 mr10" width={18}/>
<span>本月热门</span>
</div>
</div>
{hotProjectList && hotProjectList.length > 0 && hotProjectList.map((i, index)=>{
return <div className='hotProjectItem' key={index}>
<div className="mInfos">
<Link target="_blank" to={`/${i.owner && i.owner.login}/${i.identifier}`} className="name task-hide font-16">{i.owner && i.owner.name}/{i.name}</Link>
<span className='font-14'>
<i className="iconfont icon-dianzan11 font-16 mr4"></i>{i.praises}
</span>
</div>
<div className="sInfos task-hide-2 font-14 mt10">
{i.description ? i.description : "暂无项目简介"}
</div>
</div>
})}
</div>
{/* 热门开发者 */}
<div className='hotProjects mt20'>
<div className='hotProjectsTitle font-17 pl30'>
<img src={explore5} alt="" className="helpImg2 mr10" width={18}/>开源贡献者TOP10
</div>
<div className='hotAuthor til font-15'>
<div className='hotAuthor1'>排名</div>
<div className='hotAuthor2'>贡献者</div>
<div className='hotAuthor3'>总积分</div>
</div>
{authorList && authorList.length > 0 && authorList.map((i, index) =>{
return <div className={`hotAuthor font-15 ${index%2 === 0 ? 'otherColor' : ''}`} key={index}>
<div className='hotAuthor1'>{index<3 ? <img src={index === 0 ? explore6 : index === 1 ? explore7 : explore8} alt='' width={23}/> : index+1}</div>
<Link target="_blank" to={`/${i.login}`} className='hotAuthor2 task-hide'>
<img src={getImageUrl(`/${i.avatar_url}`)} alt="" width={24} className='mr5'/>
<span style={{lineHeight: '3'}}>{i.name}</span>
</Link>
<div className='hotAuthor3 ml20'>{i.score}</div>
</div>
})}
</div>
</div>
</div>
</div>
)
);
}
}
export default Index;

View File

@ -524,3 +524,64 @@
}
}
.projectBannerBox{
.imgBox{
max-height: 250px;
}
.slick-arrow{
width: 70px;
height: 70px;
z-index: 2;
&::before{content: none;}
&.slick-prev{left: 50px;}
&.slick-next{right: 50px;}
}
.slick-dots{
width: 1200px;
left: 50%;
margin-left: -600px;
bottom: 7%;
position: absolute;
display: flex!important;
justify-content: center;
z-index: 2;
li{
background-color: rgba(225,225,225,0.5);
position: relative;
height: 3px;
width: 46px;
margin-right: 15px;
&::after{
position: absolute;
left: 0px;
width: 0px;
top:0px;
height: 100%;
content: "";
transition: 5.2s;
transition-property: width;
}
&.slick-active::after{
background-color: #fff;
width: 100%;
}
button{
position: absolute;
width: 100%;
height: 10px;
left:0px;
background-color: transparent!important;
border:none;
cursor: pointer;
color: transparent;
&::before{content: none;}
}
}
}
}
.newProject li{
cursor: pointer;
&:hover{
color: $primary-color;
}
}

View File

@ -6,7 +6,6 @@ import { Link } from 'react-router-dom';
import '../css/index.scss';
import Nodata from '../Nodata';
import './list.scss';
import img_parise from '../Images/parise.png';
import SpecialModal from './SpecialModal';
class IndexItem extends Component {
@ -73,11 +72,15 @@ class IndexItem extends Component {
{
item.platform === "educoder" ?
<a href="javascript:void(0)" style={{ cursor: "default" }} className="show-user-link">
<img className="p-r-photo" alt="" src={item.author && item.author.image_url} ></img>
<div className={`${item.recommend ? 'recommendItemPng mr5' : 'mr12'}`}>
<img className="p-r-photo explore" alt="" src={item.author && item.author.image_url} ></img>
</div>
</a>
:
<Link to={`/${item.author && item.author.login}`} className="show-user-link">
<img className="p-r-photo" alt="" src={getImageUrl(`/${item.author && item.author.image_url}`)} ></img>
<div className={`${item.recommend ? 'recommendItemPng mr5' : 'mr12'}`}>
<img className="p-r-photo explore" alt="" src={getImageUrl(`/${item.author && item.author.image_url}`)} ></img>
</div>
</Link>
}
<div className="p-r-Infos">
@ -101,13 +104,13 @@ class IndexItem extends Component {
</Tooltip>:""
}
</AlignCenter> */}
<a onClick={() => this.projectHref(`/${item.author.login}/${item.identifier}`, item.user_apply_signatures, item.id, item.is_secret, item.author.login, item.is_member)} className="hide-1 color-grey-3 font-18 task-hide fwt-500 " style={{ whiteSpace: "wrap", display: 'flex', width: 400 }}>
<a onClick={() => this.projectHref(`/${item.author.login}/${item.identifier}`, item.user_apply_signatures, item.id, item.is_secret, item.author.login, item.is_member)} className="hide-1 font-16 task-hide" style={{ whiteSpace: "wrap", flex: 1, color:'#232a39'}}>
{item.author.name}/{item.name}
{
item.forked_from_project_id ?
<span className="ml5">
<i className="iconfont icon-fork font-18 color-orange" />
</span>
<Tooltip title="该项目是一个fork仓库" className="ml5">
<i className="iconfont icon-fork font-16 color-orange" />
</Tooltip>
: ""
}
{
@ -123,19 +126,18 @@ class IndexItem extends Component {
</a>
<span className="p-r-tags">
<span className="pariseTag">
<img src={img_parise} alt="" className="pariseImg" /> {item.praises_count}
<i className='iconfont icon-morendianzan_icon font-12 mr3'></i> {item.praises_count}
</span>
<span>
<i className="iconfont icon-fork mr3 font-16" style={{ color: "#1B8FFF" }} />fork {item.forked_count}
<i className="iconfont icon-fork mr3 font-12"/>fork {item.forked_count}
</span>
</span>
</div>
<p className="break_word task-hide-2 mt10" style={{ maxHeight: "44px", lineHeight: "22px" }}>{item.description}</p>
<p className="break_word task-hide-2 mt10" style={{ maxHeight: "44px", lineHeight: "22px", color: '#525561'}}>{item.description}</p>
<div className="p-r-about">
<span className="p-r-detail">
{item.last_update_time ? <span><label>更新于</label>{item.time_ago}</span> : ""}
{item.language && item.language.id ? <span className="color-grey-3">{item.language.name}</span> : ""}
<span className="p-r-detail font-13">
{item.last_update_time ? <span><i className='iconfont icon-shijianicon font-13 mr3'/>更新于{item.time_ago}</span> : ""}
{item.language && item.language.id ? <span>{item.language.name}</span> : ""}
</span>
</div>
</div>

View File

@ -37,7 +37,7 @@ function SpecialModal({ visible , hideModal , sureModal , showNotification , use
}
}
return(
<Modal title="提示" visible={visible} closable={false} onCancel={hideModal} onOk={sure}>
<Modal title="提示" visible={visible} closable={false} maskClosable={false} onCancel={hideModal} onOk={sure}>
{
!user_apply_signatures || (user_apply_signatures && user_apply_signatures.status !== "waiting") ?
<div style={{width:"420px",textAlign:'center',margin:"0 auto",paddingBottom:"30px",position:"relative"}}>

BIN
src/forge/Main/img/left.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1018 B

View File

@ -11,6 +11,110 @@
display: flex;
align-items: flex-start;
flex-wrap:wrap;
&.exploreBox{
flex-wrap: nowrap;
.actionBtnBox{
color: #2a3ee9;
display: inline-flex;
align-items: center;
&.top{
position: relative;
top: -2px;
}
}
.searchBox .ant-input{
padding-left: 16px;
height: 36px;
border: 1px solid #ffffff;
background-color: #f8fbff !important;
}
.searchBox .ant-input-search-button{
height: 36px !important;
padding: 0 20px;
}
.helpText{
height:100px;
background-image:linear-gradient(131.52deg,#2a3ee9 0%,#428cff 46.02%,#6479ff 100%);
border:2px solid #ffffff;
.helpImg1{
width: 96%;
margin: 1.5% 2.1%;
}
}
.helpImg2{
vertical-align: text-bottom;
}
.hotProjects{
background-image:linear-gradient(180deg,#f4f5f8 0%,#fbfcfd 100%);
border:2px solid #ffffff;
}
.hotProjectsTitle{
color: #000000;
height:50px;
line-height: 50px;
background-color:rgba(243, 250, 255, 0.74);
box-shadow:0px 2px 3px rgba(212, 217, 255, 0.57);
}
.oneItemTil{
display: inline-block;
width: 158px;
text-align: center;
cursor: pointer;
}
.activeHot{
color:#2a3ee9;
border-bottom: 1px solid #2a3ee9;
}
.hotProjectItem{
padding-bottom: 16px;
margin: 20px 20px 16px;
border-bottom: 1px dashed #cccfd6;
.mInfos{
display: flex;
align-items: center;
height: 20px;
color: #656977;
.name{
flex:1;
color:#232a39;
}
}
.sInfos{
background: #F7F8F9;
font-weight: 400;
color:#525561;
line-height: 24px;
word-break: break-all;
}
}
.hotProjectItem:last-child{
border-bottom: none;
}
.hotAuthor{
height: 50px;
display: flex;
align-items: center;
&.til{
color:#989fab;
}
&.otherColor{
background-color:rgba(238, 243, 251, 0.76);
}
&:not(.til):hover{
background-color:rgba(225, 225, 225, 0.28);
}
}
.hotAuthor1{
width: 90px;
text-align: center;
}
.hotAuthor2{
flex: 1;
}
.hotAuthor3{
width: 75px;
}
}
}
.list-left{
width: 26%;
@ -19,13 +123,10 @@
margin-bottom: 20px;
}
.affix-list-left{
width: 26%;
width:200px;
box-sizing: border-box;
margin-bottom: 20px;
}
.affix-list-content{
padding-right:20px;
}
.list-left > div{
border:1px solid #eee;
}
@ -61,8 +162,7 @@
justify-content: space-between;
flex-wrap: wrap;
align-items: center;
padding:25px 30px;
border-bottom: 1px solid #E0E0E0;
padding: 15px 23px 0;
}
.list-r-Search{
width: 400px;
@ -100,23 +200,39 @@
}
.p-r-Item{
display: flex;
border-bottom:1px solid rgba(238,238,238,1);
padding:22px 0px;
justify-content: flex-start;
padding-top: 22px;
}
.boxShandow{
box-shadow:0px 2px 20px 10px rgba(0,0,0,0.03);
flex: 1;
background-image:linear-gradient(180deg,#f3f5f8 0%,#ffffff 100%);
box-shadow:8px 6px 18px rgba(171, 202, 255, 0.24) inset;
}
.p-r-photo{
width: 60px;
height: 60px;
border-radius: 50%;
margin-right: 22px;
margin-top: 8px;
&.explore{
background-color: white;
width: 32px;
height: 32px;
}
}
.recommendItemPng{
background-image: url('../Images/recommend1.png');
background-size: 100% 100%;
width: 50px;
height: 55px;
display: flex;
justify-content: center;
padding-top: 7px;
margin-left: -8px;
}
.p-r-Infos{
flex: 1;
width: 0;
padding-bottom: 19px;
border-bottom: 1px dashed #cccfd6;
}
.p-r-name{
display: flex;
@ -166,16 +282,16 @@
margin-left: 15px;
padding:0px 10px;
border-radius:15px;
background: #EBF4FE;
color: #333;
height: 24px;
line-height: 24px;
background: #e3ebff;
color:#656977;
height: 28px;
line-height: 28px;
display: block;
font-size: 12px;
display: flex;
}
.p-r-tags > span.pariseTag{
background: #FFF3DC;
background: rgba(223, 115, 20, 0.08);
}
.p-r-tags.large > span >label{
padding:0px 12px;
@ -207,10 +323,7 @@
}
.p-r-detail > span{
margin-right: 22px;
color: #888;
}
.p-r-detail > span > label{
color: #999;
color:#9b9eaa;
}
.p-r-about{
@ -218,7 +331,7 @@
justify-content: space-between;
flex-wrap: nowrap;
margin-top: 8px;
color: #666;
color:#9b9eaa;
}
.spincontent{
height:400px;

View File

@ -1,6 +1,6 @@
import React,{ useEffect , useState } from 'react';
import React, { useEffect, useState } from 'react';
import SubMenu from '../sub/SubMenu';
import { Table , Tooltip , Spin } from 'antd';
import { Table, Tooltip, Spin,Pagination } from 'antd';
import axios from 'axios';
import { Link } from 'react-router-dom';
import { truncateCommitId } from '../../common/util';
@ -12,32 +12,41 @@ import moment from 'moment';
function Tags(props) {
const [ source , setSource ] = useState(undefined);
const [ isSpin , setIsSpin ] = useState(true);
const { projectsId , owner } = props.match.params;
const [source, setSource] = useState(undefined);
const [isSpin, setIsSpin] = useState(true);
const [page, setPage] = useState(1);
const [total,setTotal] =useState(0);
const [limit,setLimit] =useState(10);
const { projectsId, owner } = props.match.params;
useEffect(() => {
if (projectsId) {
setIsSpin(true);
const url = `/${owner}/${projectsId}/tags.json`;
axios.get(url).then((result) => {
axios.get(url, {
params: {
limit,
page: page
}
}).then((result) => {
if (result) {
setSource(result.data);
setSource(result.data.tags);
setTotal(result.data.total_count);
setIsSpin(false);
}
}).catch(error => {})
}).catch(error => { })
}
}, [owner, projectsId]);
}, [owner, projectsId,page]);
const columns=[
const columns = [
{
title:"标签名",
dataIndex:"name",
key:1,
ellipsis:true,
width:"200px",
render:(txt,item)=>{
return(
title: "标签名",
dataIndex: "name",
key: 1,
ellipsis: true,
width: "200px",
render: (txt, item) => {
return (
<div className="tagBranch">
<Link className="hover tagClass" to={`/${owner}/${projectsId}/tree/${item.name}`}>{item.name}</Link>
</div>
@ -45,11 +54,11 @@ function Tags(props) {
}
},
{
title:"创建时间",
dataIndex:"time_ago",
key:2,
ellipsis:true,
render:(txt,item)=>{
title: "创建时间",
dataIndex: "time_ago",
key: 2,
ellipsis: true,
render: (txt, item) => {
return (
<span className="color-grey-3 tagModel">
{
@ -57,13 +66,13 @@ function Tags(props) {
<Tooltip placement="top" title={item.tagger.name}>
{
item.tagger.id ?
<Link className="mr3 tagModelImg" to={`/${item.tagger.login}`} >
<img src={getImageUrl(`/${item.tagger && item.tagger.image_url}`)} alt=""/>
</Link>
:
<span className="mr3 tagModelImg" style={{cursor:"default"}}>
<img src={getImageUrl(`/${item.tagger && item.tagger.image_url}`)} alt=""/>
</span>
<Link className="mr3 tagModelImg" to={`/${item.tagger.login}`} >
<img src={getImageUrl(`/${item.tagger && item.tagger.image_url}`)} alt="" />
</Link>
:
<span className="mr3 tagModelImg" style={{ cursor: "default" }}>
<img src={getImageUrl(`/${item.tagger && item.tagger.image_url}`)} alt="" />
</span>
}
</Tooltip>
}
@ -73,36 +82,36 @@ function Tags(props) {
}
},
{
title:"提交ID",
dataIndex:"id",
key:3,
ellipsis:true,
render:(txt,item)=>{
title: "提交ID",
dataIndex: "id",
key: 3,
ellipsis: true,
render: (txt, item) => {
return (
<Tooltip placement="top" title={`最后提交日期:${item.created_at_unix ? moment(item.created_at_unix*1000).format('YYYY-MM-DD'):''}`}>
<img src={Tree} alt="提交ID" width="22px" className="mr4"/>
<Tooltip placement="top" title={`最后提交日期:${item.created_at_unix ? moment(item.created_at_unix * 1000).format('YYYY-MM-DD') : ''}`}>
<img src={Tree} alt="提交ID" width="22px" className="mr4" />
<Link className="hover color-blue" to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.id}`)}`}>{truncateCommitId(item.id)}</Link>
</Tooltip>
)
}
},
{
title:"描述信息",
dataIndex:"message",
key:4,
ellipsis:true,
render:(txt,item)=>{
title: "描述信息",
dataIndex: "message",
key: 4,
ellipsis: true,
render: (txt, item) => {
return item.message || "--"
}
},
{
title:"下载",
dataIndex:"stage_type",
key:5,
ellipsis:true,
align:"center",
width:"204px",
render:(txt,item)=>{
title: "下载",
dataIndex: "stage_type",
key: 5,
ellipsis: true,
align: "center",
width: "204px",
render: (txt, item) => {
return (
<React.Fragment>
<a href={`${item.tarball_url}`} download className="btn-83">
@ -116,20 +125,36 @@ function Tags(props) {
}
}
]
return(
return (
<div>
<SubMenu tab={"tags"} projectsId={projectsId} owner={owner}/>
<SubMenu tab={"tags"} projectsId={projectsId} owner={owner} />
<Spin spinning={isSpin}>
<div className="tagSpin">
{
source && source.length > 0 &&
<Table
className="tagTable"
dataSource={source} columns={columns} pagination={false}></Table>
}
{
source && source.length === 0 && <Nonedata _html={'暂无数据~'}/>
}
{
source && source.length > 0 &&
<Table
rowKey={(record) => record.id}
className="tagTable"
dataSource={source} columns={columns} pagination={false}></Table>
}
{total > limit ? (
<div className="mt30 mb50 edu-txt-center">
<Pagination
simple
current={page}
total={total}
pageSize={limit}
onChange={(e)=>{setPage(e)}}
></Pagination>
</div>
) : (
""
)}
{
source && source.length === 0 && <Nonedata _html={'暂无数据~'} />
}
</div>
</Spin>
</div>

View File

@ -61,12 +61,12 @@ export default Form.create()(
const url = `/${owner}/${projectsId}/tags.json`;
axios
.get(url,{params:{
limit:1000
page:1,limit:1000
}})
.then(result => {
if (result) {
setTagList(result.data);
setOptions(renderTagList(result.data));
if (result.data) {
setTagList(result.data.tags);
setOptions(renderTagList(result.data.tags));
}
})
.catch(error => {

View File

@ -1,5 +1,5 @@
import React, { Component } from "react";
import { Input, Dropdown, Menu, Icon, Pagination, Spin } from "antd";
import { Input, Dropdown, Menu, Icon, Pagination, Spin, Button } from "antd";
import "./merge.css";
import "../Order/order.css";
import "../Order/index.scss";
@ -257,9 +257,10 @@ class merge extends Component {
</div>
{
data && data.user_admin_or_developer &&
<CheckProfile {...this.props} className="topWrapper_btn ml10" sureFunc={() => this.checkOperation()}>
+&nbsp;新建合并请求
</CheckProfile>
<Button className="topWrapper_btn ml10" onClick={() => this.checkOperation()}>+&nbsp;新建合并请求</Button>
// <CheckProfile {...this.props} className="topWrapper_btn ml10" sureFunc={() => this.checkOperation()}>
// +&nbsp;新建合并请求
// </CheckProfile>
}
</div>
<div className="f-wrap-between screenWrap">

View File

@ -6,6 +6,7 @@ import "./index.css";
import { turnbar , returnbar } from 'educoder';
import axios from "axios";
import { Base64 } from "js-base64";
const TextArea = Input.TextArea;
class UserSubmitComponent extends Component {
@ -63,7 +64,7 @@ class UserSubmitComponent extends Component {
filepath: filename ? filename : path,
branch: returnbar(branch),
new_branch: submitType === "1" ? values.branchname : undefined,
content,
content:editor_type === "upload" ? content : Base64.encode(content),
message: values.desc,
})
.then((result) => {

View File

@ -4,7 +4,7 @@ import { Dropdown, Icon, Menu, Pagination, Typography, Popconfirm, Spin } from '
import NoneData from '../Nodata';
import axios from 'axios';
import './order.css';
import CheckProfile from '../Component/ProfileModal/Profile';
// import CheckProfile from '../Component/ProfileModal/Profile';
const { Text } = Typography;
@ -189,7 +189,8 @@ class Milepost extends Component {
</ul>
{
data && data.user_admin_or_member ?
<CheckProfile {...this.props} className="topWrapper_btn" sureFunc={() => {this.props.history.push(`/${owner}/${projectsId}/milestones/new`)}}>新的里程碑</CheckProfile>
// <CheckProfile {...this.props} className="topWrapper_btn" sureFunc={() => {this.props.history.push(`/${owner}/${projectsId}/milestones/new`)}}>新的里程碑</CheckProfile>
<Link className="topWrapper_btn" to={`/${owner}/${projectsId}/milestones/new`}>新的里程碑</Link>
: ''
}
</div>

View File

@ -3,7 +3,7 @@ import { Link } from 'react-router-dom';
import { Dropdown, Menu, Icon, Pagination, Spin } from 'antd';
import './order.css';
import { FlexAJ } from '../Component/layout';
import CheckProfile from '../Component/ProfileModal/Profile';
// import CheckProfile from '../Component/ProfileModal/Profile';
import NoneData from '../Nodata';
import OrderItem from './OrderItem';
@ -246,7 +246,8 @@ class MilepostDetail extends Component {
}
{
current_user && current_user.login ?
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push(`/${owner}/${projectsId}/issues/${meilid}/new`)}} className="topWrapper_btn">创建疑修</CheckProfile>
// <CheckProfile {...this.props} sureFunc={()=>{this.props.history.push(`/${owner}/${projectsId}/issues/${meilid}/new`)}} className="topWrapper_btn">创建疑修</CheckProfile>
<Link className="topWrapper_btn" to={`/${owner}/${projectsId}/issues/${meilid}/new`}>创建疑修</Link>
:
<a className="topWrapper_btn" onClick={showLoginDialog}>创建疑修</a>
}

View File

@ -48,7 +48,7 @@ function New({ form , showNotification , history }) {
{getFieldDecorator("key",{
rules:[{required:true,message:"请输入密钥"}]
})(
<TextArea placeholder="支持以'ssh-rsa','ssh-dss','ssh-ed25519','ecdsa-sha2-nistp256','ecdsa-sha2-nistp384','ecdsa-sha2-nistp521'开头" autoSize={{ minRows: 6, maxRows: 6 }}/>
<TextArea placeholder="支持以'ssh-rsa','ssh-ed25519','ecdsa-sha2-nistp256','ecdsa-sha2-nistp384','ecdsa-sha2-nistp521'开头" autoSize={{ minRows: 6, maxRows: 6 }}/>
)}
</Form.Item>
<button style={{width:"100px"}} onClick={submit} className="but25">确定</button>

View File

@ -30,11 +30,11 @@ function Collaborator(props){
{
author && author.type === "Organization" ?
<span>
<span style={{cursor:"pointer"}} className={nav === "1" ? "font-18 text-black color-blue":"font-18 text-black"} onClick={()=>{setNav("1");setNewId(undefined)}}>协作者管理</span>
<span style={{cursor:"pointer"}} className={nav === "1" ? "font-18 text-black color-blue":"font-18 text-black"} onClick={()=>{setNav("1");setNewId(undefined)}}>成员管理</span>
<span style={{cursor:"pointer"}} className={nav === "2" ? "font-18 text-black ml30 color-blue":"font-18 text-black ml30"} onClick={()=>{setNav("2");setNewId(undefined);setNewGroupId(undefined)}}>团队管理</span>
</span>
:
<span className="font-18 text-black">协作者管理</span>
<span className="font-18 text-black">成员管理</span>
}
{
nav === "1" &&

View File

@ -74,7 +74,7 @@ class Index extends Component {
<p>
<Link to={`/${owner}/${projectsId}/settings/collaborators`} className="w-100">
<i className="iconfont icon-chengyuan font-18 mr10"></i>
协作者管理
成员管理
</Link>
</p>
</li>

View File

@ -8,7 +8,7 @@ const { Search } = Input;
const LIMIT = 15;
function SpecialProject(props){
const [ page , setPage] = useState(1);
const [ searchValue , SetSearchValue ] = useState(undefined);
const [ searchValue , setSearchValue ] = useState(undefined);
const [ total , setTotal ] = useState(0);
const [ list , setList ] = useState(undefined);
const [ status , setStatus ] = useState(undefined);
@ -22,7 +22,7 @@ function SpecialProject(props){
setLoading(true);
Init(searchValue, status);
}
},[page,project_id]);
},[page, project_id, searchValue]);
function Init(search,status){
const url = `/apply_signatures.json`;
@ -125,9 +125,9 @@ function SpecialProject(props){
}).catch(error=>{setLoading(false)})
}
function searchList(){
function searchList(value){
setSearchValue(value);
setLoading(true);
Init(searchValue,status);
}
const menu=(
@ -155,9 +155,7 @@ function SpecialProject(props){
enterButton="搜索"
style={{width:400}}
size="middle"
value={searchValue}
onChange={(e)=>SetSearchValue(e.target.value)}
onSearch={searchList}
onSearch={(value)=>searchList(value)}
/>
<Dropdown overlay={menu} placement="bottomRight">
<span>

View File

@ -42,7 +42,7 @@ export default (props)=>{
active
}
return(
<Box>
<Box className="mt20">
<Short>
<Setnav header={<Title>团队设置</Title>} nav={array}></Setnav>
</Short>

View File

@ -39,6 +39,45 @@
width: 1200px;
margin:0px auto;
padding-top:18px;
.newsAndTrends{
.contentNews{
padding-bottom: 35px;
line-height: 1.5;
color:#26314d;
}
.newTil{
font-weight:700;
color:#1e2941;
display: inline-block;
margin-bottom: 15px !important;
}
.contentNews, .titleHead{
display: flex;
align-items: center;
}
.titleHead{
justify-content: space-between;
font-weight:700;
color:#1e2941;
margin-bottom: 20px;
padding-right: 0px;
}
.borTop{
width: 90%;
border-top: 1px dashed rgba(0, 55, 175, 0.32);
}
.newImg{
min-width: 376px;
height:120px;
margin-right: 18px;
text-align: center;
line-height: 120px;
img{
max-width: 100%;
max-height: 100%;
}
}
}
}
.list{
display: flex;
@ -143,6 +182,12 @@
padding:15px 20px;
border-top: 1px solid #eee;
}
.proYu{
margin: 0 20px 0 23px;
display: flex;
align-items: baseline;
.ant-progress{flex-grow: 1;}
}
}
}
.subNavs{
@ -413,4 +458,102 @@
}
}
}
}
.bottomOrgBox{
background-color: #fff;
padding: 0 30px;
.flexBox{
display: flex;
align-items: center;
justify-content: space-between;
}
.overviewBox{
border-color: #fff;
.headCont{
font-weight: bold;
color:#202d40;
height: 44px;
padding: 0 20px 0 16px;
background-image: url('../Images/organizationBg1.png');
background-size: 100% 100%;
}
}
.linkOrg{
color:#104fd9;
font-weight: normal;
}
.handpickProjects{
flex-wrap: wrap;
padding-bottom: 50px;
.project{
width: 48%;
height: 160px;
margin-top: 25px;
padding: 16px 30px 12px 16px;
background-size: 100% 100%;
background-image: url('../Images/organizationBg2.png');
.projectDesc, .projectName{
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
word-break: break-all;
}
.projectDesc{
-webkit-line-clamp: 2;
height: 60px;
}
}
.labelBox{
width: 102px;
height: 28px;
border-radius: 4px;
display: inline-block;
background-color: rgba(116, 160, 255, 0.13);
color:#223c77;
text-align: center;
margin-right: 22px
}
.spanBox{
flex-grow: 1;
text-align: right;
}
}
.organizationDetailContent{
padding: 0 16px;
}
}
.navBox{
display: inline-block;
padding-bottom: 25px;
.oneItemNav{
color: #333;
width: 73px;
height:32px;
display: inline-block;
text-align: center;
border:1px solid #d0d0d0;
cursor: pointer;
&.active{
color:#ffffff;
width: 83px;
background-color:#104fd9;
border-color: #104fd9;
}
&.left{
border-radius:4px 0px 0px 4px;
border-right-style: none;
}
&.right{
border-radius:0px 4px 4px 0px;
border-left-style: none;
}
}
}
.newProject li{
cursor: pointer;
&:hover{
color: $primary-color;
}
}

View File

@ -6,7 +6,10 @@ import './Index.scss';
import Item from './ListItem';
import Right from './RightBox';
import NoData from '../Nodata';
import CheckProfile from '../Component/ProfileModal/Profile';
// import CheckProfile from '../Component/ProfileModal/Profile';
import RenderHtml from 'src/components/render-html';
import img from '../Images/organizationImg.png';
import Box from '../users/GeneralView/ConcentrateBox';
import { Menu , Pagination , Dropdown , Spin } from 'antd';
import axios from 'axios';
@ -19,10 +22,18 @@ function List(props){
const [ search , setSearch ] = useState(undefined);
const [ page , setPage ] = useState(1);
const [ sortBy , setSortBy ] = useState("updated_on");
const [ active, setActive] = useState(0);
const [ visible , setVisible ] = useState(false);
const [ value , setValue ] = useState([]);
const [ proList, setProList] = useState([]);
const {showCompeleteDialog,completeProfile,history,mygetHelmetapi} = props;
const OIdentifier = props.match.params.OIdentifier;
const organizeDetail = props.organizeDetail;
useEffect(()=>{
getList();
},[])
useEffect(()=>{
if(OIdentifier){
setIsSpin(true);
@ -51,6 +62,37 @@ function List(props){
setSearch(value);
}
function getList() {
const url = `/organizations/${OIdentifier}/is_pinned_projects.json`;
axios.get(url).then(result=>{
if(result && result.data){
let p = result.data.projects;
setProList(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 = `/organizations/${OIdentifier}/is_pinned_projects/pin.json`;
axios.post(url,{
is_pinned_project_ids
}).then(result=>{
if(result && result.data){
setVisible(false);
getList();
}
}).catch(error=>{})
}
const menu=(
<Menu onClick={(e)=>setSortBy(e.key)}>
<Menu.Item key="updated_on">更新时间排序</Menu.Item>
@ -60,19 +102,51 @@ function List(props){
</Menu>
)
const menu_new=(
<ul>
<li>
<CheckProfile {...props} sureFunc={()=>{props.history.push(`/projects/deposit/new/${OIdentifier}`)}}>新建项目</CheckProfile>
<ul className='newProject'>
<li onClick={()=>{props.history.push(`/projects/deposit/new/${OIdentifier}`)}}>新建项目
{/* <CheckProfile {...props} sureFunc={()=>{props.history.push(`/projects/deposit/new/${OIdentifier}`)}}>新建项目</CheckProfile> */}
</li>
<li>
<CheckProfile {...props} sureFunc={()=>{props.history.push(`/projects/mirror/new/${OIdentifier}`)}}>导入项目</CheckProfile>
<li onClick={()=>{props.history.push(`/projects/mirror/new/${OIdentifier}`)}}>导入项目
{/* <CheckProfile {...props} sureFunc={()=>{props.history.push(`/projects/mirror/new/${OIdentifier}`)}}>导入项目</CheckProfile> */}
</li>
</ul>
)
return(
<div className="list">
<div className="list-l">
<div className='bottomOrgBox'>
<Box
visible={visible}
onCancel={()=>setVisible(false)}
onSure={onSure}
getProjectListUrl={`/organizations/${OIdentifier}/projects.json`}
choosed={value}
completeProfile={completeProfile}
showCompeleteDialog={showCompeleteDialog}
history={history}
createProjectUrl={`/projects/deposit/new/${OIdentifier}`}
/>
{/* 新闻动态 */}
{organizeDetail && (organizeDetail.news_banner_id || organizeDetail.news_content) && <div className='newsAndTrends'>
{(organizeDetail.news_banner_id || organizeDetail.news_content) && <div className='titleHead font-16'>
<img src={img} alt='' width='26px'/>
新闻动态
<div className='borTop'></div>
</div>}
<div className='contentNews'>
{organizeDetail.news_banner_id && <div className='newImg'><img src={`${mygetHelmetapi && mygetHelmetapi.current_main_site_url}/api/attachments/${organizeDetail.news_banner_id}`} alt=''/></div>}
{organizeDetail.news_content && <div style={{flexGrow: 1}} className='pr10 font-15'>
{organizeDetail.news_url ? <a className='font-16 newTil' href={organizeDetail.news_url}>{organizeDetail.news_title}</a> : <p className='font-16 newTil'>{organizeDetail.news_title}</p>}
<div>{organizeDetail.news_content}</div>
</div>}
</div>
</div>}
{/* 概览or仓库 */}
<div className='navBox'>
<span className={`oneItemNav left ${active === 0 ? 'active' : ''}`} onClick={()=>{setActive(0)}}>概览</span>
<span className={`oneItemNav right ${active === 1 ? 'active' : ''}`} onClick={()=>{setActive(1)}}>仓库</span>
</div>
<div className="list">
{active === 1 && <div className="list-l">
<div>
<div className="head">
<div style={{width:"370px"}}>
@ -109,14 +183,43 @@ function List(props){
<Pagination simple current={page} total={totalCount} onChange={(page)=>setPage(page)}/>
</div>
}
</div>
<Right
admin={organizeDetail && organizeDetail.is_admin}
OIdentifier={OIdentifier}
showCompeleteDialog={props.showCompeleteDialog}
completeProfile={props.completeProfile}
history={props.history}
/>
</div>}
{active === 0 && <div className='overviewBox list-l'>
{proList && organizeDetail && (proList.length > 0 || (proList.length === 0 && organizeDetail.is_admin)) && <div className='handpickProjectsBox'>
<div className='headCont flexBox font-16'>
精选项目
{organizeDetail.is_admin && <a className='linkOrg font-15' onClick={()=>setVisible(true)}><icon className="iconfont icon-bianji1 font-15 mr5"></icon>自定义精选项目</a>}
</div>
<div className='handpickProjects flexBox' style={{justifyContent: proList && proList.length !== 0 ? 'space-between' : 'center'}}>
{proList && proList.length > 0 ? proList.map(item =>{
return <div className='project' key={item.id}>
<Link to={`/${OIdentifier}/${item.identifier}`} className="font-16 linkOrg projectName">{item.name}</Link>
<div className='font-15 mt5 projectDesc' style={{color:'#26314d'}}>{item.description}</div>
<div className='flexBox'>
{item.category && item.category.name && <span className='labelBox'>{item.category.name}</span>}
<div className='spanBox'>
<span style={{color:'#333', marginRight: '15px'}}><i className='iconfont icon-shixing' style={{color:'#666'}}></i>{item.watchers_count}</span>
<span style={{color:'#333'}}><i className='iconfont icon-fork' style={{color:'#666'}}></i>{item.forked_count}</span>
</div>
</div>
</div>
}): <NoData _html="暂无数据" small={organizeDetail && organizeDetail.memo}/>}
</div>
</div>}
{organizeDetail && organizeDetail.memo && <div className='organizationIntroduceBox'>
<div className='headCont font-16 flexBox mb20'>组织介绍</div>
<RenderHtml className="organizationDetailContent" value={organizeDetail && organizeDetail.memo} url={props.history.location}/>
</div>}
{organizeDetail && proList && !organizeDetail.memo && proList.length === 0 && !organizeDetail.is_admin && <NoData _html="暂无数据"/>}
</div>}
<Right
admin={organizeDetail && organizeDetail.is_admin}
OIdentifier={OIdentifier}
showCompeleteDialog={props.showCompeleteDialog}
completeProfile={props.completeProfile}
history={props.history}
/>
</div>
</div>
)
}

View File

@ -6,7 +6,8 @@ import { getImageUrl } from 'educoder';
import { Link } from 'react-router-dom';
import Nodata from '../Nodata';
import CheckProfile from '../Component/ProfileModal/Profile';
// import CheckProfile from '../Component/ProfileModal/Profile';
import { Progress } from 'antd';
const Span = styled.span`{
color:#888;
@ -40,11 +41,13 @@ const Img = styled.img`{
function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,completeProfile }) {
const [ memberData, setMemberData ] = useState(undefined);
const [ groupData, setGroupData ] = useState(undefined);
const [ languages, setLanguages ] = useState(undefined);
useEffect(()=>{
if(OIdentifier){
getMember(OIdentifier);
getGroup(OIdentifier);
getLanguage(OIdentifier);
}
},[OIdentifier])
@ -64,8 +67,40 @@ function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,complet
}
}).catch(error=>{})
}
function getLanguage(iden){
const url = `/organizations/${iden}/languages.json`;
axios.get(url).then(result=>{
if(result && result.data){
let data = [];
Object.keys(result.data).map(item=>{
data.push({name:item,percent:result.data[item].substring(0, result.data[item].length-1),color:getColor()});
})
setLanguages(data);
}
}).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);
str+=arr[num];
}
return str;
}
return(
<div className="list-r">
{/* 仓库语言 */}
{languages && languages.length>0 && <div className="box">
<div className="head">
<span className="font-16">仓库语言</span>
</div>
<div className="content">
{languages.map(item=>{return <div className='proYu'><span className='font-15' style={{width: '110px'}}>{item.name}</span><Progress percent={item.percent} strokeColor={item.color}/></div>})}
</div>
</div>}
{
memberData && memberData.organization_users && memberData.organization_users.length>0 ?
<Box name="组织成员" count={memberData && memberData.total_count} url={`/${OIdentifier}/members`}>
@ -89,13 +124,13 @@ function RightBox({ OIdentifier , history , admin , showCompeleteDialog ,complet
name="组织团队"
count={groupData && groupData.total_count}
bottom={
admin &&
<CheckProfile
showCompeleteDialog={showCompeleteDialog}
completeProfile={completeProfile}
sureFunc={()=>history.push(`/${OIdentifier}/teams/new`)}
className={"ant-btn ant-btn-primary"}
>新建团队</CheckProfile>
admin && <Link className="ant-btn ant-btn-primary" to={`/${OIdentifier}/teams/new`}>新建团队</Link>
// <CheckProfile
// showCompeleteDialog={showCompeleteDialog}
// completeProfile={completeProfile}
// sureFunc={()=>history.push(`/${OIdentifier}/teams/new`)}
// className={"ant-btn ant-btn-primary"}
// ></CheckProfile>
}
url={`/${OIdentifier}/teams`}
>

View File

@ -62,7 +62,6 @@ export default Form.create()(
if(result && result.data){
showNotification("组织信息更新成功!");
if(values.name !== organizeDetail.name){
console.log("false111");
history.push(`/${values.name}/setting`);
}
updateFunc && updateFunc(values.name,values.description);
@ -74,7 +73,6 @@ export default Form.create()(
function getImage(image){
setImageFlag(true);
setImage(image);
console.log(image);
}
//
@ -108,7 +106,7 @@ export default Form.create()(
}
callback();
}
return(
<div>
<WhiteBack>
@ -137,12 +135,13 @@ export default Form.create()(
{helper(
"组织描述:",
"description",
[],
<TextArea
[{ required: true, message: "请输入组织描述" }],
<TextArea
placeholder="请输入组织名称"
maxLength={200}
onChange={(e)=>{setDescNum(e.target.value ? e.target.value.length :0)}}
/>
autoSize
/>,true
)}
</div>
{helper(
@ -160,12 +159,12 @@ export default Form.create()(
{helper(
'可见性:',
"visibility",
[],
[{ required: true, message: "请选择可见性" }],
<Radio.Group>
<Radio value="common" style={radioStyle}>公开</Radio>
<Radio value="limited" style={radioStyle}>受限<span>仅对登录用户可见</span></Radio>
<Radio value="privacy" style={radioStyle}>私有<span>仅对组织成员可见</span></Radio>
</Radio.Group>
</Radio.Group>,true
)}
{helper(
'权限:',
@ -181,7 +180,7 @@ export default Form.create()(
<InputNumber value="-1" max={1000} style={{width:"350px"}}/>,false,false,
"当输入栏为空时,默认数量无限制"
)}
<p>选择头像:</p>
<p className='required'>选择头像:</p>
<UploadImage url={image&&image.startsWith('images/avatars/Organization')?getImageUrl(`/${image}`):image} getImage={getImage}/>
<Button type={"primary"} onClick={updateDetail}>更新组织设置</Button>
</Form>

View File

@ -0,0 +1,149 @@
import React, { forwardRef , useCallback , useEffect, useState } from 'react';
import { Form , Input , Button } from 'antd';
import { WhiteBack } from '../../Component/layout';
import Title from '../../Component/Title';
import styled from 'styled-components';
import UploadImg from '../../../components/uploadImg';
import axios from 'axios';
import MDEditor from '../../../modules/tpm/challengesnew/tpm-md-editor';
const TextArea = Input.TextArea;
const Div = styled.div`{
padding:20px 30px;
}`
export default Form.create()(
forwardRef((props)=>{
const { form , organizeDetail , showNotification} = props;
const [ descNum , setDescNum ] = useState(0);
const [ description, setDescription] = useState(undefined);
const [ imageId , setImageId ] = useState(undefined);
const { getFieldDecorator , validateFields , setFieldsValue } = form;
useEffect(()=>{
if(organizeDetail){
setFieldsValue({
...organizeDetail,
max_repo_creation:organizeDetail.max_repo_creation===-1 ? "":organizeDetail.max_repo_creation
})
setImageId(organizeDetail.news_banner_id);
setDescNum(organizeDetail.news_content ? organizeDetail.news_content.length : 0);
setDescription(organizeDetail.memo);
}
},[organizeDetail])
const helper = useCallback(
(label, name, rules, widget , isRequired , flag , help ) => (
<div>
<span className={isRequired?"required":""}>{label}</span>
<Form.Item help={help}>
{getFieldDecorator(name, { rules, validateFirst: true , valuePropName:flag ? "checked":"value" })(widget)}
</Form.Item>
</div>
),
[]
);
//
function updateDetail(){
validateFields((error,values)=>{
if(!error){
const {news_url, news_title, news_content} = values;
console.log('news_title', news_title, news_content);
if((!news_title && news_content) || (!news_content && news_title)){
console.log('cuo');
const cont = !news_title ? 'news_title' : 'news_content';
console.log(cont);
form.setFields({[cont]: {value:form.getFieldValue(cont),errors:[new Error('新闻动态标题和内容必须同时输入')]}});
}else{
const params = {
news_url,
news_title,
news_content,
news_banner_id: imageId,
memo: description
}
console.log('成功', params);
const url = `/organizations/${organizeDetail.id}/update_other.json`;
axios.post(url,params).then(result=>{
if(result && result.data){
showNotification("组织信息更新成功!");
// form.resetFields();
setFieldsValue({
...params
})
}
}).catch(error=>{})
}
}
})
}
function getImageId(imageId){
setImageId(imageId);
}
function deleteImg(){
setImageId(undefined);
}
return(
<div>
<WhiteBack>
<Title>组织首页管理</Title>
<Div>
<Form className='homePageManage'>
{/* 新闻动态编辑 */}
{helper('新闻动态图片',
'news_banner_id',
[],
<UploadImg getImageId={getImageId} imageId={imageId}/>
)}
<div style={{marginTop: '-30px', position: 'relative', zIndex: '1'}} className='mb20 ml30'><a onClick={()=>{deleteImg()}}>删除</a></div>
{helper(
"新闻动态原文链接",
"news_url",
[],
<Input
placeholder="请输入新闻动态原文链接"
maxLength={50}
/>
)}
{helper(
"新闻动态标题",
"news_title",
[],
<Input
placeholder="请输入新闻动态"
maxLength={45}
/>
)}
<div className="pr">
<span className="toprightNum">{descNum}/200</span>
{helper(
"新闻动态内容",
"news_content",
[],
<TextArea
placeholder="请输入新闻内容"
maxLength={200}
onChange={(e)=>{setDescNum(e.target.value ? e.target.value.length :0)}}
autoSize
/>
)}
</div>
<p className='mt30'>组织介绍</p>
<MDEditor
placeholder={"请输入组织介绍"}
height={500}
mdID={"order-new-description"}
initValue={description}
onChange={setDescription}
></MDEditor>
<Button type={"primary"} onClick={updateDetail}>确定</Button>
</Form>
</Div>
</WhiteBack>
</div>
)
})
)

View File

@ -24,24 +24,31 @@ const Hooks = Loadable({
loader: () => import("./TeamSettingHooks"),
loading: Loading,
});
const HomePageSet = Loadable({
loader: () => import("./TeamSettingHomePage"),
loading: Loading,
});
export default (( props )=>{
const pathname = props.location.pathname;
const OIdentifier = props.match.params.OIdentifier;
function returnActive (pathname){
let a = 0;
if(pathname === `/${OIdentifier}/setting/member`){
if(pathname === `/${OIdentifier}/setting/home`){
a = 1;
}else if(pathname === `/${OIdentifier}/setting/group`){
}else if(pathname === `/${OIdentifier}/setting/member`){
a = 2;
}else if(pathname === `/${OIdentifier}/setting/hooks`){
}else if(pathname === `/${OIdentifier}/setting/group`){
a = 3;
}else if(pathname === `/${OIdentifier}/setting/hooks`){
a = 4;
}
return a;
}
const active = returnActive(pathname);
const array = {list:[
{name:'基本设置',icon:"icon-base",href:`/${OIdentifier}/setting`},
{name:'组织首页管理',href:`/${OIdentifier}/setting/home`},
{name:'组织成员管理',icon:"icon-zuzhichengyuan",href:`/${OIdentifier}/setting/member`},
{name:'组织团队管理',icon:"icon-zuzhixiangmu",href:`/${OIdentifier}/setting/group`},
// {name:'web',icon:"icon-zhongqingdianxinicon10",href:`/${OIdentifier}/setting/hooks`}
@ -49,7 +56,7 @@ export default (( props )=>{
active
}
return(
<Box>
<Box className="mt20">
<Short>
<Setnav header={<Title>组织设置</Title>} nav={array}></Setnav>
</Short>
@ -75,6 +82,12 @@ export default (( props )=>{
<Member {...props} />
)}
></Route>
<Route
path="/:OIdentifier/setting/home"
render={() => (
<HomePageSet {...props} />
)}
></Route>
<Route
path="/:OIdentifier/setting"
render={() => (

View File

@ -2,7 +2,6 @@ import React , { useEffect , useState } from 'react';
import { Route, Switch , Link } from "react-router-dom";
import Loadable from "react-loadable";
import Loading from "../../../Loading";
import {AlignCenter} from '../../Component/layout';
import Cards from '../../Component/Cards';
import axios from 'axios';
import '../Index.scss';
@ -83,10 +82,10 @@ function Detail(props){
img={detail.avatar_url}
rightBtn={
<React.Fragment>
{flag && !buttonflag && detail.is_admin ?
<Link to={`/${OIdentifier}/setting`} className="color-blue ml10 font-14">设置<i className="iconfont icon-shezhi2 ml3 fr"></i></Link>
{flag && !buttonflag && detail.is_admin ?
<Link to={`/${OIdentifier}/setting`} className="font-15 settingsLink"><i className="iconfont icon-shezhi2 mr5"></i><span>设置</span></Link>
:""}
{buttonflag &&
{buttonflag &&
<span className="subNavs">
<Link to={`/${OIdentifier}/members`} className={pathname ===`/${OIdentifier}/members` ? "active":""}><span>组织成员</span>{detail.num_users && <lable>{detail.num_users}</lable>}</Link>
<Link to={`/${OIdentifier}/teams`} className={pathname ===`/${OIdentifier}/teams` ? "active":""}><span>组织团队</span>{detail.num_teams &&<lable>{detail.num_teams}</lable>}</Link>
@ -95,14 +94,14 @@ function Detail(props){
</React.Fragment>
}
bottomInfos={
!buttonflag && <div>
!buttonflag && <div className='mt5'>
{
detail.location &&
<span className="color-grey-6"><i className="iconfont icon-weizhi mr3 font-16 color-grey-6"></i>{detail.location}</span>
detail.location &&
<span className="bottomInfos"><i className="iconfont icon-weizhi mr3 font-16"></i>{detail.location}</span>
}
{
detail.website &&
<a href={detail.website} target="_blank" className="ml20 color-grey-6"><i className="iconfont icon-lianjie mr3 font-14"></i>{detail.website}</a>
detail.website &&
<a href={detail.website} target="_blank" className="ml20 bottomInfos"><i className="iconfont icon-lianjie mr3 font-14"></i>{detail.website}</a>
}
</div>
}

View File

@ -1,8 +1,5 @@
import React, { Component } from "react";
import { Upload, Icon } from "antd";
import { getUploadActionUrl, appendFileSizeToUploadFileAll } from "educoder";
import axios from "axios";
const { Dragger } = Upload;
class Read extends Component {
constructor(props) {
@ -22,53 +19,43 @@ class Read extends Component {
});
};
handleChange = (info) => {
let reader = new FileReader();
reader.readAsText(info.fileList[0].originFileObj, "UTF-8");
reader.onload = (e) => {
this.state.fileContent = e.target.result;
this.props.load && this.props.load(this.state);
};
};
beforeUpload = (file) => {
const forbidden_type = [
"jpg",
"jpeg",
"png",
"ico",
"bmp",
"gif",
"pdf",
"csv",
"xlsx",
"xls",
"tif",
"svg",
"psd",
"cdr",
"webp",
];
const { fileList } = this.state;
const { size } = this.props;
const isLt100M = file.size / 1024 / 1024 < size;
const file_type = file.type.split("/").slice(-1)[0];
if (fileList && fileList.length > 0) {
this.props.showNotification("文件已存在, 请删除后再上传");
return false;
} else if (!isLt100M) {
this.props.showNotification(`文件大小必须小于${size}MB!`);
} else if (file_type && forbidden_type.indexOf(file_type) !== -1) {
this.props.showNotification(`不支持${file_type}类型`);
return false;
} else {
this.setState({
fileList: [file],
fileName: file.name,
})
}
return false;
};
// 上传 文件转base64
customRequest = (option) =>{
const formData = new FormData();
formData.append('files[]', option.file);
const reader = new FileReader();
reader.readAsDataURL(option.file);
const {load} = this.props;
reader.onloadend = function(e){
if(e.target.result){
option.onSuccess();
const base64 = e.target.result.substring(e.target.result.indexOf('base64')+7, e.target.result.length);
load({
fileName: option.file.name,
fileContent: base64
});
}
}
}
render() {
//判断是否已经提交,如已提交评论则上一条评论数据清除
const { icon, size } = this.props;
@ -76,10 +63,10 @@ class Read extends Component {
const upload = {
name: "file",
fileList: fileList,
onChange: this.handleChange,
customRequest: this.customRequest,
onRemove: this.onAttachmentRemove,
beforeUpload: this.beforeUpload
};
beforeUpload: this.beforeUpload,
};
return (
<Dragger {...upload} className={this.props.className}>
@ -91,9 +78,9 @@ class Read extends Component {
<p className="ant-upload-text">
拖动文件或<span className="color-blue">点击此处上传</span>
</p>
<p className="mt10">
暂仅支持文格式不支持图片,excel等不可以txt读取的文件
</p>
{/* <p className="mt10">
暂仅支持文格式不支持图片,excel等不可以txt读取的文件
</p> */}
<p className="mt10">
文件名请使用英文且不得超过{size}MB
</p>

View File

@ -62,6 +62,12 @@ ul,ol,dl{
color: #666;
display: inline-block;
}
.ProjectListIndex{
background-color:#f5f7fa;
.ant-affix{
z-index: 1;
}
}
@media screen and (max-width: 1200px){
.main{
width:100%;
@ -223,26 +229,34 @@ form{
}
}
.list-l-Menu{
margin-bottom: 12px!important;
border-radius:2px;
background-color: #fff;
box-shadow: 0px 0px 2px rgba(0,0,0,0.2);
margin-bottom: 35px!important;
background-image:linear-gradient(180deg,#f4f5f8 0%,#fbfcfd 100%);
border:2px solid #ffffff;
.list-affix{
min-height: 20px;
max-height: 248px;
max-height: 285px;
overflow-y: auto;
&::-webkit-scrollbar-thumb{
background-color:#e6edf9;
box-shadow: none
}
&::-webkit-scrollbar-track{
display: none;
}
&::-webkit-scrollbar{
background: none;
}
}
li{
font-size: 1rem;
padding:0px 0px 0px 20px;
box-sizing: border-box;
color: #333;
color:#4c5b76;
position: relative;
p{
height: 62px;
line-height: 62px;
height: 48px;
line-height: 48px;
width: 100%;
border-bottom: 1px solid #eee;
display: flex;
justify-content: space-between;
cursor: pointer;
@ -251,39 +265,38 @@ form{
a{
width:100%;
}
& span:last-child{
color: #999;
}
}
&:last-child > p{
border-bottom: none;
}
&:not(.MenuTitle):hover{
background-color: #fafafa;
&:not(.MenuTitle):not(.active):hover{
background-color: rgba(225, 225, 225, 0.3);
}
}
li.active{
background-color: #fafafa;
background-color: rgba(70, 106, 255, 0.09);
color:#2a3ee9;
}
li.active::before{
position: absolute;
left: 0px;
top: 15px;
top: 10px;
width: 6px;
content: '';
height: 33px;
height: 29px;
background: #4154f1;
}
.MenuTitle{
font-size: 16px;
font-size: 17px;
background-size: 100% 100%;
color: #333!important;
height: 62px;
line-height: 62px;
border-bottom: 1px solid #E0E0E0;
color:#000000;
height: 71px;
line-height: 48px;
font-weight: 400;
padding-left: 20px;
display: flex;
align-items: center;
span{
display: block;
width: 50%;
@ -292,7 +305,6 @@ form{
}
span:hover{
color: #4154f1;
.iconfont{
color: #4154f1 !important;
}

View File

@ -1,11 +1,12 @@
import React, { useEffect, useState } from 'react';
import { Modal , Checkbox , Spin , Input } from 'antd';
import Axios from 'axios';
import CheckProfile from '../../Component/ProfileModal/Profile';
// import CheckProfile from '../../Component/ProfileModal/Profile';
import './Index.scss';
const { Search } = Input;
const limit = 20;
function ConcentrateBox({ visible , onCancel , onSure , username , choosed , history , showCompeleteDialog , completeProfile }) {
function ConcentrateBox({ visible , onCancel , onSure , getProjectListUrl , choosed , history , showCompeleteDialog , completeProfile, createProjectUrl }) {
const [ page , setPage ]= useState(1);
const [ total , setTotal ]= useState(0);
const [ pageSize , setPageSize ] = useState(false);
@ -18,7 +19,7 @@ function ConcentrateBox({ visible , onCancel , onSure , username , choosed , his
const [ copyList , setCopyList ] = useState([]);
const [ copyAllList , setCopyAllList ] = useState([]);
useEffect(()=>{
if(visible){
setIsSpin(true);
@ -54,7 +55,7 @@ function ConcentrateBox({ visible , onCancel , onSure , username , choosed , his
},[value])
function getProjectList(p,s) {
const url = `/users/${username}/projects.json`;
const url = getProjectListUrl;
Axios.get(url,{
params:{
page:p,limit,is_public: "public",search:s,choosed
@ -137,7 +138,7 @@ function ConcentrateBox({ visible , onCancel , onSure , username , choosed , his
>
<Spin spinning={isSpin}>
<div className="operateDiv">
<p>最多可选取6个公开仓库</p>
<div className='mb5'>最多可选取6个公开仓库</div>
<Search
placeholder="请输入项目名称进行搜索"
onSearch={onSearch}
@ -170,11 +171,12 @@ function ConcentrateBox({ visible , onCancel , onSure , username , choosed , his
{
(list && list.length === 0) && (copyList && copyList.length === 0) &&
<div style={{textAlign:"center"}}>您还没有公开的{search && `${search}`}项目先去
<CheckProfile
<span onClick={()=>{history.push(createProjectUrl)}} className="color-blue">新建项目</span>
{/* <CheckProfile
showCompeleteDialog={showCompeleteDialog}
completeProfile={completeProfile}
sureFunc={()=>{history.push(`/projects/deposit/new`)}}
className="color-blue">新建项目</CheckProfile>
sureFunc={()=>{history.push(createProjectUrl)}}
className="color-blue">新建项目</CheckProfile> */}
</div>
}
</Spin>

View File

@ -49,11 +49,12 @@ function ConcentrateProject({userLogin,current,showCompeleteDialog,completeProfi
visible={visible}
onCancel={()=>setVisible(false)}
onSure={onSure}
username={userLogin}
getProjectListUrl={`/users/${userLogin}/projects.json`}
choosed={value}
completeProfile={completeProfile}
showCompeleteDialog={showCompeleteDialog}
history={history}
createProjectUrl={`/projects/deposit/new`}
/>
{
list && list.length>0 &&

View File

@ -17,8 +17,9 @@
margin-right: 0px;
}
.name{
word-break: break-all;
font-size: 16px;
color: #4CACFF;
color: #4154f1;
}
.desc{
color: #999;
@ -71,6 +72,9 @@
max-height: 210px;
overflow-y: auto;
padding-left: 30px;
.ant-checkbox-wrapper + .ant-checkbox-wrapper{
margin-left: 0px;
}
}
.operateDiv{
padding:20px 30px
@ -87,8 +91,9 @@
width: 50%;
margin-left: 0px!important;
display: flex;
align-items: center;
.ant-checkbox{
padding-top: 3px;
height: 16px;
}
span:last-child{
flex:1;

View File

@ -42,8 +42,8 @@ $flex:flex;
padding:20px 25px;
background-color:rgba(250,250,250,1);
.imgBox{
width: 190px;
height: 90px;
width: 100px;
height: 100px;
display: flex;
align-items: center;
justify-content: center;
@ -261,7 +261,7 @@ ul.ant-menu.menuStyle{
bottom: -1px;
height: 2px;
left: 0px;
background-color: #1890ff;
background-color: #4154f1;
content:"";
}
}

View File

@ -1,6 +1,6 @@
import React, { Component } from "react";
import { Menu, Input, Spin, Pagination, Popover, Button, Divider } from "antd";
import CheckProfile from '../Component/ProfileModal/Profile';
// import CheckProfile from '../Component/ProfileModal/Profile';
import axios from "axios";
import ListItem from "../Main/IndexItem";
@ -114,13 +114,19 @@ class InfosUser extends Component {
);
newItem =()=> (
<ul>
<li>
<ul className='newProject'>
<li onClick={()=>{this.props.history.push('/projects/deposit/new')}}>新建项目
{/* <CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/deposit/new')}}>新建项目</CheckProfile> */}
</li>
<li onClick={()=>{this.props.history.push('/projects/mirror/new')}}>导入项目
{/* <CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/mirror/new')}}>导入项目</CheckProfile> */}
</li>
{/* <li>
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/deposit/new')}} >新建项目</CheckProfile>
</li>
<li>
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/mirror/new')}}>导入项目</CheckProfile>
</li>
</li> */}
</ul>
);

View File

@ -1,11 +1,12 @@
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';
import axios from 'axios';
import CheckProfile from '../Component/ProfileModal/Profile';
// import CheckProfile from '../Component/ProfileModal/Profile';
const limit = 15;
function Team(props){
@ -57,7 +58,8 @@ function Team(props){
<p>
{
current_user && current_user.login === username &&
<CheckProfile {...props} sureFunc={()=>{props.history.push('/organize/new')}}><i className="iconfont icon-xinjian1 mr3 font-14"></i>新建组织</CheckProfile>
// <CheckProfile {...props} sureFunc={()=>{props.history.push('/organize/new')}}><i className="iconfont icon-xinjian1 mr3 font-14"></i></CheckProfile>
<Link className="ant-btn ant-btn-primary" to={`/organize/new`}><i className="iconfont icon-xinjian1 mr3 font-14"></i>新建组织</Link>
}
<Dropdown overlay={menu}>
<a>排序<i className="iconfont icon-sanjiaoxing-down ml3 font-14"></i></a>

5
src/global.scss Normal file
View File

@ -0,0 +1,5 @@
$primary-color: #466aff;
$primary-color-hover: #6684FE;
$primary-color-active: #1A47FF;
$link-color: #466aff;
$link-black-color: #05101a;

View File

@ -2,7 +2,7 @@ import React, { memo, useState, useEffect } from 'react';
import { Collapse, Button } from 'antd';
import moment from 'moment';
import Line from '../Line';
import { getTaskCategory, getTaskList } from '../../military/task/api';
import { getTaskCategory, getRecommendTasks } from '../../military/task/api';
import { taskModeIdArr } from '../../military/task/static';
import './index.scss';
@ -61,10 +61,9 @@ function FifthSection({ fifth, history }) {
curPage: 1,
pageSize: 3,
orderBy: 'visitsDesc',
isDelete: '0',
recommend: '1',
};
getTaskList(params).then(data => {
getRecommendTasks(params).then(data => {
if (data) {
serTaskArr(data.rows);
}

View File

@ -4,7 +4,7 @@ $deg2: -36deg;
$bgcolorlist:#254dea #e33230 #0766fb #f02c66 #6038ff #f85e55 #c13cff #2cb840 #5744f6 #e9862e;
.home-fifth-section {
min-height: 50vh;
// min-height: 50vh;
background: linear-gradient(#fff 0%, #cbdcff 100%);
.fifth-main {

View File

@ -1,5 +1,5 @@
.home-first-section {
height: 90vh;
height: 93vh;
min-height: 650px;
// background: linear-gradient(
// #1a2358 0%,
@ -32,6 +32,7 @@
align-items: center;
height: 80vh;
min-height: 600px;
margin-top: 6vh;
}
.website {

View File

@ -57,5 +57,8 @@
.footerbottom {
background-color: #162046 !important;
}
.newFooter{
top: 20px;
}
}

View File

@ -2,8 +2,9 @@ import React, { memo, useEffect, useState } from 'react';
import { Button, Modal } from 'antd';
import { Link } from 'react-router-dom';
import bg from '../img/modal.png';
import bg_local from '../img/modal_local.png';
// import bg from '../img/modal.png';
import bg from '../img/ckds.jpg';
// import bg_local from '../img/modal_local.png';
import './index.scss';
@ -37,9 +38,9 @@ function QzModal() {
width='728px'
maskClosable={false}
>
<img src={window.location.href.indexOf('osredm.jk')>-1?bg_local: bg} />
<Link to="/competition/qz2022" className="qz-btn">查看详情</Link>
{/* <img src={window.location.href.indexOf('osredm.jk')>-1?bg_local: bg} /> */}
<img src={bg} />
<a target="_blank" href="https://ckds.osredm.com" className="qz-btn">查看详情</a>
</Modal>
)
}

View File

@ -6,6 +6,7 @@
img {
border-radius: 2px;
width: 100%;
}
}

View File

@ -43,12 +43,13 @@ function SecondSection({ second ,main_web_site_url ,btnUrl}) {
if (communicates.length) {
setLeftItem(communicates[0]);
setList(communicates.slice(1, 5));
//
communicates.length < 5 && (setting.slidesToShow = 1)
}
}
}).catch(error => { });
}, [])
function goDetail(id) {
window.open(`${main_web_site_url}/forums/${id}/detail`);
}

View File

@ -129,7 +129,7 @@
.slick-list {
width: 33.75em;
margin: 0 auto;
z-index: 1001;
z-index: 999;
}
.issue-item {
text-align: center;

View File

@ -42,7 +42,7 @@ function ThirdSection({ third }) {
<div className="circle-item">
<div className="circle-item-box">
<div className="circle-item-num">
<div className="circle-item-num" style={{fontSize:statisticsNum.users_count>9999999?'24px':statisticsNum.users_count>99999?'36px':'48px'}}>
<CountUp {...countUpProps} end={statisticsNum.users_count} />
</div>
</div>

BIN
src/home/img/ckds.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

View File

@ -3,7 +3,7 @@ import { TPMIndexHOC } from '../modules/tpm/TPMIndexHOC';
import { isMobile } from 'educoder';
import './index.scss';
import Slider from './Slider';
// import Slider from './Slider';
// import QzModal from './QzModal';
import FirstSection from './FirstSection';
import SecondSection from './SecondSection';
@ -128,8 +128,8 @@ function HomePage({ history }) {
return (
<div className="homePage">
<Slider />
{/* <QzModal /> */}
{/* <Slider />
<QzModal /> */}
<div id="home-first-section" className="home-first-section">
<FirstSection first={first} />
</div>

View File

@ -9,6 +9,7 @@
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-all;
}
// 2行省略号
.ellipsis-2 {
@ -106,52 +107,6 @@
line-height: 1.6875em;
opacity: 0.8;
}
// 首页特定头部样式起
&.newHeaders {
// background-color: #1a2358;
background-color: #0037af;
z-index: 1000;
}
.newFooter{
background: inherit;
}
.head-nav {
min-width: auto;
}
.head-nav ul#header-nav li a {
font-size: 1em;
color: #fff;
}
.head-nav ul#header-nav li:hover a,
.head-nav ul#header-nav li.active a {
color: #ffa13a;
}
.head-nav ul#header-nav li.active a::after {
background-color: #ffa13a;
}
.logoDiv img {
min-width: 2.8125em;
height: 2.8125em;
}
.color-home {
color: #fff;
}
.color-home:hover {
color: #4154f1;
}
.register-button {
height: 3em;
margin-left: 1.25em;
padding: 0 1.5625em;
font-size: 0.875em;
}
// 首页特定头部样式止
}
// 波浪样式起

138
src/managements/api.js Normal file
View File

@ -0,0 +1,138 @@
import fetch,{main_web_site_url} from './fetch';
import { notification } from 'antd';
// 新增后台菜单
export async function createMenu(data){
let res = await fetch({
url: '/api/menu/create',
method: 'post',
data,
});
return res;
}
//删除后台菜单
export async function deleteMenu(menuId){
let res = await fetch({
url: `/api/menu/delete/${menuId}`,
method: 'post',
});
return res;
}
//修改菜单状态
export async function updateMenuStatus(menuId, hidden){
let res = await fetch({
url: `/api/menu/updateHidden/${menuId}?hidden=${hidden}`,
method: 'post',
});
return res;
}
//修改菜单信息
export async function updateMenu(menuId, data){
let res = await fetch({
url: `/api/menu/update/${menuId}`,
method: 'post',
data,
});
return res;
}
// 分页查询后台菜单
export async function menuList(parentId,params) {
let res = await fetch({
url: `/api/menu/list/${parentId}`,
method: 'get',
params,
});
return res;
}
// 树形结构返回所有菜单列表
export async function treeList() {
let res = await fetch({
url: `/api/menu/treeList`,
method: 'get',
});
return res;
}
//添加角色
export async function createRole(data){
let res = await fetch({
url: '/api/role/create',
method: 'post',
data,
});
return res;
}
//获取所有角色
export async function roleList() {
let res = await fetch({
url: `/api/role/listAll`,
method: 'get',
});
return res;
}
//修改角色信息
export async function updateRole(roleId, data){
let res = await fetch({
url: `/api/role/update/${roleId}`,
method: 'post',
data,
});
return res;
}
//修改角色状态
export async function updateRoleStatus(roleId, status){
let res = await fetch({
url: `/api/role/updateStatus/${roleId}?status=${status}`,
method: 'post',
});
return res;
}
//删除角色
export async function deleteRole(roleId){
let res = await fetch({
url: `/api/role/delete?ids=${roleId}`,
method: 'post',
});
return res;
}
//为角色赋予菜单
export async function allocMenu(roleId, menuIds){
let res = await fetch({
url: `/api/role/allocMenu?roleId=${roleId}&menuIds=${menuIds}`,
method: 'post',
});
return res;
}
//通过角色id获取菜单列表
export async function listMenu(roleId) {
let res = await fetch({
url: `/api/role/listMenu/${roleId}`,
method: 'get',
});
return res;
}
//修改用户角色
export async function updateUserRole(userId, ruleId){
let res = await fetch({
url: `/api/admin/role/update/?adminId=${userId}&roleIds=${ruleId}`,
method: 'post',
});
return res;
}
//获取所有管理员用户
export async function adminUserList() {
let res = await fetch({
url: `/api/admin/list`,
method: 'get',
});
return res;
}
// 获取用户角色
export async function getUserRole(adminId) {
let res = await fetch({
url: `/api/admin/role/${adminId}`,
method: 'get',
});
return res;
}

View File

@ -0,0 +1,22 @@
// 公告开始
export const noticeStatus = [
{ code: 0, name: "关闭" },
{ code: 1, name: "正常" },
{ code: 2, name: "草稿" },
];
export const noticeType = [
{ code: 4, name: "招标" },
{ code: 1, name: "更正" },
{ code: 2, name: "中标" },
{ code: 3, name: "废标" },
{ code: 5, name: "技术资产" },
{ code: 6, name: "成交" },
];
export const noticeChecked = [
{ code: 0, name: "未通过" },
{ code: 1, name: "已发布" },
{ code: 2, name: "待审核" },
];
//公告结束

View File

@ -0,0 +1,88 @@
/**
* 生成唯一字符串
*/
export function uuid() {
const s = [];
const hexDigits = '0123456789abcdef';
for (let i = 0; i < 36; i += 1) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = '4';
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
s[8] = '-';
s[13] = '-';
s[18] = '-';
s[23] = '-';
s[0] = 'abcdefghigklmnopqrst'.substr(Math.floor(Math.random() * 0x10), 1);
return s.join('');
}
// 获取当前日期前N天数组
// format='MM-dd'
export function beforeDayArr(length = 31, myDate = new Date(), flag = 1) {
myDate.setDate(myDate.getDate());
let dateArray = [];
let dateTemp;
for (let i = length; i > 0; i--) {
dateTemp = (myDate.getMonth() + 1) + "-" + myDate.getDate();
dateArray.unshift(dateTemp);
myDate.setDate(myDate.getDate() - flag);
}
return dateArray;
}
/**
* param拼接到url地址上,get请求
* @param {*} url
* @param {*} params
* @param {*} prefix
*/
export const paramToUrl = (url, params) => {
if (url.indexOf('?') == -1) {
// url += '?r=' + Math.random();
url += '?';
}
let time = 0;
for (let attr in params) {
if (!time) {
url += attr + '=' + params[attr] || '';
time++;
} else {
url += '&' + attr + '=' + params[attr] || '';
}
}
return url;
}
const isDev = window.location.port == 8000;
// const isdev2 = window.location.hostname === 'www.educoder.net'
export const TEST_HOST = "https://testforgeplus.trustie.net/"
export function getImageUrl(path) {
const local = 'https://testforgeplus.trustie.net';
if (isDev) {
return `${local}/${path}`
}
return `https://forgeplus.trustie.net${path}`;
}
export const uploadNameSizeSeperator = '  '
export function appendFileSizeToUploadFileAll(fileList) {
return fileList && fileList.map(item => {
if (item.name&&item.name.indexOf(uploadNameSizeSeperator) == -1) {
return Object.assign({}, item, { name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}` })
}
return item;
})
}
export function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
if (bytes == 0) return '0 Byte';
if (!bytes) return '';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return parseFloat(bytes / Math.pow(1024, i), 2).toFixed(1) + ' ' + sizes[i];
}

View File

@ -1,4 +1,4 @@
import { Button, message, Modal, Select, Tooltip,Table } from "antd";
import { Button, message, Modal, Select, Tooltip,Table, Popconfirm } from "antd";
import React, { useEffect, useMemo, useState } from "react";
import Link from "react-router-dom/Link";
import axios from "axios";
@ -46,6 +46,15 @@ function Competition(props){
return <a href={`/competition/${record.identifier}`} target="_blank" className="primary-link">{text}</a>
}
},
{
title: "报名开始时间",
dataIndex: "start_at",
key: "start_at",
align: "center",
render: (text, record)=>{
return text ? moment(text).format('YYYY-MM-DD HH:mm:ss'): '--'
}
},
{
title: "报名截止时间",
dataIndex: "enroll_date",
@ -73,13 +82,24 @@ function Competition(props){
return text?'是':'否'
}
},
{
title: "排序",
dataIndex: "sort_no",
key: "sort_no",
align: "center",
},
{
title: '操作',
dataIndex: 'id',
key: 'action',
fixed: 'right',
align: "center",
render: (text, record)=>{
return <Button size="small" type="link" href={`/managements/competition/customize/edit/${record.identifier}`}>编辑</Button>
return <React.Fragment>
<Popconfirm title={`您确定要${record.status? '下' : '上'}架该竞赛吗?`} onConfirm={()=>{confirm(record)}}>
<Button size="small" type={record.status? 'danger' : 'primary'} className="mr10">{record.status? '下' : '上'}</Button>
</Popconfirm>
<Link to={`/managements/competition/customize/edit/${record.identifier}`}>编辑</Link>
</React.Fragment>
}
}
];
@ -97,7 +117,17 @@ function Competition(props){
}).finally(()=>{
setLoading(false);
})
}, [])
}, [reload])
// /
function confirm(record){
axios.post(`/competition_infos/${record.identifier}/online_switch.json`).then(res=>{
if(res && res.data && !res.data.status){
setReload(Math.random());
message.success('修改成功');
}
})
}
return(
<div className="centerbox competitionList">

View File

@ -1,5 +1,5 @@
import React, { useEffect, useState, useCallback, useRef } from "react";
import { Input, Row, Col, Button, Form, message, Spin, Checkbox, DatePicker, Upload, Icon } from 'antd';
import { Input, Row, Col, Button, Form, message, Spin, Checkbox, DatePicker, Upload, Icon,InputNumber } from 'antd';
import axios from "axios";
import moment from 'moment';
import MDEditor from 'src/modules/tpm/challengesnew/tpm-md-editor';
@ -21,6 +21,9 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
const [plainOptions, setPlainOptions] = useState([]);
const [admin_data, setAdmin_data] = useState([]);
const [contentMd,setContentMd]=useState(false);
const [guideMd,setGuideMd]=useState(false);
let tableRef = useRef();
useEffect(() => {
@ -35,6 +38,7 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
identifier: details.identifier,
content: details.content,
banner_url: details.banner_url,
applet_banner_url: details.applet_banner_url,
video_url: details.video_url,
enroll_template: details.enroll_template,
guide: details.guide,
@ -42,35 +46,46 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
zones_local: details.zones_local,
sub_competitions: details.sub_competitions,
zones: details.zones,
start_at: moment(details.start_at),
enroll_date: moment(details.enroll_date),
upload_date: moment(details.upload_date),
about_us: details.about_us,
enroll_columns:details.enroll_columns
enroll_columns:details.enroll_columns,
sort_no:details.sort_no
// manager_ids: details.manager_ids,
};
setFieldsValue(initValue);
setContent(details.content);
setGuide(details.guide);
setAbout_us(details.about_us);
setTimeout(() => {
setContent(details.content);
setContentMd(true);
}, 200);
setTimeout(() => {
setGuide(details.guide);
}, 800);
setGuideMd(true);
}, 300);
setTimeout(() => {
setAbout_us(details.about_us);
document.querySelector('#title').focus();
}, 1400);
setLoading(false);
}, 600);
if (details.is_local) {
zonesArr(details.zones_local);
} else {
zonesArr(details.zones);
}
setAdmin_data(Array.isArray(details.admin_data) ? details.admin_data : []);
}else{
setLoading(false);
}
setLoading(false);
}).catch((error) => {
}).finally(() => {
setLoading(false);
})
}else{
setTimeout(() => {
setContentMd(true);
}, 200);
setTimeout(() => {
setGuideMd(true);
}, 300);
}
}, [id])
@ -125,6 +140,10 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
setFieldsValue({
[key]: `/api/attachments/${info.file.response.id}`
})
} else if (key === 'applet_banner_url') {
setFieldsValue({
[key]: `/api/attachments/${info.file.response.id}`
})
}
}
}
@ -191,6 +210,11 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
<Input placeholder="请输入参赛单位" onBlur={() => { verify("identifier") }} />
)}
{helper('排序号',
'sort_no',
[{ required: true, message: "请正确输入排序号" }],
<InputNumber placeholder="请输入整数排序号" precision={0}/>
)}
<Form.Item className="video-box" label="Banner图">
<Row gutter={8}>
@ -212,6 +236,26 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
</Row>
</Form.Item>
<Form.Item className="video-box" label="封面图">
<Row gutter={8}>
<Col span={12}>
{getFieldDecorator('applet_banner_url', {
rules: [],
})(<Input placeholder="请上传封面图或填写封面图地址" onBlur={() => { verify("video_url") }} />)}
</Col>
<Col span={12}>
<Upload
accept=".png,jpg,.jpeg,.svg"
action={getUploadActionUrl()}
onChange={(info) => { handleChange(info, 'applet_banner_url') }}
showUploadList={false}
>
<Button className="upload"><Icon type="upload" />上传封面图</Button>
</Upload>
</Col>
</Row>
</Form.Item>
<Form.Item className="video-box" label="视频地址" >
<Row gutter={8}>
<Col span={12}>
@ -252,7 +296,6 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
</Form.Item>
{helper('赛项',
'sub_competitions',
[{ required: true, message: "请填写赛项" }],
@ -260,6 +303,17 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
'请填写赛项,每个赛项之间以英文“,”隔开。如:赛项1,赛项2,赛项3'
)}
{helper(
"报名开始时间",
"start_at",
[],
<DatePicker
format={format}
placeholder="请选择时间"
showTime
/>
)}
{helper(
"报名截止时间",
"enroll_date",
@ -296,14 +350,14 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
{helper('赛区(内网)',
'zones_local',
[{ required: true, message: "请填写赛区,每个赛区之间以英文“,”隔开。如:赛区1,赛区2,赛区3" }],
<Input placeholder="请填写赛区,每个赛区之间以英文“,”隔开。如:赛区1,赛区2,赛区3" onBlur={() => { verify("zones_local") }} onBlur={zonesChange} />,
<Input placeholder="请填写赛区,每个赛区之间以英文“,”隔开。如:赛区1,赛区2,赛区3" onBlur={zonesChange} />,
'请填写赛区,每个赛区之间以英文“,”隔开。如:赛区1,赛区2,赛区3'
)}
{helper('赛区(外网)',
'zones',
[{ required: true, message: "请填写赛区,每个赛区之间以英文“,”隔开。如:赛区1,赛区2,赛区3" }],
<Input placeholder="请填写赛区,每个赛区之间以英文“,”隔开。如:赛区1,赛区2,赛区3" onBlur={() => { verify("zones") }} onBlur={zonesChange} />,
<Input placeholder="请填写赛区,每个赛区之间以英文“,”隔开。如:赛区1,赛区2,赛区3" onBlur={zonesChange} />,
'请填写赛区,每个赛区之间以英文“,”隔开。如:赛区1,赛区2,赛区3'
)}
@ -315,26 +369,26 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
</Form.Item>
<Form.Item className="mb0 mdEditor" label={'大赛介绍'}>
<MDEditor
{contentMd&&<MDEditor
placeholder={"请输入大赛介绍"}
height={500}
mdID={"competition-content"}
initValue={content}
onChange={(value) => { onContentChange(value, 'content') }}
/>
/>}
{getFieldDecorator("content", {
rules: [{ required: true, message: "请输入大赛介绍" }],
})(<Input style={{ display: "none" }} />)}
</Form.Item>
<Form.Item className="mb0 mdEditor" label={'赛事指南'}>
<MDEditor
{guideMd&&<MDEditor
placeholder={"请输入赛事指南"}
height={500}
mdID={"competition-guide"}
initValue={guide}
onChange={(value) => { onContentChange(value, 'guide') }}
/>
/>}
{getFieldDecorator("guide", {
rules: [{ required: true, message: "请输入赛事指南" }],
})(<Input style={{ display: "none" }} />)}

View File

@ -28,4 +28,7 @@
.ant-form-explain+.ant-form-extra{
display: none !important;
}
.ant-input-number{
width: 200px;
}
}

Some files were not shown because too many files have changed in this diff Show More