合并最新代码到内网分支
|
@ -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']
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -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']
|
||||
}
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
"educoder": ["./src/common/educoder.js"],
|
||||
"forge":["./src/forge"],
|
||||
"military":["./src/military"],
|
||||
"components":["./src/components"],
|
||||
}
|
||||
},
|
||||
"exclude": [
|
||||
|
|
|
@ -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,6 +216,7 @@
|
|||
"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",
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
32
src/App.js
|
@ -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} />
|
||||
|
|
|
@ -25,7 +25,7 @@ if (isDev) {
|
|||
}
|
||||
debugType = window.location.search.indexOf('debug=t') !== -1 ? 'teacher' :
|
||||
window.location.search.indexOf('debug=s') !== -1 ? 'student' :
|
||||
window.location.search.indexOf('debug=a') !== -1 ? 'a' : parsed.debug || 'admin'
|
||||
window.location.search.indexOf('debug=a') !== -1 ? 'a' : parsed.debug || ''
|
||||
}
|
||||
window._debugType = debugType;
|
||||
export function initAxiosInterceptors(props) {
|
||||
|
@ -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(
|
||||
|
|
|
@ -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} />
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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';
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
|
@ -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>
|
||||
|
||||
)
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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(()=>{
|
||||
|
|
|
@ -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)=>{
|
||||
|
|
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 2.8 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 993 B |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 873 B |
After Width: | Height: | Size: 8.1 KiB |
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" }}>
|
||||
|
|
|
@ -12,6 +12,21 @@ 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 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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
|
@ -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"}}>
|
||||
|
|
After Width: | Height: | Size: 1018 B |
After Width: | Height: | Size: 1018 B |
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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" &&
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -42,7 +42,7 @@ export default (props)=>{
|
|||
active
|
||||
}
|
||||
return(
|
||||
<Box>
|
||||
<Box className="mt20">
|
||||
<Short>
|
||||
<Setnav header={<Title>团队设置</Title>} nav={array}></Setnav>
|
||||
</Short>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -7,6 +7,9 @@ import Item from './ListItem';
|
|||
import Right from './RightBox';
|
||||
import NoData from '../Nodata';
|
||||
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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Link } from 'react-router-dom';
|
|||
import Nodata from '../Nodata';
|
||||
|
||||
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`}>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
})
|
||||
)
|
|
@ -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={() => (
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
|
|
|
@ -91,9 +91,9 @@ class Read extends Component {
|
|||
<p className="ant-upload-text">
|
||||
拖动文件或<span className="color-blue">点击此处上传</span>
|
||||
</p>
|
||||
<p className="mt10">
|
||||
{/* <p className="mt10">
|
||||
暂仅支持文件格式,不支持图片,excel等不可以txt读取的文件
|
||||
</p>
|
||||
</p> */}
|
||||
<p className="mt10">
|
||||
文件名请使用英文且不得超过{size}MB
|
||||
</p>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -2,10 +2,11 @@ import React, { useEffect, useState } from 'react';
|
|||
import { Modal , Checkbox , Spin , Input } from 'antd';
|
||||
import Axios from 'axios';
|
||||
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>
|
||||
|
|
|
@ -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 &&
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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:"";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
$primary-color: #466aff;
|
||||
$primary-color-hover: #6684FE;
|
||||
$primary-color-active: #1A47FF;
|
||||
$link-color: #466aff;
|
||||
$link-black-color: #05101a;
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -57,5 +57,8 @@
|
|||
.footerbottom {
|
||||
background-color: #162046 !important;
|
||||
}
|
||||
.newFooter{
|
||||
top: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
img {
|
||||
border-radius: 2px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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`);
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@
|
|||
.slick-list {
|
||||
width: 33.75em;
|
||||
margin: 0 auto;
|
||||
z-index: 1001;
|
||||
z-index: 999;
|
||||
}
|
||||
.issue-item {
|
||||
text-align: center;
|
||||
|
|
|
@ -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>
|
||||
|
|
After Width: | Height: | Size: 152 KiB |
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
// 首页特定头部样式止
|
||||
}
|
||||
|
||||
// 波浪样式起
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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: "待审核" },
|
||||
];
|
||||
//公告结束
|
|
@ -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];
|
||||
}
|
|
@ -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">
|
||||
|
|
|
@ -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" }} />)}
|
||||
|
|
|
@ -28,4 +28,7 @@
|
|||
.ant-form-explain+.ant-form-extra{
|
||||
display: none !important;
|
||||
}
|
||||
.ant-input-number{
|
||||
width: 200px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
import { Modal } from 'antd';
|
||||
|
||||
export default (
|
||||
handleOk,
|
||||
title,
|
||||
content,
|
||||
handleCancel) => {
|
||||
return Modal.confirm({
|
||||
title: title || "警告",
|
||||
content: content || "确认删除?",
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
onOk() {
|
||||
handleOk && handleOk();
|
||||
},
|
||||
onCancel() {
|
||||
handleCancel && handleCancel();
|
||||
}
|
||||
});
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
let fontSizeText = 16;
|
||||
let clientWidth = document.body.clientWidth;
|
||||
if (clientWidth < 1000) {
|
||||
fontSizeText = 16
|
||||
} else if (clientWidth >= 1000 && clientWidth <= 2000) {
|
||||
fontSizeText = 14 + (clientWidth - 1000) / 500;
|
||||
} else if (clientWidth > 2000) {
|
||||
fontSizeText = 16 + (clientWidth - 2000) / 500;
|
||||
} else if (clientWidth > 3000) {
|
||||
fontSizeText = 18 + (clientWidth - 3000) / 2000;
|
||||
}
|
||||
let fontSizeTitle = 1.25 * fontSizeText;
|
||||
|
||||
|
||||
export default ({ id,className, title, xData, yData }) => {
|
||||
|
||||
useEffect(() => {
|
||||
let newEchartBar = document.getElementById(id) && echarts.init(document.getElementById(id));
|
||||
let textColor = "#7988a5";
|
||||
let normalColor = "#e8e8ed";
|
||||
|
||||
let option = {
|
||||
grid: {
|
||||
left: "3%",
|
||||
top: "15%",
|
||||
right: "8%",
|
||||
bottom: 0,
|
||||
containLabel: true
|
||||
},
|
||||
title: {
|
||||
text: title,
|
||||
fontSize: fontSizeTitle,
|
||||
position: 'inside',
|
||||
textStyle: {
|
||||
color: textColor
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
type: "shadow",
|
||||
textStyle: {
|
||||
color: "#fff"
|
||||
}
|
||||
},
|
||||
},
|
||||
xAxis: [{
|
||||
type: "category",
|
||||
data: xData,
|
||||
axisPointer: {
|
||||
type: "shadow"
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: textColor,
|
||||
fontSize: .75 * fontSizeText
|
||||
},
|
||||
interval: 0,
|
||||
rotate: 40
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: normalColor
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
}],
|
||||
yAxis: [{
|
||||
type: "value",
|
||||
minInterval: 1,
|
||||
nameTextStyle: {
|
||||
color: textColor,
|
||||
fontSize: fontSizeText
|
||||
},
|
||||
axisLabel: {
|
||||
formatter: "{value}",
|
||||
textStyle: {
|
||||
color: textColor,
|
||||
fontSize: fontSizeText
|
||||
}
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: normalColor
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: normalColor
|
||||
}
|
||||
},
|
||||
}],
|
||||
series: [{
|
||||
type: "bar",
|
||||
data: yData,
|
||||
barWidth: "60%",
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: {
|
||||
type: "linear",
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [{
|
||||
offset: 0,
|
||||
color: "#deeefe"
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: "#2c8bff"
|
||||
}
|
||||
],
|
||||
globalCoord: false
|
||||
}
|
||||
}
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
// position: ['-20%', -1.2 * fontSizeText],
|
||||
position: "top",
|
||||
// color: "#2c8bff",
|
||||
color: '#555',
|
||||
fontSize: fontSizeText,
|
||||
formatter: function (params) {
|
||||
// var percent = 0;
|
||||
// percent = ((params.value / allStaff.num) * 100).toFixed(0);
|
||||
return params.value || ''
|
||||
// + '\n' + percent + '%';
|
||||
},
|
||||
}
|
||||
}]
|
||||
};
|
||||
newEchartBar && newEchartBar.setOption(option);
|
||||
}, [id, title, xData, yData])
|
||||
|
||||
return (
|
||||
<div id={id} key={id} className={className} style={{minHeight:"20vh"}}>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
|
||||
let fontSizeText = 16;
|
||||
let clientWidth = document.body.clientWidth;
|
||||
if (clientWidth < 1000) {
|
||||
fontSizeText = 16
|
||||
} else if (clientWidth >= 1000 && clientWidth <= 2000) {
|
||||
fontSizeText = 14 + (clientWidth - 1000) / 500;
|
||||
} else if (clientWidth > 2000) {
|
||||
fontSizeText = 16 + (clientWidth - 2000) / 500;
|
||||
} else if (clientWidth > 3000) {
|
||||
fontSizeText = 18 + (clientWidth - 3000) / 2000;
|
||||
}
|
||||
|
||||
const colorList = ["#27e8b4", '#77b4fd', '#ffd55f', '#ac90ef', '#9E87FF'];
|
||||
|
||||
export default ({ id = "uid", className, title, xData, seriesArr }) => {
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
let newEchartBar = document.getElementById(id) && echarts.init(document.getElementById(id));
|
||||
let option = {
|
||||
backgroundColor: '#fff',
|
||||
legend: {
|
||||
icon: 'circle',
|
||||
top: '5%',
|
||||
itemWidth: 6,
|
||||
itemGap: 20,
|
||||
textStyle: {
|
||||
color: '#556677'
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
color: "#DCE2E8"
|
||||
}
|
||||
},
|
||||
backgroundColor: '#fff',
|
||||
textStyle: {
|
||||
color: '#5c6c7c'
|
||||
},
|
||||
padding: [10, 10],
|
||||
extraCssText: 'box-shadow: 1px 0 2px 0 rgba(163,163,163,0.5)'
|
||||
},
|
||||
grid: {
|
||||
top: '15%'
|
||||
},
|
||||
xAxis: [{
|
||||
type: 'category',
|
||||
data: xData,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#DCE2E8'
|
||||
}
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
// interval: 0,
|
||||
textStyle: {
|
||||
color: '#556677'
|
||||
},
|
||||
// 默认x轴字体大小
|
||||
fontSize: 0.75*fontSizeText,
|
||||
// margin:文字到x轴的距离
|
||||
margin: fontSizeText,
|
||||
rotate: 40
|
||||
},
|
||||
axisPointer: {
|
||||
label: {
|
||||
padding: [0, 0, 10, 0],
|
||||
/*
|
||||
除了padding[0]建议必须是0之外,其他三项可随意设置
|
||||
和CSSpadding相同,[上,右,下,左]
|
||||
如果需要下边线超出文字,设左右padding即可,注:左右padding最好相同
|
||||
padding[2]的10:
|
||||
10 = 文字距下边线的距离 + 下边线的宽度
|
||||
如:UI图中文字距下边线距离为7 下边线宽度为2
|
||||
则padding: [0, 0, 9, 0]
|
||||
*/
|
||||
// 这里的margin和axisLabel的margin要一致!
|
||||
margin: fontSizeText,
|
||||
// 移入时的字体大小
|
||||
fontSize: 0.75*fontSizeText,
|
||||
backgroundColor: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [{
|
||||
offset: 0,
|
||||
color: '#fff' // 0% 处的颜色
|
||||
}, {
|
||||
// offset: 0.9,
|
||||
offset: 0.86,
|
||||
//0.86 = (文字 + 文字距下边线的距离)/(文字 + 文字距下边线的距离 + 下边线的宽度)
|
||||
color: '#fff' // 0% 处的颜色
|
||||
}, {
|
||||
offset: 0.86,
|
||||
color: '#33c0cd' // 0% 处的颜色
|
||||
}, {
|
||||
offset: 1,
|
||||
color: '#33c0cd' // 100% 处的颜色
|
||||
}],
|
||||
global: false // 缺省为 false
|
||||
}
|
||||
}
|
||||
},
|
||||
boundaryGap: false
|
||||
}],
|
||||
yAxis: [{
|
||||
name: "(个)",
|
||||
minInterval: 1,
|
||||
type: 'value',
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: '#556677'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#556677'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#e8e8ed'
|
||||
}
|
||||
}
|
||||
}],
|
||||
series: [],
|
||||
};
|
||||
|
||||
for (let i = 0; i < seriesArr.length; i++) {
|
||||
if (seriesArr[i].data) {
|
||||
option.series.push({
|
||||
name: seriesArr[i].name,
|
||||
type: 'line',
|
||||
data: seriesArr[i].data,
|
||||
symbolSize: 1,
|
||||
symbol: 'circle',
|
||||
smooth: true,
|
||||
yAxisIndex: 0,
|
||||
showSymbol: false,
|
||||
itemStyle: {
|
||||
normal: {
|
||||
color: colorList[i],
|
||||
borderColor: colorList[i]
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
if(seriesArr[i].name=='新增代码数'&&seriesArr[i].data){
|
||||
option.yAxis.push({
|
||||
name: "(行)",
|
||||
type: 'value',
|
||||
position: 'right',
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
textStyle: {
|
||||
color: '#556677'
|
||||
},
|
||||
formatter: '{value}'
|
||||
},
|
||||
axisLine: {
|
||||
show: false,
|
||||
lineStyle: {
|
||||
color: '#556677'
|
||||
}
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
newEchartBar && newEchartBar.setOption(option);
|
||||
}, [xData,seriesArr])
|
||||
|
||||
return (
|
||||
<div id={id} key={id} className={className} style={{ minHeight: "400px" }}>
|
||||
</div>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import { notification } from 'antd';
|
||||
|
||||
export default (message)=>{
|
||||
notification.open({
|
||||
message: "提示",
|
||||
description: message,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
import React, { useEffect, useState } from "react";
|
||||
import { Upload, Button } from 'antd';
|
||||
import { appendFileSizeToUploadFileAll } from '../common/utils';
|
||||
import ShowNotification from './ShowNotification';
|
||||
|
||||
|
||||
function Uploads({ className, size, actionUrl, fileList, load, number }) {
|
||||
const [files, setFiles] = useState(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
if (fileList) {
|
||||
init();
|
||||
}
|
||||
}, [fileList]);
|
||||
|
||||
function init() {
|
||||
let f = appendFileSizeToUploadFileAll(fileList);
|
||||
setFiles(f);
|
||||
}
|
||||
function onAttachmentRemove(file) {
|
||||
if (!file.percent || file.percent === 100) {
|
||||
deleteAttachment(file);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
function deleteAttachment(file) {
|
||||
let id = (file.response && file.response.data && file.response.data.id) || file.id;
|
||||
|
||||
// 暂时不直接删除上传的文件,只在最后保存的时候进行修改
|
||||
let nf = files.filter(item => {
|
||||
let itemId = (item.response && item.response.data && item.response.data.id) || item.id;
|
||||
return itemId !== id;
|
||||
});
|
||||
setFiles(nf);
|
||||
load && load(nf);
|
||||
}
|
||||
|
||||
|
||||
function handleChange(info) {
|
||||
if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
|
||||
let fileList = info.fileList;
|
||||
if (number) {
|
||||
fileList = fileList.slice(-number);
|
||||
}
|
||||
if (info.file.status === 'done' && info.file.response.code === "0") {
|
||||
fileList.pop();
|
||||
ShowNotification(info.file.response.message);
|
||||
}
|
||||
setFiles(appendFileSizeToUploadFileAll(fileList));
|
||||
if (info.file.status === 'done' || info.file.status === 'removed') load && load(fileList);
|
||||
}
|
||||
}
|
||||
|
||||
function beforeUpload(file) {
|
||||
const isLt100M = file.size / 1024 / 1024 < size;
|
||||
if (!isLt100M) {
|
||||
ShowNotification(`文件大小必须小于${size}MB!`);
|
||||
}
|
||||
return isLt100M;
|
||||
}
|
||||
|
||||
const upload = {
|
||||
name: 'file',
|
||||
fileList: files,
|
||||
action: actionUrl + `/busiAttachments/upload`,
|
||||
onChange: handleChange,
|
||||
onRemove: onAttachmentRemove,
|
||||
beforeUpload: beforeUpload,
|
||||
};
|
||||
return (
|
||||
<Upload {...upload} className={className}>
|
||||
<Button type="primary">点击上传</Button>
|
||||
<span className="ml10 color-grey-9">(你可以上传小于<span className="color-red">{size}MB</span>的文件)</span>
|
||||
</Upload>
|
||||
)
|
||||
}
|
||||
export default Uploads;
|
|
@ -0,0 +1,464 @@
|
|||
/**
|
||||
* 路由配置表
|
||||
* key:必填,唯一标识
|
||||
* title:必填,菜单名称
|
||||
* location:路由地址
|
||||
* icon:左侧图标
|
||||
* target:打开方式,参考HTML标签的target属性
|
||||
* urltype:路由类别,用于拓展其它项目管理菜单,self为在当前项目下跳转路由,main_web_site_url或其它为匹配setting中对应路参数径
|
||||
* children:子元素数组
|
||||
*/
|
||||
|
||||
export default [
|
||||
{
|
||||
key: "statistics",
|
||||
title: "概览",
|
||||
location: "",
|
||||
icon: "icon-yonghuguanli",
|
||||
target: "_self",
|
||||
urltype: "self",
|
||||
children: [
|
||||
{
|
||||
key: "global",
|
||||
title: "全局统计",
|
||||
location: "/managements/statistics/global",
|
||||
menustatus: "Y",
|
||||
parentKey: "statistics",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
// {
|
||||
// key: "member",
|
||||
// title: "成员工作统计",
|
||||
// location: "/managements/statistics/member",
|
||||
// menustatus: "Y",
|
||||
// parentKey: "statistics",
|
||||
// icon: "",
|
||||
// target: "",
|
||||
// urltype: "self",
|
||||
// children: [],
|
||||
// },
|
||||
// {
|
||||
// key: "activity",
|
||||
// title: "项目活跃度统计",
|
||||
// location: "/managements/statistics/activity",
|
||||
// menustatus: "Y",
|
||||
// parentKey: "statistics",
|
||||
// icon: "",
|
||||
// target: "",
|
||||
// urltype: "self",
|
||||
// children: [],
|
||||
// },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "task",
|
||||
title: "创客空间",
|
||||
location: "",
|
||||
icon: "icon-weixuanze-chuangkekongjian",
|
||||
target: "_self",
|
||||
urltype: "self",
|
||||
children: [
|
||||
{
|
||||
key: "taskAdmin",
|
||||
title: "创客任务列表",
|
||||
location: "/managements/task/taskAdmin",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "commission",
|
||||
title: "待办事项",
|
||||
location: "",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "_self",
|
||||
urltype: "self",
|
||||
children: [
|
||||
{
|
||||
key: "delayManage",
|
||||
title: "延期任务处理",
|
||||
location: "/managements/task/delayManage",
|
||||
menustatus: "Y",
|
||||
parentKey: "commission",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "payProof",
|
||||
title: "支付报酬凭证上传",
|
||||
location: "/managements/task/payProof",
|
||||
menustatus: "Y",
|
||||
parentKey: "commission",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "publish",
|
||||
title: "任务发布审批",
|
||||
location: "",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "_self",
|
||||
urltype: "self",
|
||||
children: [
|
||||
{
|
||||
key: "overall",
|
||||
title: "统筹任务发布审批",
|
||||
location: "/managements/task/taskManage/1",
|
||||
menustatus: "Y",
|
||||
parentKey: "publish",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "autonomous",
|
||||
title: "自主任务发布审批",
|
||||
location: "/managements/task/taskManage/0",
|
||||
menustatus: "Y",
|
||||
parentKey: "publish",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "outcomeReview",
|
||||
title: "成果评论审批",
|
||||
location: "/managements/task/paperManage",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "supportingMaterials",
|
||||
title: "佐证材料审批",
|
||||
location: "/managements/task/proofManage",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "agreement",
|
||||
title: "协议审批",
|
||||
location: "/managements/task/agreementManage",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "appeal",
|
||||
title: "申诉审批",
|
||||
location: "",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [
|
||||
{
|
||||
key: "resultsSubmission",
|
||||
title: "成果提交申诉审批",
|
||||
location: "/managements/task/paperComplain",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "publicityPeriod",
|
||||
title: "公示期成果申诉审批",
|
||||
location: "/managements/task/publicityComplain",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
// {
|
||||
// key: "basics",
|
||||
// title: "基础数据",
|
||||
// location: "",
|
||||
// menustatus: "Y",
|
||||
// parentKey: "task",
|
||||
// icon: "",
|
||||
// target: "_self",
|
||||
// urltype: "self",
|
||||
// children: [
|
||||
// {
|
||||
// key: "categories",
|
||||
// title: "任务领域",
|
||||
// location: "/admin/categories/list",
|
||||
// menustatus: "Y",
|
||||
// parentKey: "task",
|
||||
// icon: "",
|
||||
// target: "_self",
|
||||
// urltype: "main_web_site_url",
|
||||
// children: [],
|
||||
// },
|
||||
// {
|
||||
// key: "industries",
|
||||
// title: "行业信息",
|
||||
// location: "/managements/industries/list",
|
||||
// menustatus: "Y",
|
||||
// parentKey: "task",
|
||||
// icon: "",
|
||||
// target: "_self",
|
||||
// urltype: "main_web_site_url",
|
||||
// children: [],
|
||||
// },
|
||||
// {
|
||||
// key: "placements",
|
||||
// title: "职位信息",
|
||||
// location: "/managements/placements/list",
|
||||
// menustatus: "Y",
|
||||
// parentKey: "task",
|
||||
// icon: "",
|
||||
// target: "_self",
|
||||
// urltype: "main_web_site_url",
|
||||
// children: [],
|
||||
// },
|
||||
// ],
|
||||
// },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "competition",
|
||||
title: "竞赛活动",
|
||||
location: "",
|
||||
icon: "icon-jingsaihuodong",
|
||||
target: "_self",
|
||||
urltype: "self",
|
||||
children: [
|
||||
{
|
||||
key: "competitionList",
|
||||
title: "竞赛列表",
|
||||
location: "/admin/competitions/list",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "main_web_site_url",
|
||||
params:'layout=none',
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "competitionRegion",
|
||||
title: "赛区配置",
|
||||
location: "/admin/competitions/region_zone_edit",
|
||||
menustatus: "Y",
|
||||
parentKey: "task",
|
||||
icon: "",
|
||||
target: "_blank",
|
||||
urltype: "main_web_site_url",
|
||||
params:'layout=none',
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "competitionExpert",
|
||||
title: "竞赛评审列表",
|
||||
location: "/managements/expert/competition",
|
||||
menustatus: "Y",
|
||||
parentKey: "competition",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "userManagement",
|
||||
title: "用户管理",
|
||||
location: "",
|
||||
icon: "icon-yonghuguanli",
|
||||
target: "_self",
|
||||
urltype: "self",
|
||||
children: [
|
||||
{
|
||||
key: "expertRegister",
|
||||
title: "专家注册列表",
|
||||
location: "/managements/expert/register",
|
||||
menustatus: "Y",
|
||||
parentKey: "userManagement",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "expertList",
|
||||
title: "专家库列表",
|
||||
location: "/managements/expert/list",
|
||||
menustatus: "Y",
|
||||
parentKey: "userManagement",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "notice",
|
||||
title: "公告管理",
|
||||
location: "",
|
||||
icon: "icon-yonghuguanli",
|
||||
target: "_self",
|
||||
urltype: "self",
|
||||
children: [
|
||||
{
|
||||
key: "noticeList1",
|
||||
title: "已发布",
|
||||
location: "/managements/notice/list/1",
|
||||
menustatus: "Y",
|
||||
parentKey: "notice",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "noticeList2",
|
||||
title: "待审核",
|
||||
location: "/managements/notice/list/2",
|
||||
menustatus: "Y",
|
||||
parentKey: "notice",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "noticeList0",
|
||||
title: "未通过",
|
||||
location: "/managements/notice/list/0",
|
||||
menustatus: "Y",
|
||||
parentKey: "notice",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "noticeDraft",
|
||||
title: "草稿箱",
|
||||
location: "/managements/notice/list/draft",
|
||||
menustatus: "Y",
|
||||
parentKey: "notice",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "noticeEdit",
|
||||
title: "发布公告",
|
||||
location: "/managements/notice/edit",
|
||||
menustatus: "Y",
|
||||
parentKey: "notice",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "jurisdiction",
|
||||
title: "权限管理",
|
||||
location: "",
|
||||
icon: "icon-yonghuguanli",
|
||||
target: "_self",
|
||||
urltype: "self",
|
||||
children: [
|
||||
{
|
||||
key: "adminUserList",
|
||||
title: "管理员列表",
|
||||
location: "/managements/jurisdiction/users",
|
||||
menustatus: "Y",
|
||||
parentKey: "jurisdiction",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "roleList",
|
||||
title: "角色列表",
|
||||
location: "/managements/jurisdiction/roles",
|
||||
menustatus: "Y",
|
||||
parentKey: "jurisdiction",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
{
|
||||
key: "menuList",
|
||||
title: "菜单列表",
|
||||
location: "/managements/jurisdiction/menu",
|
||||
menustatus: "Y",
|
||||
parentKey: "jurisdiction",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "self",
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
key: "settings",
|
||||
title: "网站配置",
|
||||
location: "",
|
||||
icon: "icon-yonghuguanli",
|
||||
target: "",
|
||||
urltype: "current_main_site_url",
|
||||
children: [
|
||||
{
|
||||
key: "platform_communicates",
|
||||
title: "社区动态管理",
|
||||
location: "/managements/admins/platform_communicates",
|
||||
menustatus: "Y",
|
||||
parentKey: "settings",
|
||||
icon: "",
|
||||
target: "",
|
||||
urltype: "current_main_site_url",
|
||||
params:'layout=none',
|
||||
children: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
|
@ -0,0 +1,198 @@
|
|||
import React, { useState, useEffect, Fragment } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Menu } from "antd";
|
||||
import { main_web_site_url } from '../../fetch';
|
||||
import "./index.scss";
|
||||
const { SubMenu } = Menu;
|
||||
|
||||
|
||||
export default (props) => {
|
||||
const { current_user, children, history, menuList, location: { pathname } } = props;
|
||||
const setting = (localStorage.chromesetting && JSON.parse(localStorage.chromesetting)) || {};
|
||||
const [openKeys, setOpenKeys] = useState([]);
|
||||
const [current, setCurrent] = useState();
|
||||
const [keyPath, setKeyPath] = useState();
|
||||
const [acitve, setActive] = useState({});
|
||||
|
||||
const titleObj = {};
|
||||
const locationObj = {};
|
||||
const parentKeyObj = {};
|
||||
const allRouter = [];
|
||||
const rootSubmenuKeys = [];
|
||||
|
||||
function titleFun(menus) {
|
||||
menus.forEach(i => {
|
||||
if (i.hidden === 1) {
|
||||
titleObj[i.key] = i.title;
|
||||
locationObj[i.location] = i;
|
||||
i.key = i.key + '';
|
||||
i.parentKey = i.parentKey + '';
|
||||
i.location && allRouter.push(i.location);
|
||||
i.parentKey == '0' && rootSubmenuKeys.push(i.key);
|
||||
if (i.hidden === 1 && Array.isArray(i.children) && i.children.length > 0) {
|
||||
titleFun(i.children);
|
||||
i.parentKey && (parentKeyObj[i.key] = i.parentKey + '');
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
menuList && menuList.length && titleFun(menuList);
|
||||
|
||||
useEffect(() => {
|
||||
sessionStorage.setItem("current_user", JSON.stringify(current_user));
|
||||
}, [current_user.login]);
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (locationObj[pathname]) {
|
||||
setCurrent(locationObj[pathname] ? [locationObj[pathname].key] : []);
|
||||
setKeyPath(locationObj[pathname] ? [locationObj[pathname].parentKey, locationObj[pathname].key] : []);
|
||||
const defaultOpenKeys = [];
|
||||
const myKey = pathname && locationObj[pathname] && locationObj[pathname].parentKey;
|
||||
defaultOpenKeys.push(myKey ? myKey : "task");
|
||||
parentKeyObj[myKey] && defaultOpenKeys.push(parentKeyObj[myKey]);
|
||||
setActive(locationObj[pathname]);
|
||||
setOpenKeys(defaultOpenKeys);
|
||||
}
|
||||
}, [locationObj[pathname]])
|
||||
|
||||
|
||||
function handleClick(e) {
|
||||
setCurrent([e.key]);
|
||||
setKeyPath(e.keyPath.reverse());
|
||||
}
|
||||
|
||||
function itemClick(item) {
|
||||
let myIframe = document.getElementById("iframe");
|
||||
if (myIframe) {
|
||||
myIframe.height = 'auto';
|
||||
}
|
||||
setActive(item)
|
||||
}
|
||||
|
||||
function getMenuList(menus) {
|
||||
return menus.map(function (item) {
|
||||
if (item.hidden === 1) {
|
||||
let title = (
|
||||
<span>
|
||||
{item.icon && <i className={"left-icon iconfont " + item.icon}></i>}
|
||||
<span>{item.title}</span>
|
||||
</span>
|
||||
);
|
||||
if (Array.isArray(item.children) && item.children.length > 0) {
|
||||
return (
|
||||
<SubMenu key={item.key} children={item.children} title={item.title}>{getMenuList(item.children)}</SubMenu>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Menu.Item title={item.title} key={item.key}>
|
||||
{item.location ? <Link to={item.location} onClick={() => { itemClick(item) }}>{title}</Link>
|
||||
: title}
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function head(keyPath) {
|
||||
return keyPath ? keyPath.map((i, index) => {
|
||||
return <span key={index}>{titleObj[i]}{index !== keyPath.length - 1 && ' / '}</span>
|
||||
}) : ''
|
||||
}
|
||||
|
||||
function iframeLoad() {
|
||||
try {
|
||||
let myIframe = document.getElementById("iframe");
|
||||
if (myIframe.contentDocument) {
|
||||
myIframe.height = myIframe.contentDocument.querySelector('.content').clientHeight + 260;
|
||||
myIframe.contentDocument.querySelector('.admin-body-container').style.overflow = 'hidden';
|
||||
// let MutationObserver =window.MutationObserver ;
|
||||
|
||||
// // let MutationObserver =myIframe.contentWindow.MutationObserver || myIframe.contentWindow.WebKitMutationObserver || myIframe.contentWindow.MozMutationObserver;
|
||||
// let observer = new MutationObserver(function (mutations) {
|
||||
// console.log("asdf", mutations);
|
||||
// });
|
||||
// observer.observe(myIframe.contentDocument.querySelector('.content'), {
|
||||
// attributes: true,
|
||||
// attributeFilter:['style'],
|
||||
// attributeOldValue:true
|
||||
// });
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
// useEffect(() => {
|
||||
// try {
|
||||
// document.getElementById("iframe").contentDocument.querySelector('.content').addEventListener("message", iframeHeight, false);
|
||||
// return () => {
|
||||
// document.getElementById("iframe").contentDocument.querySelector('.content').removeEventListener("message", iframeHeight, false);
|
||||
// }
|
||||
// } catch (err) {
|
||||
// console.error(err);
|
||||
// }
|
||||
// }, []);
|
||||
|
||||
function onOpenChange(newOpenKeys) {
|
||||
const latestOpenKey = newOpenKeys.find(key => openKeys.indexOf(key) === -1);
|
||||
if (rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
|
||||
setOpenKeys(newOpenKeys);
|
||||
} else {
|
||||
setOpenKeys(latestOpenKey ? [latestOpenKey] : []);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
// 添加路由监听函数
|
||||
history.listen(historyLocation => {
|
||||
// 每次路由变化都会执行这个方法
|
||||
if (allRouter.includes(historyLocation.pathname)) {
|
||||
setCurrent([locationObj[historyLocation.pathname].key]);
|
||||
setKeyPath([locationObj[pathname].parentKey, locationObj[pathname].key]);
|
||||
}
|
||||
})
|
||||
}, [history]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("message", iframeHeight, false);
|
||||
return () => {
|
||||
window.removeEventListener("message", iframeHeight, false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
function iframeHeight(e) {
|
||||
if (e.origin === main_web_site_url && e.data && !isNaN(e.data)) {
|
||||
document.getElementById("iframe").height=Number(e.data)+20;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<div className="layouts">
|
||||
<Menu
|
||||
mode="inline"
|
||||
selectedKeys={current}
|
||||
onClick={handleClick}
|
||||
onOpenChange={onOpenChange}
|
||||
openKeys={openKeys}
|
||||
>
|
||||
{menuList && menuList.length && getMenuList(menuList)}
|
||||
</Menu>
|
||||
</div>
|
||||
<div className="managements">
|
||||
<div className="head-title">{head(keyPath)}</div>
|
||||
{/* 如果不是react的新后端,那就用iframe打开 */}
|
||||
{acitve && acitve.urlType && acitve.urlType !== 'self' ?
|
||||
<iframe id="iframe" className="iframe-item" src={`${setting[acitve.urlType]}${acitve.location && acitve.location.startsWith('/administration') ? acitve.location.replace(/\/administration/, "") : acitve.location}${acitve.location.indexOf('?')>-1?'&layout=none':'?layout=none'}`} onLoad={iframeLoad}></iframe>
|
||||
: children
|
||||
}
|
||||
</div>
|
||||
</Fragment>
|
||||
);
|
||||
};
|