Merge pull request '新版后台管理' (#390) from tongChong/forgeplus-react:dev_military_admin into pre_dev_military

This commit is contained in:
xxq250 2022-06-01 10:41:39 +08:00
commit fa57794270
94 changed files with 5469 additions and 458 deletions

View File

@ -104,6 +104,7 @@ module.exports = {
src: path.join(paths.appSrc), // 整个源代码目录
forge: path.join(paths.appSrc, 'forge'),
military: path.join(paths.appSrc, 'military'),
components: path.join(paths.appSrc, 'components'),
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
"react-native": "react-native-web",

View File

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

View File

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

50
package-lock.json generated
View File

@ -265,17 +265,17 @@
}
},
"@babel/runtime-corejs3": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.16.0.tgz",
"integrity": "sha512-Oi2qwQ21X7/d9gn3WiwkDTJmq3TQtYNz89lRnoFy8VeZpWlsyXvzSwiRrRZ8cXluvSwqKxqHJ6dBd9Rv+p0ZGQ==",
"version": "7.17.2",
"resolved": "http://173.15.15.82:8081/repository/npm-all/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz",
"integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==",
"requires": {
"core-js-pure": "^3.19.0",
"core-js-pure": "^3.20.2",
"regenerator-runtime": "^0.13.4"
},
"dependencies": {
"regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"resolved": "http://173.15.15.82:8081/repository/npm-all/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
}
}
@ -3969,9 +3969,9 @@
"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
},
"core-js-pure": {
"version": "3.19.1",
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.19.1.tgz",
"integrity": "sha512-Q0Knr8Es84vtv62ei6/6jXH/7izKmOrtrxH9WJTHLCMAVeU+8TF8z8Nr08CsH4Ot0oJKzBzJJL9SJBYIv7WlfQ=="
"version": "3.21.1",
"resolved": "http://173.15.15.82:8081/repository/npm-all/core-js-pure/-/core-js-pure-3.21.1.tgz",
"integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ=="
},
"core-util-is": {
"version": "1.0.2",
@ -19402,9 +19402,9 @@
}
},
"wangeditor": {
"version": "4.7.7",
"resolved": "https://registry.npmjs.org/wangeditor/-/wangeditor-4.7.7.tgz",
"integrity": "sha512-eUpgP7i4pCYIjxjGMMcSUtkHUCkdX7BBwLZE6umseoK9hs3qIMu1tQ95FG48NJwL71JyAjt5c1gB56PzducL3Q==",
"version": "4.7.12",
"resolved": "http://173.15.15.82:8081/repository/npm-all/wangeditor/-/wangeditor-4.7.12.tgz",
"integrity": "sha512-5KOIpQ0+idKvDTkjZOp7RHYXA97FyJ9mjwy+zQUdMUCqZItlEXzvVOYtOlHkJr/HcbwgIz/7f/trGFggZK5X4g==",
"requires": {
"@babel/runtime": "^7.11.2",
"@babel/runtime-corejs3": "^7.11.2",
@ -19412,38 +19412,26 @@
},
"dependencies": {
"@babel/runtime": {
"version": "7.15.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.3.tgz",
"integrity": "sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==",
"version": "7.17.2",
"resolved": "http://173.15.15.82:8081/repository/npm-all/@babel/runtime/-/runtime-7.17.2.tgz",
"integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
"requires": {
"regenerator-runtime": "^0.13.4"
}
},
"regenerator-runtime": {
"version": "0.13.9",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"resolved": "http://173.15.15.82:8081/repository/npm-all/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
}
}
},
"wangeditor-for-react": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/wangeditor-for-react/-/wangeditor-for-react-1.5.3.tgz",
"integrity": "sha512-nnfZW6leWrVP5UFLEl93UmquSxgfkMpRM45nRusuA/QA+OPIKh0+JW4ZSmSjpmolhT8//iyQOry1I5EuVFwgog==",
"version": "1.5.6",
"resolved": "http://173.15.15.82:8081/repository/npm-all/wangeditor-for-react/-/wangeditor-for-react-1.5.6.tgz",
"integrity": "sha512-FLxU4K6PXc9AS3SFfU7vZhUR+EpUEWUVraFPRUiSH9VSzt9jLO9fp4IyReT7ebbp/YaMKXHhN5JLu2v2/zvNrA==",
"requires": {
"react": "^17.0.2",
"wangeditor": "^4.7.5"
},
"dependencies": {
"react": {
"version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
"requires": {
"loose-envify": "^1.1.0",
"object-assign": "^4.1.1"
}
}
"wangeditor": "^4.7.12"
}
},
"warning": {

View File

@ -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",

View File

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

File diff suppressed because one or more lines are too long

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -137,7 +137,7 @@ const AboutUs = Loadable({
// 管理页面
const Managements = Loadable({
loader: () => import('./military/managements'),
loader: () => import('./managements/index'),
loading: Loading,
})
// const CreateMerge = Loadable({
@ -146,7 +146,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"];
class App extends Component {
constructor(props) {
@ -405,8 +405,12 @@ class App extends Component {
path="/register"
render={(props) =><LoginRegisterPage {...this.props} {...props}/>}
></Route>
{/*管理页面*/}
{/*管理页面 三个路由分别对应本环境管理、原测试ruby模板管理、原项目管理*/}
<Route path="/managements" component={Managements} />
<Route path="/admin" component={Managements} />
<Route path="/administration" component={Managements} />
{/*403*/}
<Route path="/403" component={Shixunauthority} />

View File

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

View File

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

View File

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

View File

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

@ -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(() => {
@ -49,27 +52,29 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
// 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);
})
}
}, [id])
@ -252,7 +257,6 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
</Form.Item>
{helper('赛项',
'sub_competitions',
[{ required: true, message: "请填写赛项" }],
@ -315,26 +319,26 @@ export default Form.create()(({ form, match, history, current_user, showNotifica
</Form.Item>
<Form.Item className="mb0 mdEditor" label={'大赛介绍'}>
<MDEditor
{contentMd&&<MDEditor
placeholder={"请输入大赛介绍"}
height={500}
mdID={"competition-content"}
initValue={content}
onChange={(value) => { onContentChange(value, 'content') }}
/>
/>}
{getFieldDecorator("content", {
rules: [{ required: true, message: "请输入大赛介绍" }],
})(<Input style={{ display: "none" }} />)}
</Form.Item>
<Form.Item className="mb0 mdEditor" label={'赛事指南'}>
<MDEditor
{guideMd&&<MDEditor
placeholder={"请输入赛事指南"}
height={500}
mdID={"competition-guide"}
initValue={guide}
onChange={(value) => { onContentChange(value, 'guide') }}
/>
/>}
{getFieldDecorator("guide", {
rules: [{ required: true, message: "请输入赛事指南" }],
})(<Input style={{ display: "none" }} />)}

View File

@ -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();
}
});
}

View File

@ -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>
)
}

View File

@ -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]
*/
// marginaxisLabelmargin!
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>
)
}

View File

@ -0,0 +1,8 @@
import { notification } from 'antd';
export default (message)=>{
notification.open({
message: "提示",
description: message,
});
}

View File

@ -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;

View File

@ -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: [],
},
],
},
];

View File

@ -0,0 +1,197 @@
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={title}>{getMenuList(item.children)}</SubMenu>
);
} else {
return (
<Menu.Item title={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>
{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.params || 'layout=none'}`} onLoad={iframeLoad}></iframe>
: children
}
</div>
</Fragment>
);
};

View File

@ -0,0 +1,67 @@
.layouts {
position: fixed;
top: 70px;
left: 0;
width: 13.75rem;
height: calc(100vh - 70px);
overflow: hidden;
overflow-y: scroll;
background-color:#ffffff;
border-radius:4px;
box-shadow:0px 3px 10px rgba(88, 116, 255, 0.07);
&::-webkit-scrollbar{
width: 0;
}
.left-icon {
font-size: 1.25rem;
margin-right: 0.625rem;
margin-left: -.3125rem;
}
.ant-menu-submenu:hover, .ant-menu-submenu-selected, .ant-menu:hover, .ant-menu-submenu-selected .ant-menu{
background-color:#fbfbff;
}
.ant-menu-submenu-selected{
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected{
background-image:linear-gradient(90deg,#e7efff 0%,#f0f5ff 65.69%,#ffffff 100%);
&::after{
position: absolute;
top: 0;
left: 0;
bottom: 0;
content: '';
border: none;
border-left: 5px solid #2a3ee9;
}
}
}
li.ant-menu-item{
border: none;
&:hover{
background-color:#e2e6f5;
a{ color: rgba(0, 0, 0, 0.65) !important;}
}
}
}
.managements {
.head-title {
padding-top:1.25rem;
span {
color: #a6adc4;
font-size: 0.875rem;
line-height: 1.375rem;
&:last-child{
color:#596078;
}
}
}
.iframe-item{
width: 100%;
min-height: calc(100vh - 225px);
border: 0;
}
.ant-input, .ant-select-selection{
border-color:#e2e6f5;
}
}

11
src/managements/fetch.js Normal file
View File

@ -0,0 +1,11 @@
import javaFetch from '../military/javaFetch';
let settings = localStorage.chromesetting && JSON.parse(localStorage.chromesetting);
let actionUrl = settings && settings.api_urls && settings.api_urls.task ? settings.api_urls.task : 'https://task.osredm.com';
// let actionUrl = 'http://10.47.38.60:8088';
const service = javaFetch(actionUrl);
export const httpUrl = actionUrl;
export const main_web_site_url = settings && settings.main_web_site_url;
export default service;

334
src/managements/index.js Normal file
View File

@ -0,0 +1,334 @@
import React, { useEffect, useState } from "react";
import { Route, Switch } from "react-router-dom";
import { withRouter } from "react-router";
import { SnackbarHOC } from "educoder";
import { CNotificationHOC } from "../modules/courses/common/CNotificationHOC";
import { TPMIndexHOC } from "../modules/tpm/TPMIndexHOC";
import Loadable from "react-loadable";
import Loading from "../Loading";
import { ImageLayerOfCommentHOC } from "../modules/page/layers/ImageLayerOfCommentHOC";
import Layouts from "./components/layouts";
import './index.scss';
// 概览
const Statistics = Loadable({
loader: () => import("./statistics/"),
loading: Loading,
});
{/* 任务管理审核 */ }
const TaskManage = Loadable({
loader: () => import("../military/task/taskManage"),
loading: Loading,
});
{/* 成果管理审核 */ }
const PaperManage = Loadable({
loader: () => import("../military/task/paperManage"),
loading: Loading,
});
{/* 成果申诉管理审核 */ }
const PaperComplain = Loadable({
loader: () => import("../military/task/paperComplain"),
loading: Loading,
});
const ProofManage = Loadable({
loader: () => import("../military/task/proofManage"),
loading: Loading,
});
const PublicityComplain = Loadable({
loader: () => import("../military/task/publicityComplain"),
loading: Loading,
});
const AgreementManage = Loadable({
loader: () => import("../military/task/agreementManage"),
loading: Loading,
});
const PayProof = Loadable({
loader: () => import("../military/task/payProof"),
loading: Loading,
});
const TaskAdmin = Loadable({
loader: () => import("../military/task/taskAdmin"),
loading: Loading,
});
const DelayManage = Loadable({
loader: () => import("../military/task/delayManage"),
loading: Loading,
});
// 协议签订模板
const AgreementContent = Loadable({
loader: () => import("../military/task/agreementContent"),
loading: Loading,
});
// 专家库
const ExpertList = Loadable({
loader: () => import("../military/expert/expertList"),
loading: Loading,
});
// 专家审核
const RegisterList = Loadable({
loader: () => import("../military/expert/registerList"),
loading: Loading,
});
//创客任务评审规则
const ReviewRules = Loadable({
loader: () => import("../military/expert/reviewRules"),
loading: Loading,
});
//创客任务选择评审专家
const SelectExpert = Loadable({
loader: () => import("../military/expert/selectExpert"),
loading: Loading,
});
//创客任务评审结果查看
const ReviewResult = Loadable({
loader: () => import("../military/expert/reviewResult"),
loading: Loading,
});
//竞赛评审任务列表
const CompetitionList = Loadable({
loader: () => import("../military/expert/competionList"),
loading: Loading,
});
// 定制化竞赛列表,如启智
const CompetionCustomize =Loadable({
loader: () => import("../managements/competition/competionCustomize"),
loading: Loading,
})
const CompetionSetting=Loadable({
loader: () => import("../managements/competition/setting"),
loading: Loading,
});
// 公告管理
const NoticeManage = Loadable({
loader: () => import("./notice"),
loading: Loading,
});
// 权限管理
// 非普通用户(管理员)列表
const AdminUserList = Loadable({
loader: () => import("./jurisdiction/userList"),
loading: Loading,
})
// 系统角色列表
const RoleList = Loadable({
loader: () => import("./jurisdiction/roles"),
loading: Loading,
})
// 菜单列表
const MenuList = Loadable({
loader: () => import("./jurisdiction/menuList"),
loading: Loading,
})
const Managements = (propsF) => {
return (
<div className="newMain clearfix">
<Layouts {...propsF} >
<Switch {...propsF}>
{/* 概览 */}
<Route
path="/managements/statistics"
render={(props) => (
<Statistics {...propsF} {...props} />
)}
></Route>
{/* 任务管理审核 */}
<Route
path="/managements/task/taskManage/:publishMode"
render={(props) => (
<TaskManage {...propsF} {...props} />
)}
></Route>
{/* 成果管理审核 */}
<Route
path="/managements/task/paperManage"
render={(props) => (
<PaperManage {...propsF} {...props} />
)}
></Route>
{/* 成果申诉管理审核 */}
<Route
path="/managements/task/paperComplain"
render={(props) => (
<PaperComplain {...propsF} {...props} />
)}
></Route>
{/* 公示期成果申诉管理审核 */}
<Route
path="/managements/task/publicityComplain"
render={(props) => (
<PublicityComplain {...propsF} {...props} />
)}
></Route>
{/* 佐证管理审核 */}
<Route
path="/managements/task/proofManage"
render={(props) => (
<ProofManage {...propsF} {...props} />
)}
></Route>
{/* 管理员协议审核 */}
<Route
path="/managements/task/agreementManage"
render={(props) => (
<AgreementManage {...propsF} {...props} />
)}
></Route>
{/* 管理员上传支付凭证 */}
<Route
path="/managements/task/payProof"
render={(props) => (
<PayProof {...propsF} {...props} />
)}
></Route>
{/* 管理员任务列表 */}
<Route
path="/managements/task/taskAdmin"
render={(props) => (
<TaskAdmin {...propsF} {...props} />
)}
></Route>
{/* 延期管理 */}
<Route
path="/managements/task/delayManage"
render={(props) => (
<DelayManage {...propsF} {...props} />
)}
></Route>
{/* 协议内容 */}
<Route
path="/managements/task/agreement/content"
render={(props) => (
<AgreementContent {...propsF} {...props} />
)}
></Route>
{/* 专家审核 */}
<Route
path="/managements/expert/register"
render={(props) => (
<RegisterList {...propsF} {...props} />
)}
></Route>
{/* 专家库列表 */}
<Route
path="/managements/expert/list"
render={(props) => (
<ExpertList {...propsF} {...props} />
)}
></Route>
{/* 创客任务评审规则 */}
<Route
path="/managements/expert/task/review/rules/:containerType/:containerId"
render={(props) => (
<ReviewRules {...propsF} {...props} />
)}
></Route>
{/* 创客任务选择评审专家 */}
<Route
path="/managements/expert/task/review/select/:containerType/:containerId"
render={(props) => (
<SelectExpert {...propsF} {...props} />
)}
></Route>
{/* 创客任务评审结果查看 */}
<Route
path="/managements/expert/task/review/results/:containerType/:containerId"
render={(props) => (
<ReviewResult {...propsF} {...props} />
)}
></Route>
{/* 竞赛评审任务列表 */}
<Route
path="/managements/expert/competition"
render={(props) => (
<CompetitionList {...propsF} {...props} />
)}
></Route>
{/* 非普通用户(管理员)列表 */}
<Route
path="/managements/jurisdiction/users"
render={(props) => (
<AdminUserList {...propsF} {...props} />
)}
></Route>
{/* 系统角色列表 */}
<Route
path="/managements/jurisdiction/roles"
render={(props) => (
<RoleList {...propsF} {...props} />
)}
></Route>
{/* 菜单列表 */}
<Route
path="/managements/jurisdiction/menu"
render={(props) => (
<MenuList {...propsF} {...props} />
)}
></Route>
{/* 公告管理 */}
<Route
path="/managements/notice"
render={(props) => (
<NoticeManage {...propsF} {...props} />
)}
></Route>
{/* 定制竞赛配置详情 */}
<Route
path="/managements/competition/customize/edit/:id"
render={(props) => (
<CompetionSetting {...propsF} {...props} />
)}
></Route>
<Route
path="/managements/competition/customize/add"
render={(props) => (
<CompetionSetting {...propsF} {...props} />
)}
></Route>
{/* 定制竞赛配置列表 */}
<Route
path="/managements/competition/customize"
render={(props) => (
<CompetionCustomize {...propsF} {...props} />
)}
></Route>
</Switch>
</Layouts>
</div>
);
}
export default withRouter(
ImageLayerOfCommentHOC({
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
parentSelector: ".newMain",
})(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(Managements))))
);

View File

@ -0,0 +1,91 @@
.managements{
margin-left: 13.75rem;
padding:0 1.875rem 1.6rem;
background: #f6f9fe;
min-height: 80vh;
.content{
margin-top:1rem;
}
}
.management-content-head{
background-color: #fff;
margin-top: 1.5rem;
padding: 1.5rem;
border-radius:4px;
box-shadow:0px 0px 10px rgba(88, 116, 255, 0.18);
>p{
color:#18191e;
padding-bottom: 10px;
border-bottom: 1px solid #e2e6f5;
}
}
.managements .ant-table-thead > tr > th,.managements .ant-table-tbody > tr > td {
padding: 1rem 1rem;
text-align: left;
.ant-btn{
padding: 0 9px;
}
.f20{
border-color:#f20000;
span{
color:#f20000;
}
}
.f89{
border-color:#f89d00;
span{
color:#f89d00;
}
}
.c2a3{
border-color:#2a3ee9;
&.bor{
background-color: #fff;
span{color:#2a3ee9;}
}
&.full{
background-color:#2a3ee9;
span{color: white;}
}
&.disabled{
background-color:#f2f2f2;
border: none;
span{color:#a6adc4;}
}
}
}
.f20{
border-color:#f20000;
span{
color:#f20000;
}
}
.f89{
border-color:#f89d00;
span{
color:#f89d00;
}
}
.c2a3{
border-color:#2a3ee9;
&.bor{
background-color: #fff;
span{color:#2a3ee9;}
}
&.full{
background-color:#2a3ee9;
span{color: white;}
}
&.disabled{
background-color:#f2f2f2;
border: none;
span{color:#a6adc4;}
}
}
// 系统默认字体大小是16px大屏的在此基础上增大字体
@media screen and (min-width: 1921px) {
html{
font-size: calc(100% + 6 * (100vw - 1920px) / 1000 );
font-size: calc(100% + 6 * (100vw - 1920px) / 1000 );
}
}

View File

@ -0,0 +1,27 @@
.search-list{
margin-top: 1rem;
display: flex;
justify-content: flex-end;
}
.menuDetail{
>div{
display: flex;
align-items: center;
}
.ant-form-item-label{
width: 5rem;
justify-content: flex-end;
margin-right: 1rem;
}
}
.menuDetail{
.has-error .ant-form-explain{
position: absolute;
}
.ant-row{
margin-top: 24px;
}
.ant-row:first-child{
margin-top: 0;
}
}

View File

@ -0,0 +1,285 @@
import React, { useCallback, useEffect, useState, useMemo } from 'react';
import { Input, Select, Button, Form, message, Switch, Radio, Popconfirm, TreeSelect } from 'antd';
import {createMenu, deleteMenu, treeList, updateMenu, updateMenuStatus} from '../../api';
import PaginationTable from '../../../components/pagination-table';
import Modal from '../../../components/modal/index';
import './index.scss';
import '../index.scss';
const Option = Select.Option;
export default Form.create()(({ form}) => {
const { getFieldDecorator, setFieldsValue, getFieldsValue, validateFields } = form;
const [reload, setReload] = useState();
const [loading, setLoading] = useState(false);
const [curPage, setCurPage] = useState(1);
const [total, setTotal] = useState(0);
//
const [dataList, setDataList] = useState([]);
// ()
const [treeNode, setTreeNode] = useState([]);
//
const [menuDetailModal, setMenuDetailModal] = useState(false);
const [editMenuModal, setEditMenuModal] = useState(false);
const [editMenuId, setEditMenuId] = useState(undefined);
const [treeSelectValue, setTreeSelectValue] = useState(undefined);
const helper = useCallback(
(label, name, rules, widget, initialValue) => (
<Form.Item label={label}>
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
</Form.Item>
), []);
const columns = useMemo(() => {
return [
{
title: '菜单名称',
dataIndex: 'title',
render: (text, record) => (
text || record.name
),
},
{
title: '菜单级数',
dataIndex: 'level',
render: (text, record) => (text+1),
},
{
title: '路由',
dataIndex: 'location',
width: "20%",
render: (text, record) => (text || '--'),
},
{
title: '前端图标',
dataIndex: 'icon',
width: "20%",
render: (text, record) => {return text || '--'}
},
{
title: '是否显示',
dataIndex: 'hidden',
render: (text, record) => {
return <Switch checked={text==1} onChange={(checked)=>changeMenuStatus(checked, record.key)}/>
}
},
{
title: '操作',
key: 'action',
dataIndex: 'key',
align: 'center',
render: (text, record) => {
return(
<React.Fragment>
<Button className="mr5 f89" onClick={()=>editMenuDetail(record)}>编辑</Button>
<Popconfirm placement="bottom" title="你确认要删除此菜单吗?" onConfirm={()=>deleteMenuById(text)}>
<Button className='mr5 f20'>删除</Button>
</Popconfirm>
</React.Fragment>
)},
},
]
}, [curPage, reload]);
const menuDetail =(
<div className='menuDetail'>
{helper(
"菜单名称",
"menuName",
[{ max: 20, message: '长度不能超过20个字符' },{required: true, message: "菜单名称不能为空"}],
<Input
placeholder="请输入菜单名称"
/>
)}
{helper(
"上级菜单",
"parentKey",
[],
<TreeSelect
className="column-select"
treeData={treeNode}
placeholder="请选择上级菜单"
style={{ width: '195px' }}
allowClear
value={treeSelectValue}
onChange={(value)=>setTreeSelectValue(value)}
/>,
)}
{helper(
"路由",
"location",
[{ max: 100, message: '长度不能超过100个字符' }],
<Input
placeholder="请输入前端路由"
/>
)}
{helper(
"前端图标",
"icon",
[{ max: 100, message: '长度不能超过100个字符' }],
<Input
placeholder="请输入前端图标"
/>
)}
{helper(
"是否显示",
"hidden",
[],
<Radio.Group>
<Radio value={1}></Radio>
<Radio value={0}></Radio>
</Radio.Group>,
)}
{helper(
"环境",
"urlType",
[],
<Select
className="column-select"
>
<Option key={'self'}>8000环境</Option>
<Option key={'current_main_site_url'}>8000项目管理</Option>
<Option key={'main_web_site_url'}>8001环境</Option>
</Select>,
)}
</div>
)
//
function changeMenuStatus(checked, MenuId){
updateMenuStatus(MenuId, checked ? 1: 0).then(response=>{
if(response && response.message=='success'){
message.success("状态更新成功");
setReload(Math.random());
}else{
message.error('状态更新失败');
}
})
}
function addMenu(){
validateFields((error, values) => {
if(!error){
//
const params = {
name: values.menuName,
title: values.menuName,
parentKey: parseInt(values.parentKey || 0),
location: values.location,
icon: values.icon,
hidden: values.hidden,
level: parseInt(values.parentKey)+1,
urlType:values.urlType,
}
createMenu(params).then(response=>{
if(response && response.message=='success'){
message.success("菜单新建成功");
setReload(Math.random());
setMenuDetailModal(false);
}
})
}
})
}
//
function deleteMenuById(menuId){
//
deleteMenu(menuId).then(response=>{
if(response && response.message=='success'){
message.success("菜单删除成功");
setReload(Math.random());
}else{
message.error('菜单删除失败');
}
})
}
//
function editMenuDetail(roleDetail){
setEditMenuId(roleDetail.key);
setFieldsValue({
menuName: roleDetail.name,
parentKey: roleDetail.parentKey.toString(),
location: roleDetail.location,
icon: roleDetail.icon,
hidden: roleDetail.hidden,
urlType: roleDetail.urlType
});
setEditMenuModal(true);
}
//
function editMenu(){
validateFields((error, values) => {
if(!error){
//
const params = {
...values,
title: values.menuName,
name: values.menuName,
}
updateMenu(editMenuId, params).then(response=>{
if(response && response.message=='success'){
setReload(Math.random());
setEditMenuModal(false);
message.success("菜单更新成功");
}else{
message.error('菜单更新失败');
}
})
}
})
}
// value 使
function valueFun(menus) {
const treeList = menus.slice(0, menus.length);
treeList.map(item=>{
item.value = item.key;
if (Array.isArray(item.children) && item.children.length > 0) {
valueFun(item.children);
}
})
treeList.unshift({key:'0', value: '0', title: "无上级菜单"});
setTreeNode(treeList);
}
useEffect(()=>{
setLoading(true);
treeList().then(response=>{
if(response && response.message=='success'){
setDataList(response.data);
valueFun(response.data);
}
}).finally(()=>{
setLoading(false);
})
},[reload])
return (
<div className="centerbox task-manage-all ">
<div className='management-content-head'>
<p className='font-18'>菜单列表</p>
<div className="search-list" >
<Button className='c2a3 full' onClick={()=>{setFieldsValue({hidden: 1,menuName: '',parentKey: undefined,location: '',icon: '', urlType: "self"}); setMenuDetailModal(true);}}>新增</Button>
<Modal visible={menuDetailModal} title="新增菜单" content={menuDetail} onOk={addMenu} onCancel={()=>setMenuDetailModal(false)}/>
<Modal visible={editMenuModal} title="编辑菜单" content={menuDetail} onOk={editMenu} onCancel={()=>setEditMenuModal(false)}/>
</div>
</div>
<div className="center-content">
<PaginationTable
loading={loading}
rowKey={row=> row.key}
dataSource={dataList}
columns={columns}
total={total}
current={curPage}
setCurPage={(page)=>{setCurPage(page)}}
className="expertReviewTable"
indentSize={30}
/>
</div>
</div>
)
})

View File

@ -0,0 +1,20 @@
// .ant-table-row-collapsed::after, .ant-table-row-expanded::after{
// content: '查看下级';
// color:#2a3ee9;
// }
// .ant-table-row-expand-icon, .ant-table-row-expand-icon{
// width: auto;
// height: 32px;
// line-height: 32px;
// padding: 0 9px;
// border-color:#2a3ee9;
// background-color: #fff;
// :hover, :hover::after{
// border-color:#2a3ee9;
// opacity: 0.75;
// }
// }
.column-select .ant-select-selection{
width: 193px;
}

View File

@ -0,0 +1,286 @@
import React, { useCallback, useEffect, useState, useMemo } from 'react';
import { Input, Button, Form, message, Radio, Switch, Popconfirm, Tree } from 'antd';
import Modal from '../../../components/modal/index';
import PaginationTable from '../../../components/pagination-table';
import './index.scss';
import '../index.scss';
import '../../index.scss';
import { createRole, deleteRole, roleList, updateRoleStatus, updateRole, treeList, allocMenu, listMenu } from 'src/managements/api';
const { TextArea } = Input;
export default Form.create()(({form}) => {
const { getFieldDecorator, setFieldsValue, getFieldsValue, validateFields } = form;
const [reload, setReload] = useState();
const [loading, setLoading] = useState(false);
const [curPage, setCurPage] = useState(1);
const [total, setTotal] = useState(0);
//
const [dataList, setDataList] = useState([]);
//
const [roleDetailModal, setRoleDetailModal] = useState(false);
//
const [editRoleModal, setEditRoleModal] = useState(false);
const [editRoleId, setEditRoleId] = useState(undefined);
//
const [menuModal, setMenuModal] = useState(false);
const [menuTreeData, setMenuTreeData] = useState(false);
const [roleId, setRoleId] = useState(undefined);
//
const [selectedMenu, setSelectedMenu] = useState(undefined);
//
const [selectedMenuFa, setSelectedMenuFa] = useState(undefined);
//
let oneTree = [];
const helper = useCallback(
(label, name, rules, widget, initialValue) => (
<Form.Item label={label}>
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
</Form.Item>
), []);
const columns = useMemo(() => {
return [
{
title: '编号',
dataIndex: 'number',
render: (text, record, index) => (
index+1
),
},
{
title: '角色名称',
dataIndex: 'name'
},
{
title: '描述',
dataIndex: 'description',
width: "20%"
},
{
title: '添加时间',
dataIndex: 'createTime',
render: (text, record) => {
text = text && text.replaceAll('-','/').substring(0,16);
return text || '--'
}
},
// {
// title: '',
// dataIndex: 'status',
// render: (text, record) => {
// return <Switch defaultChecked={text == 1} onChange={(checked)=>changeRoleStatus(checked, record.id)}/>
// }
// },
{
title: '操作',
key: 'action',
dataIndex: 'id',
align: 'center',
render: (text, record) => {
return(
<React.Fragment>
<Button className="mr5 c2a3 full" onClick={()=>menuListByRole(text)}>分配菜单</Button>
<Button className="mr5 f89" onClick={()=>editRoleDetail(record)}>编辑</Button>
<Popconfirm placement="bottom" title="你确认要删除此角色吗?" onConfirm={()=>deleteRoleById(text)}>
<Button className='mr5 f20'>删除</Button>
</Popconfirm>
</React.Fragment>
)},
},
]
}, [curPage]);
const roleDetail =(
<div className='menuDetail'>
{helper(
"角色名称",
"name",
[{ max: 20, message: '长度不能超过20个字符'},
{ required: true, message: "角色名称不能为空"},
{ validator: (rule, value, callback)=>{
//
const filter = dataList.filter(item=>{ return item.id !== editRoleId && item.name === value});
filter.length>0 ? callback('此角色名称已存在'):callback();
}}],
<Input
placeholder="请输入角色名称"
/>
)}
{helper(
"描述",
"description",
[{ max: 500, message: '长度不能超过500个字符'}],
<TextArea rows={4}/>,
)}
{false && helper(
"是否启用",
"status",
[],
<Radio.Group>
<Radio value={1}></Radio>
<Radio value={0}></Radio>
</Radio.Group>,
1
)}
</div>
)
const menuTree = (
<Tree
checkable
treeData={menuTreeData}
onCheck={(checkedKeys, info)=>{const keys = [...checkedKeys, ...info.halfCheckedKeys]; setSelectedMenu(checkedKeys); setSelectedMenuFa(keys)}}
checkedKeys={selectedMenu}
/>
)
function addRole(){
validateFields((error, values) => {
if(!error){
//
// let values = getFieldsValue(['name', 'description']);
const params = {
...values
}
createRole(params).then(response=>{
if(response && response.message=='success'){
message.success("角色新建成功");
setReload(Math.random());
setRoleDetailModal(false);
}else{
message.error('角色新建失败');
}
})
}
})
}
//
function deleteRoleById(roleId){
//
deleteRole(roleId).then(response=>{
if(response && response.message=='success'){
message.success("角色删除成功");
setReload(Math.random());
}else{
message.error('角色删除失败');
}
})
}
//
function changeRoleStatus(checked, roleId){
updateRoleStatus(roleId, checked ? 1: 0).then(response=>{
if(response && response.message=='success'){
message.success("状态更新成功");
}else{
message.error('状态更新失败');
}
})
}
function editRoleDetail(roleDetail){
setEditRoleId(roleDetail.id);
setFieldsValue({
name: roleDetail.name,
description: roleDetail.description,
});
setEditRoleModal(true);
}
//
function editRole(){
validateFields((error, values) => {
if(!error){
//
const params = {
...values
}
updateRole(editRoleId, params).then(response=>{
if(response && response.message=='success'){
message.success("角色更新成功");
setReload(Math.random());
setEditRoleModal(false);
}else{
message.error('角色更新失败');
}
})
}
})
}
//
function menuListByRole(roleId){
listMenu(roleId).then(response=>{
if(response && response.message=='success'){
//
const keys = response.data.map(item=>{return oneTree.indexOf(item.key.toString()) === -1 ? item.key.toString() : null});
setSelectedMenu(keys);
setRoleId(roleId);
setMenuModal(true);
}
})
}
//
function allotMenu(){
allocMenu(roleId, selectedMenuFa).then(response=>{
if(response && response.message=='success'){
message.success("分配成功");
setMenuModal(false);
}else{
message.error('分配失败');
}
})
}
useEffect(()=>{
treeList().then(response=>{
if(response && response.message=='success'){
oneTree = response.data.map(item=>{return item.key.toString()});
setMenuTreeData(response.data);
}
}).finally(()=>{
setLoading(false);
})
},[])
useEffect(()=>{
setLoading(true);
roleList().then(response=>{
if(response && response.message=='success'){
setDataList(response.data);
}
}).finally(()=>{
setLoading(false);
})
},[reload])
return (
<div className="centerbox task-manage-all ">
<div className='management-content-head'>
<p className='font-18'>角色列表</p>
<div className="search-list">
<Button className='c2a3 full' onClick={()=>{setRoleDetailModal(true); setEditRoleId(undefined); setFieldsValue({name: '',description: ''})}}>新增</Button>
<Modal visible={roleDetailModal} title="添加角色" content={roleDetail} onOk={addRole} onCancel={()=>setRoleDetailModal(false)}/>
<Modal visible={editRoleModal} title="编辑角色" content={roleDetail} onOk={editRole} onCancel={()=>setEditRoleModal(false)}/>
<Modal visible={menuModal} title="分配菜单" content={menuTree} onOk={allotMenu} onCancel={()=>setMenuModal(false)}/>
</div>
</div>
<div className="center-content">
<PaginationTable
loading={loading}
rowKey={(row) => row.id}
dataSource={dataList}
columns={columns}
total={total}
current={curPage}
setCurPage={(page)=>{setCurPage(page)}}
className="expertReviewTable"
/>
</div>
</div>
)
})

View File

@ -0,0 +1,130 @@
import React, { useCallback, useEffect, useState, useMemo } from 'react';
import {Select, Form, message } from 'antd';
import PaginationTable from '../../../components/pagination-table';
import './index.scss';
import '../index.scss';
import { adminUserList, roleList, updateUserRole } from 'src/managements/api';
const Option = Select.Option;
export default Form.create()(({form}) => {
const { getFieldDecorator, setFieldsValue, getFieldsValue } = form;
const [reload, setReload] = useState();
const [loading, setLoading] = useState(false);
const [curPage, setCurPage] = useState(1);
const [total, setTotal] = useState(0);
const [dataList, setDataList] = useState([]);
//
const [rolesList, setRolesList] = useState([]);
const helper = useCallback(
(label, name, rules, widget, initialValue) => (
<Form.Item label={label}>
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
</Form.Item>
), []);
const columns = useMemo(() => {
return [
{
title: 'ID',
dataIndex: 'login'
},
{
title: '姓名',
dataIndex: 'name',
},
{
title: '邮箱',
dataIndex: 'email',
},
{
title: '创建时间',
dataIndex: 'createdOn',
render: (text, record) => {
text = text && text.replaceAll('-','/').substring(0,16);
return text || '--'
}
},
{
title: '最后登录时间',
dataIndex: 'lastLoginOn',
render: (text, record) => {
text = text && text.replaceAll('-','/').substring(0,16);
return text || '--'
}
},
{
title: '角色',
key: 'action',
dataIndex: 'roles',
align: 'center',
render: (text, record) => {
return(
<Select
mode="multiple"
className="column-select"
defaultValue={(text && text.substring(1, text.length-1).replaceAll(' ','').split(',')) || []}
onChange={(key) => { changeRole(key, record.id) }}
style={{ minWidth: 200 }}
placeholder="请选择角色"
>
{
rolesList && rolesList.map(item => {
return <Option key={parseInt(item.id)}>{item.name}</Option>
})
}
</Select>
)},
},
]
}, [curPage, rolesList]);
function changeRole(value, userId){
updateUserRole(userId, value).then(response=>{
if(response && response.message!='success'){
message.error('用户更新失败');
}
})
}
useEffect(()=>{
roleList().then(response=>{
if(response && response.message=='success'){
setRolesList(response.data);
}
})
},[])
useEffect(()=>{
setLoading(true);
adminUserList().then(response=>{
if(response && response.message=='success'){
setDataList(response.data);
}
}).finally(()=>{
setLoading(false);
})
},[reload])
return (
<div className="centerbox task-manage-all ">
<div className='management-content-head'>
<p className='font-18'>管理员列表</p>
<div className="search-list" ></div>
</div>
<div className="center-content">
<PaginationTable
loading={loading}
rowKey={(row) => row.id}
dataSource={dataList}
columns={columns}
total={total}
current={curPage}
setCurPage={(page)=>{setCurPage(page)}}
className="expertReviewTable"
/>
</div>
</div>
)
})

View File

@ -0,0 +1,80 @@
import fetch from 'military/notice/fetch';
import showNotification from '../components/ShowNotification';
// 公告列表查询
export async function getNoticeList(params) {
let res = await fetch({
url: '/api/announcements/',
method: 'get',
params,
});
if (res.message === 'success') {
return res.data;
} else {
showNotification(res.message || '请求错误');
}
}
//新增公告
export function addNotice(data) {
return fetch({
url: '/api/announcements/add',
method: 'post',
data: data
});
}
//删除公告
export function deleteNotice(id) {
return fetch({
url: '/api/announcements/' + id,
method: 'DELETE',
});
}
//更新公告
export function editNotice(data) {
return fetch({
url: '/api/announcements/update',
method: 'put',
data: data
});
}
//审核公告
export function checkNotice(data) {
return fetch({
url: '/api/announcements/check',
method: 'put',
data: data
});
}
// 公告详情查询
export async function getNoticeDetail(id) {
let res = await fetch({
url: '/api/announcements/' + id,
method: 'get',
});
if (res.data) {
return res.data;
} else {
showNotification(res.message || '请求错误');
}
}
// 公告密文查看人详情
export async function getNoticeReader(params) {
let res = await fetch({
url: '/api/request_contact_reader_info/',
method: 'get',
params,
});
if (res.data) {
return res.data;
} else {
showNotification(res.message || '请求错误');
}
}

View File

@ -0,0 +1,42 @@
.notice-content {
min-height: 50vh;
margin: 1em;
background: #fff;
border-radius: 1em;
box-shadow: 0 1px 2px #d9d9d9;
overflow-y: scroll;
}
.notice-title {
padding: 0.75em;
border-bottom: 1px solid #e5e5e5;
}
.notice-form .edit-input{
max-width:450px;
}
.my-search-button{
margin-top:4px;
}
.encrypt-item{
margin-top: -24px;
}
.encrypt-item .ant-form-item-label{
visibility: hidden;
}
.ant-radio-checked .ant-radio-inner{
border-color: #4154f1;
}
.ant-radio-inner::after{
background-color: #4154f1;
}
.ant-radio-wrapper:hover .ant-radio, .ant-radio:hover .ant-radio-inner, .ant-radio-input:focus + .ant-radio-inner{
border-color: #4154f1;
}
.ant-radio-checked::after{
border: 1px solid #4154f1;
}

View File

@ -0,0 +1,67 @@
import React from "react";
import { Route, Switch } from "react-router-dom";
import Loadable from "react-loadable";
import Loading from "../../Loading";
//
const NoticeList = Loadable({
loader: () => import("./noticeList"),
loading: Loading,
});
//
const NoticeDetail = Loadable({
loader: () => import("./noticeDetail"),
loading: Loading,
});
//
const NoticeEdit = Loadable({
loader: () => import("./noticeEdit"),
loading: Loading,
});
// reader
const NoticeReader = Loadable({
loader: () => import("./noticeReader"),
loading: Loading,
});
export default (propsF)=>{
return (
<Switch {...propsF}>
{/* 公告列表 */}
<Route
path="/managements/notice/list/:isChecked"
render={(props) => (
<NoticeList {...propsF} {...props} />
)}
></Route>
{/* 公告详情 */}
<Route
path="/managements/notice/detail/:noticeId"
render={(props) => (
<NoticeDetail {...propsF} {...props} />
)}
></Route>
{/* 公告编辑 */}
<Route
path="/managements/notice/edit/:noticeId"
render={(props) => (
<NoticeEdit {...propsF} {...props} />
)}
></Route>
{/* 公告新增 */}
<Route
path="/managements/notice/edit"
render={(props) => (
<NoticeEdit {...propsF} {...props} />
)}
></Route>
{/* 公告预览 */}
<Route
path="/managements/notice/reader/:noticeId"
render={(props) => (
<NoticeReader {...propsF} {...props} />
)}
></Route>
</Switch>
)
}

View File

@ -0,0 +1,84 @@
import React, { useCallback, useEffect, useState } from 'react';
import { Button, Descriptions, Icon } from 'antd';
import ShowNotification from '../../components/ShowNotification';
import { noticeType, noticeChecked } from '../../common/static';
import { getNoticeDetail, checkNotice } from '../api';
import '../index.css';
import './index.scss';
const noticeTypeArr = [];
for (const item of noticeType) {
noticeTypeArr[item.code] = (item.name);
}
const noticeCheckedArr = [];
for (const item of noticeChecked) {
noticeCheckedArr[item.code] = (item.name);
}
const IndexPage = ({ match, history, current_user: { admin } }) => {
const [noticeData, setNoticeData] = useState({});
const id = match.params.noticeId;
useEffect(() => {
id && getNoticeDetail(id).then(data => {
setNoticeData(data || {});
})
}, [id]);
//
function checkItem(isChecked) {
checkNotice({
id: noticeData.id,
isChecked,
}).then(res => {
if (res && res.code == '1') {
ShowNotification("操作成功");
history.go(-1);
} else {
ShowNotification(res.message || "操作失败");
history.go(-1);
}
})
}
function download(url) {
if (window.location.href.indexOf('localhost') > -1) {
url = 'http://106.75.31.211:58088' + url;
}
window.open(url);
}
return (
<div className="notice-content">
<h4 className="notice-title"><span className='backList' onClick={() => { history.go(-1) }}><Icon type="left" />返回</span>公告详情</h4>
<Descriptions className='itemContent' column={1}>
<Descriptions.Item label="公告状态"><span className='statusColor'>{noticeData.status == 1 ? noticeCheckedArr[noticeData.isChecked] : '草稿'}</span></Descriptions.Item>
<Descriptions.Item label="公告标题">{noticeData.title}</Descriptions.Item>
<Descriptions.Item label="公告类型">{noticeTypeArr[noticeData.type]}</Descriptions.Item>
<Descriptions.Item label="发布单位">{noticeData.publisher}</Descriptions.Item>
<Descriptions.Item label="公告描述" className='alignTop'><div className="editor-w-text" dangerouslySetInnerHTML={{ __html: noticeData.text }}></div></Descriptions.Item>
{[4, 5, 6].includes(noticeData.type) && <Descriptions.Item label="联系方式" className='alignTop'><div className="editor-w-text" dangerouslySetInnerHTML={{ __html: noticeData.contactInfo && noticeData.contactInfo.replace(/\n/g, '</br>') }}></div></Descriptions.Item>}
<Descriptions.Item label="公告附件">
<div style={{ color: '#1890ff' }} onClick={() => { download(noticeData.fileDownloadPath) }}>{noticeData.fileName}</div>
</Descriptions.Item>
<Descriptions.Item label="创建时间">{noticeData.createdAt}</Descriptions.Item>
{noticeData.publishDate && <Descriptions.Item label="发布时间">{noticeData.publishDate}</Descriptions.Item>}
<Descriptions.Item label="截止时间">{noticeData.closingDate}</Descriptions.Item>
<Descriptions.Item label="">
{admin && noticeData.status == 1 && noticeData.isChecked == 2 &&
<React.Fragment>
<Button className="mr20" type="primary" onClick={() => { checkItem(1) }}>通过</Button>
<Button className="mr20" type="primary" onClick={() => { checkItem(0) }}>拒绝</Button>
<Button className="mr20" onClick={() => { history.go(-1) }}>取消</Button>
</React.Fragment>
}
</Descriptions.Item>
</Descriptions>
</div>
)
}
export default IndexPage;

View File

@ -0,0 +1,22 @@
.itemContent {
padding: 10px 10px 0 30px;
}
.statusColor{
color: #1890ff;
}
.alignTop{
display: flex;
align-items: flex-start;
}
.backList{
margin-right:1em;
&:hover{
color: #1890ff;
}
}
:global{
.ant-descriptions-item-label{
min-width: 5em;
}
}

View File

@ -0,0 +1,322 @@
import React, { forwardRef, Fragment, useCallback, useEffect, useState } from 'react';
import ReactWEditor from 'wangeditor-for-react';
import { Form, Input, Button, Radio, Checkbox, DatePicker } from 'antd';
import moment from 'moment';
import { noticeType } from '../../common/static';
import Upload from '../../components/Upload';
import ShowNotification from '../../components/ShowNotification';
import { getNoticeDetail, addNotice, editNotice } from '../api';
import { httpUrl } from 'military/notice/fetch';
import '../index.css';
const format = "YYYY-MM-DD HH:mm:ss";
const { TextArea } = Input;
let actionUrl = httpUrl;
// if (window.location.href.indexOf('localhost') > -1) {
// actionUrl = httpUrl;
// } else {
// actionUrl = "https://info.osredm.com";
// }
const NoticeEdit = Form.create()(forwardRef(({ form, match, history }, ref) => {
const [fileList, setFileList] = useState(null);
const [noticeHtml, setNoticeHtml] = useState('');
const id = match.params.noticeId;
const { getFieldDecorator, validateFields, setFieldsValue } = form;
const [typeValue, setTypeValue] = useState(4);
const [isSecret, setIsSecret] = useState();
useEffect(() => {
id && getNoticeDetail(id).then(data => {
const formValue = {
type: data.type,
title: data.title,
publisher: data.publisher,
text: data.text,
closingDate: data.closingDate && moment(data.closingDate),
contactInfo: data.contactInfo,
};
setFieldsValue(formValue);
setNoticeHtml(data.text || '');
setIsSecret(Boolean(data.isSecret));
if (data.fileName) {
setFileList([{
name: data.fileName,
fileName: data.fileName,
fileDownloadPath: data.fileDownloadPath,
uid: "rc-upload" + data.id
}])
}
})
}, [id]);
//
function UploadFunc(fileList) {
setFileList(fileList);
}
const helper = useCallback(
(label, name, rules, widget, initialValue) => (
<Form.Item label={label}>
{getFieldDecorator(name, { rules, initialValue, validateFirst: true })(widget)}
</Form.Item>
),
[]
);
const editor = useCallback(() => (
<Form.Item label={"公告描述:"} required={true}>
{(!id || (id && noticeHtml)) &&
<ReactWEditor
defaultValue={noticeHtml}
config={
{
placeholder: "请输入公告描述",
excludeMenus: [
'list',
'todo',
'emoticon',
'video'
],
uploadImgServer: actionUrl + '/busiAttachments/upload',
uploadFileName: 'file',
uploadImgHeaders: {
'X-Requested-With': 'XMLHttpRequest'
},
uploadImgHooks: {
//
customInsert: function (insertImgFn, result) {
// result
// insertImgFn src
if (result && result.data && result.data.id) {
insertImgFn(`${actionUrl}/busiAttachments/view/${result.data.id}`);
}
}
}
}
}
onChange={(html) => {
changeHtml(html);
}}
/>}
{getFieldDecorator('text', {
rules: [{ required: true, message: "请输入公告描述" }],
validateFirst: true
})(<Input style={{ display: 'none' }} />)}
</Form.Item>
), [noticeHtml])
const formItemLayout = {
labelCol: {
xs: { span: 10 },
sm: { span: 8 },
lg: { span: 3 },
},
wrapperCol: {
xs: { span: 14 },
sm: { span: 16 },
lg: { span: 16 },
},
};
const tailFormItemLayout = {
wrapperCol: {
xs: {
span: 20,
offset: 4,
},
sm: {
span: 20,
offset: 4,
},
},
};
//
function saveItem(status) {
validateFields((error, values) => {
if (!error) {
let params = {
...values,
status,
fileDownloadPath: '',
fileName: '',
templateUrl: '',
};
params.closingDate = params.closingDate.format(format);
params.isSecret = Number(params.isSecret);
if (fileList && fileList.length) {
params.fileName = fileList[0].fileName || fileList[0].response.data.fileName;
params.fileDownloadPath = fileList[0].fileDownloadPath || `${actionUrl}/busiAttachments/download/${fileList[0].response.data.id}`;
}
if (id) {
//
params.id = id;
editNotice(params).then(res => {
if (res.message === 'success') {
ShowNotification("操作成功!");
if (status == 1) {
history.push('/managements/notice/list/2');
} else {
history.push('/managements/notice/list/draft');
}
} else {
ShowNotification(res.message);
}
});
} else {
//
addNotice(params).then(res => {
if (res.message === 'success') {
ShowNotification("公告新增成功!");
if (status == 1) {
history.push('/managements/notice/list/2');
} else {
history.push('/managements/notice/list/draft');
}
} else {
ShowNotification(res.message);
}
});
}
}
})
}
function changeClosingDate(val) {
if (val) {
let nextTime = moment(new Date().setDate(new Date().getDate() + val)).format('YYYY-MM-DD');
nextTime += ' 23:59:59';
setFieldsValue({
closingDate: moment(nextTime)
});
}
}
function changeHtml(html) {
setFieldsValue({
text: html
});
// setNoticeHtml(html);
}
return (
<div className="notice-content">
<h4 className="notice-title">{id ? '修改' : '发布'}公告</h4>
<Form className="notice-form" {...formItemLayout}>
{helper(
"公告类型:",
"type",
[{ required: true, message: "请选择公告类型" }],
<Radio.Group
onChange={(e) => { setTypeValue(e.target.value) }}
>
{
noticeType.map(item => {
return <Radio key={item.code} value={item.code}>{item.name}</Radio>
})
}
</Radio.Group>,
4
)}
{helper(
"公告标题:",
"title",
[{ required: true, message: "请输入公告标题" },
{ max: 50, message: '长度不能超过50个字符' }],
<Input
className="edit-input"
placeholder="请输入公告标题"
/>
)}
{helper(
"发布单位:",
"publisher",
[{ required: true, message: "请输入发布单位" },
{ max: 50, message: '长度不能超过50个字符' }],
<Input
className="edit-input"
placeholder="请输入发布单位"
/>
)}
{editor()}
{[4, 5, 6].includes(typeValue) && <Fragment>
{helper(
"联系方式:",
"contactInfo",
[{ max: 5000, message: '长度不能超过5000个字符' }],
<TextArea
rows={4}
// className="edit-input"
placeholder="请输入联系方式"
/>
)}
<Form.Item className="encrypt-item" label="加密与否">
{/* <Checkbox checked={isSecret} onChange={e => { setIsSecret(e.target.checked) }}>设置联系方式为加密内容</Checkbox> */}
{getFieldDecorator('isSecret',
{
validateFirst: true
})(<Checkbox checked={isSecret} onChange={e => { setIsSecret(e.target.checked) }}>设置联系方式为加密内容</Checkbox>)}
</Form.Item>
</Fragment>}
<Form.Item label={"上传文件:"}>
<Upload
className="commentStyle"
load={UploadFunc}
size={100}
ShowNotification={ShowNotification}
actionUrl={actionUrl}
fileList={fileList}
number={1}
/>
{/* 用一个隐藏的input实现上传文件的必填校验 */}
{/* {getFieldDecorator('file_name', {
rules: [{ required: true, message: "请上传公告文件" }],
validateFirst: true
})(<Input style={{ display: 'none' }} />)} */}
</Form.Item>
<Form.Item label="截止时间:">
<Radio.Group onChange={(e) => { changeClosingDate(e.target.value) }}>
<Radio value={6}>一周内</Radio>
<Radio value={29}>一个月内</Radio>
<Radio value={90}>三个月内</Radio>
<Radio value={182}>半年内</Radio>
<Radio value={0}>自定义</Radio>
</Radio.Group>
{getFieldDecorator('closingDate',
{
rules: [{ required: true, message: "请选择截止时间" }],
validateFirst: true
})(<DatePicker
showTime
format={format}
placeholder="请选择截止时间"
/>)}
</Form.Item>
<Form.Item {...tailFormItemLayout}>
<Button className="mr20" type={"primary"} onClick={() => { saveItem(1) }}>发布</Button>
<Button className="mr20" type={"primary"} onClick={() => { saveItem(2) }}>保存</Button>
<Button onClick={() => { history.go(-1) }}>取消</Button>
</Form.Item>
</Form>
</div>
)
})
)
export default NoticeEdit;

View File

@ -0,0 +1,302 @@
import React, { forwardRef, useEffect, useState, useCallback } from 'react';
import { Button, Form, Modal, Input, Select, Radio, } from 'antd';
import PaginationTable from "../../../components/pagination-table";
import { noticeType } from '../../common/static';
import DelModal from '../../components/DelModal';
import ShowNotification from '../../components/ShowNotification';
import { getNoticeList, checkNotice, deleteNotice } from '../api';
import '../index.css';
import './index.scss';
const Option = Select.Option;
const noticeTypeArr = [];
for (const item of noticeType) {
noticeTypeArr[item.code] = (item.name);
}
const NoticeList = Form.create()(forwardRef(({ form, match, history, current_user: { admin } }, ref) => {
let status = 1;
let isChecked = match.params.isChecked;
if (history.location.pathname.indexOf('draft') > -1) {
status = 2;
isChecked ='';
}
const { getFieldDecorator, validateFields, setFieldsValue, } = form;
const [type, setType] = useState(undefined);
const [title, setTitle] = useState(undefined);
const [pageSize, setPageSize] = useState(10);
const [curPage, setCurPage] = useState(1);
const [total, setTotal] = useState(0);
const [orderBy, setOrderBy] = useState('');
const [dataList, setDataList] = useState([]);
const [loading, setLoading] = useState(false);
const [visible, setVisible] = useState(false);
const [currentId, setCurrentId] = useState('');
const [currentIsChecked, setCurrentIsChecked] = useState(1);
const [reload, setReload] = useState(0);
useEffect(() => {
//
console.log('useEffect --- ');
//
history.listen(historyLocation => {
//
// console.log('route history , ', history);
// console.log('route history location , ', historyLocation);
setCurPage(1);
setType(undefined);
setTitle(undefined);
setFieldsValue({
type: undefined,
title: undefined,
});
})
}, [history]);
useEffect(() => {
setLoading(true);
getNoticeList({
orderBy,
curPage,
isChecked,
pageSize,
status,
type,
title,
flag: 2, //21
}).then(data => {
setLoading(false);
if (data) {
setDataList(data.rows);
setTotal(data.total);
} else {
setTotal(0);
setDataList([]);
}
});
}, [curPage, type, title, isChecked, reload,pageSize]);
const columns = [
{
title: '公告标题',
dataIndex: 'title',
key: 'title',
width: '30%'
},
{
title: '公告类型',
key: 'type',
dataIndex: 'type',
render: (text, record) => {
return noticeTypeArr[text];
}
},
{
title: '创建时间',
key: 'createdAt',
dataIndex: 'createdAt',
},
{
title: '截止时间',
key: 'closingDate',
dataIndex: 'closingDate',
},
{
title: '操作',
key: 'action',
render: (text, record) => (
<span>
{record.status == 2 && <Button className="mr5 font-12" type="primary" size="small" onClick={() => { editItem(record.id) }}>修改</Button>}
<Button className="mr5 font-12" type="info" size="small" onClick={() => { detailItem(record.id) }}>详情</Button>
{admin && record.status == 1 && record.isChecked == 2 && <Button className="mr5 font-12" type="primary" size="small" onClick={() => { setCurrentId(record.id); setVisible(true); }}>审核</Button>}
{(admin || (record.isChecked != 1)) && < Button className="mr5 font-12" type="danger" size="small" onClick={() => { deletItem(record.id) }}>删除</Button>}
</span >
),
},
];
//
if (isChecked == 1) {
columns.splice(3, 0, {
title: '发布时间',
key: 'publishDate',
dataIndex: 'publishDate',
});
columns.splice(4, 0, {
title: '密文浏览数',
key: 'requestViewCount',
dataIndex: 'requestViewCount',
render: (text, record) => {
return <span className={`${text > 0 ? 'link' : ''}`} onClick={() => { text > 0 && history.push(`/managements/notice/reader/${record.id}`) }}>{text}</span>;
}
});
}
function detailItem(id) {
history.push(`/managements/notice/detail/${id}`);
}
//
function checkItem() {
checkNotice({
id: currentId,
isChecked: currentIsChecked,
}).then(res => {
if (res && res.code == '1') {
ShowNotification("操作成功");
setVisible(false);
setReload(reload + 1);
} else {
ShowNotification(res.message || "操作失败");
}
})
}
function editItem(id) {
history.push(`/managements/notice/edit/${id}`);
}
function deletItem(id) {
DelModal(() => {
deleteNotice(id).then(res => {
if (res.message === 'success') {
ShowNotification("删除成功");
if (dataList.length == 1 && curPage > 1) {
setCurPage(curPage - 1);
} else {
setReload(reload + 1);
}
} else {
ShowNotification("删除失败");
}
})
}, '此操作将删除该记录, 是否继续?');
}
function handleSearch() {
validateFields((error, values) => {
console.log(values);
if (!error) {
setType(values.type || "");
setTitle(values.title);
}
});
}
const helper = useCallback(
(label, name, rules, widget) => (
<Form.Item label={label} className='searchForm'>
{getFieldDecorator(name, { rules, validateFirst: true, })(widget)}
</Form.Item>
), []);
const formItemLayout = {
labelCol: {
xs: { span: 12 },
sm: { span: 6 },
},
wrapperCol: {
xs: { span: 12 },
sm: { span: 18 },
},
};
function onShowSizeChange(current, pageSize) {
setCurPage(current);
setPageSize(pageSize);
}
return (
<div className="content">
<Form className="clearfix">
{helper(
"",
"type",
[],
<Select
placeholder="公告类型"
allowClear
showArrow
>
{
noticeType.map(item => {
return <Option key={item.code}>{item.name}</Option>
})
}
</Select>
)}
{helper(
"",
"title",
[{ max: 20, message: '关键字长度不能超过20个字符' }],
<Input
placeholder="输入标题关键字进行搜索"
/>
)}
<Button className="my-search-button" type="primary" onClick={handleSearch}>查询</Button>
</Form>
<div className="table-detail">
<PaginationTable
loading={loading}
dataSource={dataList}
columns={columns}
total={total}
setCurPage={setCurPage}
current={curPage}
onShowSizeChange={onShowSizeChange}
showSizeChanger
/>
{/* <Table
loading={loading}
rowKey={(row) => row.id}
dataSource={dataList}
columns={columns}
pagination={false}
/>
{dataList.length > 0 &&
<Pagination
onChange={(page) => { setCurPage(page) }}
current={curPage}
total={total}
/>} */}
</div>
<Modal
title="公告审核"
visible={visible}
onOk={checkItem}
onCancel={() => { setVisible(false) }}
className="form-edit-modal"
>
<Form {...formItemLayout}>
<Form.Item label={"审核意见:"} >
<Radio.Group defaultValue={currentIsChecked} onChange={(e) => { setCurrentIsChecked(e.target.value) }} >
<Radio className="columsRadio" value={1}>
通过
</Radio>
<Radio className="columsRadio" value={0}>
拒绝
</Radio>
</Radio.Group>
</Form.Item>
</Form>
</Modal>
</div>
);
})
)
export default NoticeList;

View File

@ -0,0 +1,7 @@
.searchForm{
float: left;
min-width: 260px;
margin-right:2em !important;
}

View File

@ -0,0 +1,105 @@
import React, { useCallback, useEffect, useState } from 'react';
import { Button, Descriptions, Pagination, Icon, Table } from 'antd';
import PaginationTable from "../../../components/pagination-table";
import { noticeType, noticeChecked } from '../../common/static';
import { getNoticeDetail, getNoticeReader } from '../api';
import '../index.css';
import './index.scss';
const noticeTypeArr = [];
for (const item of noticeType) {
noticeTypeArr[item.code] = (item.name);
}
const noticeCheckedArr = [];
for (const item of noticeChecked) {
noticeCheckedArr[item.code] = (item.name);
}
const NoticeReader = ({ match, history }) => {
const id = match.params.noticeId;
const [noticeData, setNoticeData] = useState({});
const [loading, setLoading] = useState(false);
const [dataList, setDataList] = useState([]);
const [pageSize, setPageSize] = useState(10);
const [curPage, setCurPage] = useState(1);
const [total, setTotal] = useState(0);
useEffect(() => {
id && getNoticeDetail(id).then(data => {
setNoticeData(data || {});
})
}, [id]);
useEffect(() => {
setLoading(true);
id && getNoticeReader({
currentPage: curPage,
annId: id,
pageSize,
}).then(data => {
setLoading(false);
if (data) {
setDataList(data.rows);
setTotal(data.total);
} else {
setTotal(0);
setDataList([]);
}
})
}, [id, curPage, pageSize]);
const columns = [
{
title: '用户姓名',
key: 'readerName',
dataIndex: 'readerName',
width: '20%',
},
{
title: '公司名称',
key: 'companyName',
dataIndex: 'companyName',
width: '40%',
},
{
title: '联系方式',
key: 'contactInfo',
dataIndex: 'contactInfo',
width: '40%',
},
];
function onShowSizeChange(current, pageSize) {
setCurPage(current);
setPageSize(pageSize);
}
return (
<div className="notice-content">
<h4 className="notice-title"><span className='backList' onClick={() => { history.go(-1) }}><Icon type="left" />返回</span>浏览过该公告加密内容的用户详情</h4>
<Descriptions className='itemContent' column={1}>
<Descriptions.Item label="公告标题">{noticeData.title}</Descriptions.Item>
<Descriptions.Item label="加密信息被浏览数">{total}</Descriptions.Item>
<Descriptions.Item label="浏览过该公告加密内容的用户信息"></Descriptions.Item>
</Descriptions>
<div className="table-detail">
<PaginationTable
loading={loading}
dataSource={dataList}
columns={columns}
total={total}
setCurPage={setCurPage}
current={curPage}
onShowSizeChange={onShowSizeChange}
showSizeChanger
/>
</div>
</div>
)
}
export default NoticeReader;

View File

@ -0,0 +1,25 @@
.itemContent {
padding: 10px 10px 0 30px;
}
.statusColor{
color: #1890ff;
}
.alignTop{
display: flex;
align-items: flex-start;
}
.backList{
margin-right:1em;
&:hover{
color: #1890ff;
}
}
:global{
.ant-descriptions-item-label{
min-width: 5em;
}
.ant-table-row-cell-break-word{
word-break: break-all;
}
}

View File

@ -0,0 +1,175 @@
import React, { useEffect, useState } from 'react';
import { Table, Pagination, notification, Input } from 'antd';
import { paramToUrl } from '../../common/utils';
import fetch from 'military/notice/fetch';
const { Search } = Input;
export default function Activity(props) {
const [curPage, setCurPage] = useState(1);
const [total, setTotal] = useState(0);
const [orderBy, setOrderBy] = useState('');
const [dataList, setDataList] = useState([]);
const [loading, setLoading] = useState(false);
const [projectName, setProjectName] = useState('');
useEffect(() => {
// table
let params = {
orderBy,
curPage,
projectName,
pageSize: 10,
};
let url = encodeURI(paramToUrl('/api/ProjectActivityData/', params));
setLoading(true);
fetch({
url,
method: 'get',
}).then(res => {
if (res.code === '1') {
setDataList(res.data.rows);
setTotal(res.data.total);
} else {
setDataList([]);
setTotal(0);
notification.open({
message: "错误",
description: res.message,
});
}
setLoading(false);
});
}, [curPage, orderBy, projectName]);
function handleTableChange(pagination, filters, sorter) {
if (sorter.order) {
if (sorter.order === 'ascend') {
setOrderBy(sorter.field + 'Asc');
} else {
setOrderBy(sorter.field + 'Desc');
}
} else {
setOrderBy('');
}
}
function onCell(record) {
return {
onClick: event => { onCellClick(record) }, //
}
}
function onCellClick(record) {
let url = encodeURI(paramToUrl('/api/ProjectActivityData/getUrl', { projectId: record.projectId }));
fetch({
url,
method: 'get',
}).then(res => {
if (res.code === '1') {
window.open(res.data);
} else {
notification.open({
message: "错误",
description: res.message,
});
}
});
}
const columns = [
{
title: '项目名',
dataIndex: 'name',
key: 'name',
className: 'link',
onCell,
},
{
title: '活跃度',
key: 'activityScore',
dataIndex: 'activityScore',
sorter: true,
},
{
title: '浏览数',
key: 'visits',
dataIndex: 'visits',
sorter: true,
},
{
title: '点赞数',
key: 'praisesCount',
dataIndex: 'praisesCount',
sorter: true,
},
{
title: '关注数',
key: 'watchersCount',
dataIndex: 'watchersCount',
sorter: true,
},
{
title: '任务数',
key: 'issuesCount',
dataIndex: 'issuesCount',
sorter: true,
},
{
title: 'PR数',
key: 'pullRequestsCount',
dataIndex: 'pullRequestsCount',
sorter: true,
},
{
title: '版本数',
key: 'versionsCount',
dataIndex: 'versionsCount',
sorter: true,
},
];
function searchFun(val) {
setProjectName(val);
setCurPage(1);
}
return (
<div className="content">
<Search
style={{ width: '300px', margin: '1em' }}
placeholder="请输入项目关键字"
enterButton="搜索"
size="large"
onSearch={searchFun}
className="global-search"
maxLength={20}
/>
<div className="table-detail">
<Table
loading={loading}
rowKey={(row) => row.id}
dataSource={dataList}
columns={columns}
pagination={false}
onChange={handleTableChange} //
/>
{dataList.length > 0 &&
<Pagination
onChange={(page) => { setCurPage(page) }}
current={curPage}
total={total}
/>}
</div>
</div>
);
}

View File

@ -0,0 +1,134 @@
import React, { useEffect, useState } from 'react';
import { Icon, Col, Row, Tabs, notification } from 'antd';
import EchartBar from '../../components/EchartBar';
import fetch from 'military/notice/fetch';
import './index.scss';
const { TabPane } = Tabs;
let length = 13;
let nowMonth = new Date().getMonth() + 1;
let year = new Date().getFullYear() - 1;
let monthArr = [];
if (nowMonth === 13) {
nowMonth = 1
}
for (let i = 0; i < length; i++) {
monthArr.push(year + '.' + nowMonth);
nowMonth++;
if (nowMonth === 13) {
nowMonth = 1;
year++;
}
}
export default function Global(props){
const [type, setType] = useState(1);
const [totalProjects, setTotalProjects] = useState(0);
const [totalMembers, setTotalMembers] = useState(0);
const [newAddedProjects, setNewAddedProjects] = useState([]);
const [newAddedMembers, setNewAddedMembers] = useState([]);
const [newCodeSubmissionTimes, setNewCodeSubmissionTimes] = useState([]);
const [taskCompletion, setTaskCompletion] = useState([]);
useEffect(() => {
fetch({
url: 'http://111.8.36.180:8092/api/GlobalResourcesData/',
method: 'get',
}).then(res => {
if (res.data) {
const data = res.data;
setTotalProjects(data.totalProjects);
setTotalMembers(data.totalMembers);
setNewAddedProjects(data.newAddedProjects);
setNewAddedMembers(data.newAddedMembers);
setNewCodeSubmissionTimes(data.newCodeSubmissionTimes);
setTaskCompletion(data.taskCompletion);
} else {
notification.open({
message: "错误",
description: res.message,
});
}
});
}, []);
return (
<div className="content">
<Row>
<Col className="box-item" xs={12} lg={6}>
<Icon type="folder" />
<div>
<p className="box-item-tit">项目总数</p>
<p className="box-item-num">{totalProjects}</p>
<p className="box-item-describe">当前项目总数</p>
</div>
</Col>
<Col className="box-item" xs={12} lg={6}>
<Icon type="user" />
<div>
<p className="box-item-tit">用户总数</p>
<p className="box-item-num">{totalMembers}</p>
<p className="box-item-describe">当前用户总数</p>
</div>
</Col>
</Row>
<Tabs defaultActiveKey="1" onChange={(key) => { setType(key) }}>
<TabPane tab="开源统计" key="1">
<Row>
<Col xs={24} lg={12}>
<EchartBar
id="newAddedProjects"
className="echart-box"
title="新项目统计"
xData={monthArr}
yData={newAddedProjects}
/>
</Col>
<Col xs={24} lg={12}>
<EchartBar
id="newAddedMembers"
className="echart-box"
title="新用户统计"
xData={monthArr}
yData={newAddedMembers}
/>
</Col>
<Col xs={24} lg={12}>
<EchartBar
id="newCodeSubmissionTimes"
className="echart-box"
title="issue创建数"
xData={monthArr}
yData={newCodeSubmissionTimes}
/>
</Col>
<Col xs={24} lg={12}>
<EchartBar
id="taskCompletion"
className="echart-box"
title="任务完成量"
xData={monthArr}
yData={taskCompletion}
/>
</Col>
</Row>
</TabPane>
{/* <TabPane tab="" key="2">
</TabPane>
<TabPane tab="其他" key="4">
</TabPane> */}
</Tabs>
</div>
);
}

View File

@ -0,0 +1,50 @@
.box-item{
display: flex;
max-width: 300px;
justify-content: space-around;
margin: .75em;
padding: .5em;
background: #fff;
border-radius: .5em;
box-shadow: 0 1px 1px #d9d9d9;
.anticon{
font-size: 4em;
color: #1890ff;
}
.box-item-num{
font-size: 2em;
margin-bottom: 0;
}
.box-item-describe{
font-size: .9em;
color: #999;
}
}
.ant-tabs-bar{
border: 0;
}
.ant-tabs-tabpane {
min-height: 25vh;
}
.ant-tabs-tab-active {
color: #000;
font-weight: 600;
}
.ant-tabs-nav .ant-tabs-tab:hover {
color: #000;
font-weight: 600;
}
.echart-box{
height: 300px;
margin: .75em;
padding: 1em;
border-radius: .5em;
background: #fff;
border:1px solid #d9d9d9;
}

View File

@ -0,0 +1,49 @@
import React from "react";
import { Route, Switch } from "react-router-dom";
import Loadable from "react-loadable";
import Loading from "../../Loading";
//
const Global = Loadable({
loader: () => import("./global"),
loading: Loading,
});
//
const Member = Loadable({
loader: () => import("./member"),
loading: Loading,
});
//
const Activity = Loadable({
loader: () => import("./activity"),
loading: Loading,
});
export default (propsF)=>{
return (
<Switch {...propsF}>
{/* 全局统计 */}
<Route
path="/managements/statistics/global"
render={(props) => (
<Global {...propsF} {...props} />
)}
></Route>
{/* 成员工作统计 */}
<Route
path="/managements/statistics/member"
render={(props) => (
<Member {...propsF} {...props} />
)}
></Route>
{/* 活跃度统计 */}
<Route
path="/managements/statistics/activity"
render={(props) => (
<Activity {...propsF} {...props} />
)}
></Route>
</Switch>
)
}

View File

@ -0,0 +1,280 @@
import React, { useEffect, useState } from 'react';
import { Col, Row, Select, Button, DatePicker, notification } from 'antd';
import moment from 'moment';
import EchartLine from '../../components/EchartLine';
import { beforeDayArr, paramToUrl } from '../../common/utils';
import TableDetail from './table-detail';
import fetch from 'military/notice/fetch';
import './index.scss';
const { Option } = Select;
const ButtonGroup = Button.Group;
const { RangePicker } = DatePicker;
const monthArr = beforeDayArr();
const nowDate = moment(new Date()).format('YYYY-MM-DD');
const weekAgo = moment(new Date().setDate(new Date().getDate() - 6)).format('YYYY-MM-DD');
console.log(weekAgo);
const monthAgo = moment(new Date().setDate(new Date().getDate() - 30)).format('YYYY-MM-DD');
const threeMonthAgo = moment(new Date().setDate(new Date().getDate() - 90)).format('YYYY-MM-DD');
export default function Member(props) {
const [member, setMember] = useState(undefined);
const [memberList, setMemberList] = useState([]);
const [timeType, setTimeType] = useState(2);
const [dayNum, setDayNum] = useState(30);
const [timeArr, setTimeArr] = useState(monthArr);
const [startTime, setStartTime] = useState(monthAgo); //
const [endTime, setEndTime] = useState(nowDate);
const [newTask, setNewTask] = useState(null);
const [completedTask, setCompletedTask] = useState(null);
const [newPrNum, setNewPrNum] = useState(null);
const [newCommitNum, setNewCommitNum] = useState(null);
const [newCodeNum, setNewCodeNum] = useState(null);
// 线
function getAllDataLine() {
let params = {
startTime,
endTime,
}
let url = encodeURI(paramToUrl('/api/DeveloperData/total', params));
fetch({
url,
method: 'get',
}).then(res => {
if (res.code === '1') {
const data = res.data;
setNewTask(data.newTask);
setCompletedTask(data.completedTask);
setNewPrNum(data.newPrNum);
setNewCommitNum(data.newCommitNum);
setNewCodeNum(data.newCodeNum);
}
});
}
//
function getPersonData() {
let params = {
startTime,
endTime,
curPage: 1,
pageSize: 31,
userId: member.key,
userName:member.login,
};
if (timeType == 1) {
params.pageSize = 7;
} else if (timeType == 3) {
params.pageSize = 91;
} else if (timeType == 0) {
params.pageSize = dayNum;
}
let url = encodeURI(paramToUrl('/api/DeveloperData/detail/search', params));
fetch({
url,
method: 'get',
}).then(res => {
let newTask = [];
let completedTask = [];
let newPrNum = [];
let newCommitNum = [];
let newCodeNum = [];
if (res.code === '1' && res.data.rows) {
if (res.data.rows.length) {
for (const item of res.data.rows) {
newTask.unshift(item.newTask);
completedTask.unshift(item.completedTask);
newPrNum.unshift(item.newPrNum);
newCommitNum.unshift(item.newCommitNum);
newCodeNum.unshift(item.newCodeNum);
}
} else {
newCodeNum.fill(0, 0,);
}
} else {
notification.open({
message: "错误",
description: res.message,
});
}
setNewTask(newTask);
setCompletedTask(completedTask);
setNewPrNum(newPrNum);
setNewCommitNum(newCommitNum);
setNewCodeNum(newCodeNum);
});
}
function onSearch(value) {
if (value) {
getMemberList(value);
}
}
//
let timeout;
function getMemberList(value) {
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
function fake() {
fetch({
url: '/api/DeveloperData/detail/searchInput?userName=' + value,
method: 'get',
}).then(res => {
if (res.code === '1') {
setMemberList(res.data);
} else {
notification.open({
message: "错误",
description: res.message,
});
}
});
}
timeout = setTimeout(fake, 1000);
}
function searchInTime(timeType) {
setTimeType(timeType);
if (timeType === 1) {
setTimeArr(beforeDayArr(7));
setStartTime(weekAgo);
setEndTime(nowDate);
} else if (timeType === 2) {
setTimeArr(monthArr);
setStartTime(monthAgo);
setEndTime(nowDate);
} else if (timeType === 3) {
setTimeArr(beforeDayArr(91));
setStartTime(threeMonthAgo);
setEndTime(nowDate);
}
}
function changeDate(dates, dateStrings) {
if (dateStrings && dateStrings[0]) {
setStartTime(dateStrings[0]);
setEndTime(dateStrings[1]);
let dayNum = (dates[1] - dates[0]) / 86400000 + 1;
setTimeArr(beforeDayArr(dayNum, new Date(dates[1])));
setTimeType(0);
setDayNum(dayNum);
} else {
setTimeType(2);
setTimeArr(monthArr);
setStartTime(monthAgo);
setEndTime(nowDate);
}
}
useEffect(() => {
if (member) {
getPersonData();
} else {
getAllDataLine();
}
}, [startTime, endTime, member]);
function changeMember(val){
if(val){
for(const item of memberList){
if(val.key==item.id){
val.login=item.login
}
}
}
setMember(val);
}
return (
<div className="content">
<Row className="search-box">
<Col xs={24} sm={12} lg={10} >
<Select
showSearch
value={member}
placeholder={'请选择成员或输入成员查询'}
defaultActiveFirstOption={false}
filterOption={false}
onSearch={onSearch}
onChange={(val) => { changeMember(val) }}
notFoundContent={null}
allowClear={true}
labelInValue
>
{
memberList.map(d => <Option key={d.id}>{d.nickname || d.login}</Option>)
}
</Select>
</Col>
<Col xs={24} sm={12} lg={14} className="choose-time">
<ButtonGroup>
<Button type={timeType === 1 ? "primary" : ""} onClick={() => { searchInTime(1) }}>
近1周
</Button>
<Button type={timeType === 2 ? "primary" : ""} onClick={() => { searchInTime(2) }}>
近1月
</Button>
<Button type={timeType === 3 ? "primary" : ""} onClick={() => { searchInTime(3) }}>
近3月
</Button>
</ButtonGroup>
<div className="custom-time">
<div className="time-label">自定义时间段</div>
<RangePicker
placeholder={['--/--', '--/--']}
onChange={changeDate}
/>
</div>
</Col>
</Row>
<EchartLine
id="memberStatistics"
xData={timeArr}
seriesArr={
[{
name: '新增任务数',
data: newTask
}, {
name: '完成任务数',
data: completedTask
}, {
name: '新增PR数',
data: newPrNum
}, {
name: '新增提交数',
data: newCommitNum
}, {
name: '新增代码数',
data: newCodeNum
}]
}
/>
<h4 className="mt20">详情列表</h4>
<TableDetail
member={member}
startTime={startTime}
endTime={endTime}
/>
</div>
);
}

View File

@ -0,0 +1,44 @@
.search-box {
margin-bottom: .75rem;
.ant-select {
min-width: 280px;
}
.ant-btn:active, .ant-btn.active{
color: #fff;
background-color: #096dd9;
border-color: #096dd9;
}
.choose-time{
display: flex;
justify-content: flex-end;
}
.ant-btn-group{
margin-right: 10px;
}
.custom-time{
display: flex;
justify-content: flex-end;
align-items: center;
}
.ant-calendar-picker{
max-width: 250px;
}
.time-label{
background: #fafbfc;
line-height: 30px;
padding: 0 10px;
border: 1px solid #d9d9d9;
border-right: 0;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
}
.ant-calendar-picker-input{
text-align: left;
border-top-left-radius: 0px;
border-bottom-left-radius: 0px;
}
}

View File

@ -0,0 +1,175 @@
import React, { useEffect, useState } from 'react';
import { Table, Pagination, notification } from 'antd';
import { paramToUrl } from '../../common/utils';
import fetch from 'military/notice/fetch';
export default ({ member, startTime, endTime }) => {
const [curPage, setCurPage] = useState(1);
const [total, setTotal] = useState(0);
const [orderBy, setOrderBy] = useState('');
const [dataList, setDataList] = useState([]);
const [loading, setLoading] = useState(false);
useEffect(() => {
getTableData();
}, [member, startTime, endTime, orderBy, curPage]);
// table
function getTableData() {
let params = {
startTime,
endTime,
orderBy,
curPage,
pageSize: 10,
};
setLoading(true);
let url;
if (member) {
//
params = {
...params,
userId: member.key,
userName: member.login,
};
url = encodeURI(paramToUrl('/api/DeveloperData/detail/search', params));
} else {
//
url = encodeURI(paramToUrl('/api/DeveloperData/detail', params));
}
fetch({
url,
method: 'get',
data: params
}).then(res => {
if (res.code === '1') {
setDataList(res.data.rows);
setTotal(res.data.total);
} else {
setDataList([]);
setTotal(0);
notification.open({
message: "错误",
description: res.message,
});
}
setLoading(false);
});
}
function handleTableChange(pagination, filters, sorter) {
if (sorter.order) {
if (sorter.order === 'ascend') {
setOrderBy(sorter.field + 'Asc');
setCurPage(1);
} else {
setOrderBy(sorter.field + 'Desc');
setCurPage(1);
}
} else {
setOrderBy('');
setCurPage(1);
}
}
const columns = [
{
title: '成员姓名',
dataIndex: 'nickName',
key: 'nickName',
width: '20%',
className: 'link',
onCell,
render: (text, record) => {
return (text || record.userName)
}
},
{
title: '新增任务数',
key: 'newTask',
dataIndex: 'newTask',
sorter: true,
},
{
title: '完成任务数',
key: 'completedTask',
dataIndex: 'completedTask',
sorter: true,
},
{
title: '新增PR数',
key: 'newPrNum',
dataIndex: 'newPrNum',
sorter: true,
},
{
title: '新增提交数',
key: 'newCommitNum',
dataIndex: 'newCommitNum',
sorter: true,
},
// {
// title: '',
// key: 'newCodeNum',
// dataIndex: 'newCodeNum',
// },
];
function onCell(record) {
return {
onClick: event => { onCellClick(record) }, //
}
}
function onCellClick(record) {
let url = encodeURI(paramToUrl('/api/DeveloperData/getUrl', { login: record.userName }));
fetch({
url,
method: 'get',
}).then(res => {
if (res.code === '1') {
window.open(res.data);
} else {
notification.open({
message: "错误",
description: res.message,
});
}
});
}
if (member) {
columns.splice(0, 1, {
title: '日期',
dataIndex: 'date',
key: 'date',
width: '20%',
})
}
return (
<div className="table-detail">
<Table
loading={loading}
rowKey={(row, i) => row.id || i}
dataSource={dataList}
columns={columns}
pagination={false}
onChange={handleTableChange}
/>
{dataList.length > 0 &&
<Pagination
onChange={(page) => { setCurPage(page) }}
current={curPage}
total={total}
loading={loading}
/>}
</div>
)
}

View File

@ -7,9 +7,10 @@ function Uploads({ className, size, actionUrl, fileList, showNotification, load
const [files, setFiles] = useState(undefined);
useEffect(() => {
if (fileList) {
init();
}
// if (fileList) {
// init();
// }
init();
}, [fileList]);
function init() {

View File

@ -8,6 +8,7 @@ import { getCompetitionList, getRules, selectExpertList, updateCompetitionReview
import { competitionStatus } from "../static";
import './index.scss';
import '../../../managements/index.scss';
const Option = Select.Option;
const statusArr = [];
@ -260,7 +261,7 @@ function Competition(props){
// ,
function updateUrl(page){
setCurPage(page);
window.location.href=`/managements/expert/competition/#page=${page}`;
window.location.href=`/managements/expert/competition#page=${page}`;
}
function hashDate(hash) {

View File

@ -57,6 +57,7 @@ a.primary-link{
}
.competitionList{
margin-top: 1rem;
.ant-select-selection{
width: 115px;
}

View File

@ -2,7 +2,7 @@ import React, { useState, useMemo, useEffect } from "react";
import { Input, Select, Button, Form, Table, Upload, Modal, Popconfirm, message } from 'antd';
import cookie from 'react-cookies';
import { exportExcel } from '../components/exportExcel.js';
import Paginationtable from "../../components/paginationTable";
import Paginationtable from "../../../components/pagination-table";
import { Info } from '../../components/ModalFun';
import { expertList, deleteExpert } from "../api";
import { professionalType, reviewArea } from "../static";
@ -221,6 +221,9 @@ function RegisterList({ showNotification }) {
statusString: '1',
};
expertList(params).then(data => {
if((data.rows && data.rows.length<=0) && curPage>1){
setCurPage(curPage-1);
}
setDataList(data.rows || []);
setLoading(false);
setTotal(data && data.total);
@ -315,15 +318,16 @@ function RegisterList({ showNotification }) {
};
return (
<div className="expert-list centerbox">
<div className="expert-list">
<div className="center-screen" >
<div className="center-right-but">
<div className="center-right-but btn-group">
<Form.Item label={"姓名/手机"}>
<Search
maxLength={20}
style={{ width: "300px" }}
placeholder="请输入专家姓名或手机号"
onSearch={(value) => { setSearchInput(value); setCurPage(1); }}
allowClear
/>
</Form.Item>

View File

@ -8,8 +8,10 @@
}
.center-right-but{
flex:auto;
justify-content: space-between;
justify-content: flex-start;
margin-right: 4em;
.ant-row{margin-right: 5rem;}
.ant-form-item{margin-bottom: 0;}
}
.ant-form-item-control-wrapper{

View File

@ -4,6 +4,7 @@ import javaFetch from '../javaFetch';
let settings = localStorage.chromesetting && JSON.parse(localStorage.chromesetting);
let actionUrl = settings && settings.api_urls && settings.api_urls.task ? settings.api_urls.task : 'https://task.osredm.com';
// let actionUrl = 'http://10.47.38.60:8088';
const service = javaFetch(actionUrl);
export const httpUrl = actionUrl;
export const main_web_site_url = settings && settings.main_web_site_url;

View File

@ -178,4 +178,10 @@
}
}
.expert-list .center-screen{
padding: 1rem;
background: #fff;
border-radius: 4px;
box-shadow:0px 0px 10px rgba(88, 116, 255, 0.18);
margin: 1rem 0;
}

View File

@ -1,6 +1,6 @@
import React, { useState, useCallback, useMemo, useEffect } from "react";
import { Input, Select, Button, Form, Modal } from 'antd';
import Paginationtable from "../../components/paginationTable";
import Paginationtable from "../../../components/pagination-table";
import { Confirm } from '../../components/ModalFun';
import { expertList, registerCheck } from "../api";
import { httpUrl } from '../fetch';
@ -188,6 +188,9 @@ function RegisterList({ showNotification, form }) {
};
expertList(params).then(data => {
if (data && Array.isArray(data.rows)) {
if((data.rows && data.rows.length<=0) && curPage>1){
setCurPage(curPage-1);
}
for (const item of data.rows) {
item.detail = item.paperDetail && item.paperDetail.content;
}
@ -249,21 +252,17 @@ function RegisterList({ showNotification, form }) {
});
}
});
}
return (
<div className="expert-list centerbox">
<div className="center-screen mb30" >
<Search
maxLength={20}
style={{ width: "300px" }}
placeholder="请输入专家姓名或手机号"
onSearch={(value) => { setSearchInput(value); setCurPage(1); }}
/>
<div className="center-screen mb20" >
<Search
maxLength={20}
style={{ width: "300px" }}
placeholder="请输入专家姓名或手机号"
onSearch={(value) => { setSearchInput(value); setCurPage(1); }}
/>
</div>
<Paginationtable
loading={loading}

View File

@ -39,6 +39,9 @@ export default Form.create()(({ form, showNotification, match, history }) => {
setLoading(true);
agreementList(params).then(data => {
if (data) {
if((data.rows && data.rows.length<=0) && curPage>1){
setCurPage(curPage-1);
}
if (loadPaper === 0 && data.rows.length === 0) {
setLoadPaper(1);
} else {

View File

@ -3,7 +3,6 @@
display: flex;
justify-content: space-between;
padding: 20px;
margin: 0 1.5rem;
background: #fff;
border-bottom: 1px solid #dedede;
a.edu-orangeline-btn {

View File

@ -3,7 +3,6 @@
display: flex;
justify-content: space-between;
padding: 20px;
margin: 0 1.5rem;
background: #fff;
border-bottom: 1px solid #dedede;
a.edu-orangeline-btn {

View File

@ -62,6 +62,11 @@ export default Form.create()((props) => {
}
function uploadAgree(item) {
//
setFileList(null);
setFieldsValue({
files: ''
});
setVisibleAgree(true);
setTaskId(item.id);
setCheckItem(item);

View File

@ -3,7 +3,6 @@
display: flex;
justify-content: space-between;
padding: 20px;
margin: 0 1.5rem;
background: #fff;
border-bottom: 1px solid #dedede;
a.edu-orangeline-btn {

View File

@ -3,7 +3,6 @@
display: flex;
justify-content: space-between;
padding: 20px;
margin: 0 1.5rem;
background: #fff;
border-bottom: 1px solid #dedede;
a.edu-orangeline-btn {

View File

@ -23,6 +23,14 @@ export default Form.create()((props) => {
function deal(item) {
//
setIsAccepted('');
setIsReconsidered('');
setIsChanged('');
setFieldsValue({
isAccepted: '',
reason: '',
});
setCheckedItem(item);
setVisible(true);
}
@ -37,6 +45,9 @@ export default Form.create()((props) => {
if (res && res.message === 'success') {
showNotification('操作成功');
reloadList();
setIsAccepted('');
setIsReconsidered('');
setIsChanged('');
setFieldsValue({
isAccepted: '',
reason: '',

View File

@ -3,7 +3,6 @@
display: flex;
justify-content: space-between;
padding: 20px;
margin: 0 1.5rem;
background: #fff;
border-bottom: 1px solid #dedede;
a.edu-orangeline-btn {

View File

@ -90,7 +90,7 @@ export default (props) => {
<span className="fl color-grey-9 mt3">{timeAgo(item.createdAt)}</span>
<span className="fr">
{item.status > 2 && item.status !== 9 && <span className="spanTitle color-grey-6 fl ml20">已同意</span>}
{item.status === 9 && <span className="spanTitle color-yellow fl ml20">已处理</span>}
{item.status === 9 && <span className="spanTitle color-yellow fl ml20">待修缮</span>}
{item.status === 2 && <span className="spanTitle color-red fl ml20">已拒绝</span>}
{

View File

@ -3,7 +3,6 @@
display: flex;
justify-content: space-between;
padding: 20px;
margin: 0 1.5rem;
background: #fff;
border-bottom: 1px solid #dedede;
a.edu-orangeline-btn {

View File

@ -37,6 +37,9 @@ export default ({ current_user, showNotification, history }) => {
setLoading(true);
delayList(params).then(data => {
if (data) {
if((data.rows && data.rows.length<=0) && curPage>1){
setCurPage(curPage-1);
}
setTaskList(data.rows);
setTotal(data.total);
}
@ -68,7 +71,7 @@ export default ({ current_user, showNotification, history }) => {
}, [])
return (
<div className="centerbox task-manage">
<div className="task-manage">
<div className="center-screen" >
<div className="center-left-but">

View File

@ -4,7 +4,7 @@ import javaFetch from '../javaFetch';
let settings=localStorage.chromesetting&&JSON.parse(localStorage.chromesetting);
let actionUrl = settings && settings.api_urls? settings.api_urls.task :'https://task.osredm.com';
// let actionUrl = 'http://111.8.36.180:8094'
// let actionUrl = 'http://10.47.38.60:8088'
const service = javaFetch(actionUrl);
export const httpUrl = actionUrl;

View File

@ -1,15 +1,12 @@
// 本功能模块公样式
// 本功能模块公样式
.task-manage {
margin-top: 1.25rem;
.status-list {
margin: 0 1.5rem;
}
.center-screen {
display: flex;
justify-content: space-between;
margin: 1.25rem 0;
padding: 1rem 0;
padding: 1rem 1.5rem;
background-color: #fff;
.ant-form-item {
@ -88,6 +85,8 @@ span.list-gray {
}
.center-content .ant-pagination {
margin: 2rem 1.5rem;
text-align: right;
margin: 2rem auto !important;
text-align: center;
.ant-pagination-item:focus, .ant-pagination-item:hover, .ant-pagination-item-active, .ant-pagination-prev:hover a, .ant-pagination-next:hover a, .ant-pagination-options-quick-jumper input:focus, .ant-pagination-options-quick-jumper input:hover{
@ -123,6 +122,10 @@ span.list-gray {
opacity: 0.8;
}
}
.center-right-but, .center-left-but{
display: flex;
align-items: center;
}
.center-right-but .ant-input:hover, .center-content .ant-pagination-prev:hover{
border-color: #4154f1 !important;
}

View File

@ -19,7 +19,6 @@ for (const item of taskStatusAllArr) {
}
export default ({ location, history, current_user, showNotification }) => {
console.log(current_user);
let defaultValue = decodeURI(location.search.split("=")[1] || "");
const [identity, setIdentity] = useState('1');

View File

@ -43,6 +43,9 @@ export default Form.create()(({ form, showNotification, history}) => {
setLoading(true);
complainPaperList(params).then(data => {
if (data) {
if((data.rows && data.rows.length<=0) && curPage>1){
setCurPage(curPage-1);
}
setTaskList(data.rows);
setTotal(data.total);
}
@ -139,19 +142,21 @@ export default Form.create()(({ form, showNotification, history}) => {
{
title: '审核状态',
dataIndex: 'status',
key: 'status',
render: (text, record) => {
return text !== 2 ? paperComplainStatus[text] : <React.Fragment>
<Button className="mr5 font-12" type="primary" size="small" onClick={() => { checkPaperItem(record.id, 1) }}>通过</Button>
<Button className="mr5 font-12" type="info" size="small" onClick={() => { setActiveId(record.id); setVisible(true) }}>不通过</Button>
<Button className="mr5 font-12" type="info" size="small" onClick={() => { setActiveId(record.id); setFieldsValue({message: ''}); setVisible(true) }}>不通过</Button>
</React.Fragment>
}
},
{
title: '操作',
dataIndex: 'status',
key: 'action',
render: (text, record) => (
<Link className="line_1 color-grey3" to={`/task/taskDetail/${record.taskId}`}>查看详情</Link>
),
render: (text, record) => {
return text === 0 ? <span style={{color:'gray'}}>查看详情</span> : <Link className="line_1 color-grey3" to={`/task/taskDetail/${record.taskId}`}></Link>
},
},
]
}, []);
@ -187,7 +192,7 @@ export default Form.create()(({ form, showNotification, history}) => {
}, []);
return (
<div className="centerbox task-manage">
<div className="task-manage">
<div className="center-screen" >

View File

@ -20,7 +20,7 @@ export default Form.create()(({ current_user, form, showNotification, match, his
const [loading, setLoading] = useState(false);
const [searchObj, setSearchObj] = useState({
checkStatus: '0',
checkStatus: '2',
parentId: 0,
});
const [curPage, setCurPage] = useState(1);
@ -41,6 +41,9 @@ export default Form.create()(({ current_user, form, showNotification, match, his
setLoading(true);
readyCheckPapers(params).then(data => {
if (data) {
if((data.rows && data.rows.length<=0) && curPage>1){
setCurPage(curPage-1);
}
setTaskList(data.rows);
setTotal(data.total);
}
@ -81,6 +84,7 @@ export default Form.create()(({ current_user, form, showNotification, match, his
checkPaper({
paperId,
auditingVo: {
// pass1 2 0
pass: passStatus ? 1 : values.pass,
message: values.message,
}
@ -141,7 +145,7 @@ export default Form.create()(({ current_user, form, showNotification, match, his
title: '审核状态',
dataIndex: 'checkStatus',
render: (text, record) => {
return text === 0 ? <React.Fragment>
return text === 2 ? <React.Fragment>
<Button className="mr5 font-12" type="primary" size="small" onClick={() => { checkPaperItem(record.id, true) }}>通过</Button>
<Button className="mr5 font-12" type="info" size="small" onClick={() => { disagree(record) }}>不通过</Button>
</React.Fragment> : checkStatusArr[text]
@ -189,7 +193,7 @@ export default Form.create()(({ current_user, form, showNotification, match, his
function changeStatus(e) {
setSearchObj({
...searchObj,
checkStatus: e,
checkStatus: e === '0,1,2' ? '' : e,
});
setCurPage(1);
}
@ -203,11 +207,11 @@ export default Form.create()(({ current_user, form, showNotification, match, his
}
return (
<div className="centerbox task-manage">
<div className="task-manage">
<div className="center-screen" >
<div className="center-left-but">
{helper(
"",
"审核状态",
"checkStatus",
[],
<Select
@ -222,11 +226,11 @@ export default Form.create()(({ current_user, form, showNotification, match, his
})
}
</Select>,
'0'
'2'
)}
{helper(
"",
"审核类型",
"parentId",
[],
<Select

View File

@ -25,12 +25,15 @@ export default Form.create()(({ current_user, form, showNotification, match, his
...searchObj,
status:approve,
type:'',
currentPage:curPage,
curPage,
pageSize: 10,
};
setLoading(true);
uploadPayProofList(params).then(data => {
if (data) {
if((data.rows && data.rows.length<=0) && curPage>1){
setCurPage(curPage-1);
}
setTaskList(data.rows);
setTotal(data.total);
}
@ -75,7 +78,7 @@ export default Form.create()(({ current_user, form, showNotification, match, his
}, [])
return (
<div className="centerbox task-manage">
<div className="task-manage">
<div className="center-screen" >

View File

@ -31,6 +31,9 @@ export default Form.create()(({ current_user, form, showNotification, match, his
setLoading(true);
proofList(params).then(data => {
if (data) {
if((data.rows && data.rows.length<=0) && curPage>1){
setCurPage(curPage-1);
}
setTaskList(data.rows);
setTotal(data.total);
}

View File

@ -30,6 +30,9 @@ export default Form.create()(({ current_user, form, showNotification, match, his
setLoading(true);
publicityComplainList(params).then(data => {
if (data) {
if((data.rows && data.rows.length<=0) && curPage>1){
setCurPage(curPage-1);
}
setTaskList(data.rows);
setTotal(data.total);
}
@ -82,7 +85,7 @@ export default Form.create()(({ current_user, form, showNotification, match, his
}, [])
return (
<div className="centerbox task-manage">
<div className="task-manage">
<div className="center-screen" >
<div className="center-left-but">

View File

@ -106,9 +106,9 @@ export const applyStatusAllArr = [
];
export const paperCheckStatusArr = [
{ dicItemCode: "0", name: "待审核", dicItemName: "待审核" },
{ dicItemCode: "2", name: "待审核", dicItemName: "待审核" },
{ dicItemCode: "1", name: "通过", dicItemName: "通过" },
{ dicItemCode: "2", name: "未通过", dicItemName: "未通过" },
{ dicItemCode: "0", name: "未通过", dicItemName: "未通过" },
];
export const paperCheckTextArr = [

View File

@ -1,14 +1,14 @@
import React, { useCallback, useEffect, useState, useMemo } from 'react';
import classNames from 'classnames';
import { Input, Select, Button, Form, DatePicker, Table, Pagination, Modal, message } from 'antd';
import { Input, Select, Button, Form, DatePicker, Modal, message, Popover } from 'antd';
import { Link } from 'react-router-dom';
import { paperCheckStatusArr, publishModeArr, taskStatusAllArr, showUserModeArr, main_web_site_url, expertReviewArr } from '../static';
import { paperCheckStatusArr, publishModeArr, taskStatusAllArr, showUserModeArr, main_web_site_url } from '../static';
import { getTaskAdminList, changeShowUserMode, deleteTask, recommendTask, addExpertReview, publishExpertsAndRules } from '../api';
import '../index.scss';
import './index.scss';
import { getRules, selectExpertList } from 'src/military/expert/api';
import PaginationTable from '../../../../src/military/components/paginationTable';
import PaginationTable from '../../../components/pagination-table';
const format = "YYYY-MM-DD HH:mm:ss";
const Option = Select.Option;
@ -21,7 +21,7 @@ for (const item of paperCheckStatusArr) {
checkStatusArr[item.dicItemCode] = item.dicItemName;
}
//
export default Form.create()(({ form, showNotification, match, history, state }) => {
const { getFieldDecorator, setFieldsValue, getFieldsValue } = form;
const { hash} = history && history.location;
@ -48,6 +48,8 @@ export default Form.create()(({ form, showNotification, match, history, state })
const [rules, setRules] = useState(undefined);
const [selectedExperts, setSelectedExperts] = useState(undefined);
const [publicTaskId, setPublicTaskId] = useState(undefined);
// id
const [reviewTaskId, setReviewTaskId] = useState(undefined);
useEffect(()=>{
setCurPage(hashDate(hash) || 1);
@ -69,6 +71,11 @@ export default Form.create()(({ form, showNotification, match, history, state })
setLoading(true);
getTaskAdminList(params).then(data => {
if (data) {
let taskIds = [];
for(const item of data.rows){
item.expertReview && (taskIds[taskIds.length] = item.id)
}
setReviewTaskId(taskIds.toString());
setTaskList(data.rows);
setTotal(data.total);
}
@ -102,116 +109,78 @@ export default Form.create()(({ form, showNotification, match, history, state })
startTime: '',
endTime: '',
nameInput: '',
enterpriseNameInput: ''
enterpriseNameInput: '',
taskMode: '0,1,2,3,4,5,6,7,8,9',
showUserMode: '0,1,2',
publishMode1: '0,1',
expertReviewStatus: '-1',
showStatus: '0',
isRecommend: 'all',
sortBy: 'createdAt'
});
setStatusString('0,1,2,3,4,5,6,7,8,9');
setShowUserMode('0,1,2');
setPublishMode('0,1');
setExpertReview('-1');
setIsDelete('0');
setRecommend('');
setOrder("createdAt");
setSearchObj({});
}
const columns = useMemo(() => {
return [
{
title: '任务编号',
dataIndex: 'number',
width: "26%"
},
{
title: '任务名称',
dataIndex: 'name',
width: "13%",
width: "10%",
render: (text, record) => (
<Link className="line_1 primary-link" target="_blank" to={`/task/taskDetail/${record.id}`} >{text}</Link>
<Popover content = {
<div className='taskPopover'>
<p><span>任务名称:</span>{text}</p>
<p className='mt5'><span>截稿时间:</span>{record.collectingEndTime && record.collectingEndTime.replaceAll('-','/').substring(0,16) || '--'}</p>
<p className='mt5'><span>稿件数:</span>{record.papersCount || '--'}</p>
</div>
}>
<Link className="line_1 primary-link" target="_blank" to={`/task/taskDetail/${record.id}`} >{text}</Link>
</Popover>
),
},
{
title: <Select
className="column-select"
showArrow
defaultValue={'-1'}
onChange={(value)=>{setExpertReview(value);setCurPage1(1);}}
>
<Option key={'-1'} >专家评审</Option>
<Option key={'1'} >已提交评审</Option>
<Option key={'0'} >未提交评审</Option>
</Select>,
dataIndex: 'expertReview',
title: '发布主体',
dataIndex: 'enterpriseName',
},
{
title: '发布时间',
dataIndex: 'publishedAt',
width: "8%",
render: (text, record) => {
return <Select
className="column-select"
showArrow
defaultValue={text?1:-1}
onChange={(key) => { changeExpertReviewStatus(key, record.id) }}
disabled={record.assignRuleAndExperts || !(record.status == 1 || record.status == 3)}
>
{
expertReviewArr.map(item => {
return <Option key={item.dicItemCode} value={item.dicItemCode}>{item.dicItemName}</Option>
})
}
</Select>
text = text && text.replaceAll('-','/').substring(0,16);
return text || '--'
}
},
{
title: <Select
className="column-select"
showArrow
defaultValue={'0,1'}
onChange={(value)=>{setPublishMode(value);setCurPage1(1);}}
>
<Option key={'0,1'} >发布方式</Option>
<Option key={'0'} >自主提交</Option>
<Option key={'1'} >统筹任务</Option>
</Select>,
title: '发布方式',
dataIndex: 'publishMode',
render: (text, record) => {
return publishModeArr[text]
return <span className={`publishMode mode${text}`}>{publishModeArr[text]}</span>
}
},
{
title: <Select
className="column-select"
showArrow
defaultValue={'0,1,2,3,4,5,6,7,8,9'}
onChange={(value)=>{setStatusString(value);setCurPage1(1);}}
>
<Option key={'0,1,2,3,4,5,6,7,8,9'} >任务状态</Option>
{
taskStatusAllArr.map(item => {
return <Option key={item.dicItemCode} >{item.dicItemName}</Option>
})
}
</Select>,
width: '6%',
title: '任务状态',
dataIndex: 'status',
render: (text, record) => {
return record.exceptClosedBoolean ? '已关闭' : statusArr[text]
}
},
{
title: '发布主体',
dataIndex: 'enterpriseName',
width: '9%',
},
{
title: '发布时间',
dataIndex: 'publishedAt',
width: '7%',
render: (text, record) => {
return text || '--'
}
},
{
// title: '',
title: <Select
className="column-select"
showArrow
placeholder="请选择审核状态"
defaultValue={'0,1,2'}
onChange={setShowUserMode}
>
<Option key={'0,1,2'}>应征者公示</Option>
{
showUserModeArr.map(item => {
return <Option key={item.dicItemCode}>{item.dicItemName}</Option>
})
}
</Select>,
title: '应征者公示',
dataIndex: 'showUserMode',
width:'8%',
render: (text, record) => {
return <Select
className="column-select"
@ -228,44 +197,21 @@ export default Form.create()(({ form, showNotification, match, history, state })
</Select>
}
},
{
title: '评审规则',
dataIndex: 'ruleEditedCount',
render: (text, record) => {
return record.assignRuleAndExperts ? <Button size='small' type="primary" onClick={()=>{viewRules(record)}}>查看</Button> : record.expertReview && (record.status === 1 || record.status === 3) ? <Link className="line_1 primary-link" to={`/managements/expert/task/review/rules/${1}/${record.id}/?status=${record.status}&name=${record.name}&createdAt=${record.createdAt}&collectingEndTime=${record.collectingEndTime}&choosingDays=${record.choosingDays}`}>编辑</Link> : <span className='gary_span'>编辑</span>
}
},
{
title: '专家选取',
dataIndex: 'expertSelectedCount',
render: (text, record) => {
return record.assignRuleAndExperts ? <Button size='small' type="primary" onClick={()=>{viewExperts(record)}}>查看</Button> : record.expertReview && (record.status === 1 || record.status === 3) ? <Link className="line_1 primary-link" to={`/managements/expert/task/review/select/${1}/${record.id}/?name=${record.name}`}>选择</Link> : <span className='gary_span'>选择</span>
}
},
{
title: '评审任务',
dataIndex: 'expertReview1',
render: (text, record) => {
return record.assignRuleAndExperts ? <span className='gary_span'>已发布</span> : record.expertReview && (record.status === 1 || record.status === 3) ? <Button size='small' type="primary" onClick={()=>{publishTaskReview(record)}}>发布</Button> : <span className='gary_span'>发布</span>
}
},
{
title: '评审结果',
dataIndex: 'expertReview2',
render: (text, record) => {
return record.assignRuleAndExperts ? <Link className="line_1 primary-link" to={`/managements/expert/task/review/results/${1}/${record.id}/#status=${record.status}&name=${record.name}&taskModeId=${record.taskModeId}`}>查看</Link>:<span className='gary_span'>查看</span>
}
},
{
title: '操作',
key: 'action',
width: '6%',
render: (text, record) => (
dataIndex: 'expertReview',
align: 'center',
render: (text, record) => {
const disabled = record.assignRuleAndExperts || !(record.status == 1 || record.status == 3);
return(
<React.Fragment>
{
isDelete == '0' ? <Button className="mr5 font-12" type="danger" size="small" onClick={() => { deleteItem(record.id, '1') }}>隐藏</Button>
: <Button className="mr5 font-12" type="primary" size="small" onClick={() => { deleteItem(record.id, '0') }}>恢复</Button>
<Button className="mr5 f20" onClick={() => { deleteItem(record.id,isDelete == '0' ? '1':'0') }}>{isDelete == '0' ? '隐藏任务':'恢复任务'}</Button>
<Button className="mr5 f89" onClick={() => { recommendItem(record.id, record.recommend ? '0' :'1') }}>{record.recommend ? '撤销推荐':'首页推荐'}</Button>
<Button className={`mr5 c2a3 ${text ? 'bor':'full'} ${disabled && 'disabled'}`} onClick={() => { changeExpertReviewStatus(text ? '-1':'1', record.id) }} disabled={disabled}>{text ? '取消专家评审':'加入专家评审'}</Button>
{/* {
isDelete == '0' ? <Button className="mr5 font-12" type="danger" size="small" onClick={() => { deleteItem(record.id, '1') }}>隐藏任务</Button>
: <Button className="mr5 font-12" type="primary" size="small" onClick={() => { deleteItem(record.id, '0') }}>恢复任务</Button>
}
{
@ -274,11 +220,10 @@ export default Form.create()(({ form, showNotification, match, history, state })
{
record.recommend && <Button className="mr5 font-12" type="danger" size="small" onClick={() => { recommendItem(record.id, '0') }}>撤销推荐</Button>
}
} */}
{/* <Link className="line_1 color-grey3" to={`/task/taskDetail/${record.taskId}`}>查看</Link> */}
</React.Fragment>
),
)},
},
]
}, [isDelete, curPage]);
@ -370,7 +315,6 @@ export default Form.create()(({ form, showNotification, match, history, state })
//lookRules,lookExperts,pulicReview
useEffect(()=>{
//
lookRules && rules && Modal.info({
className: 'publishReview',
@ -544,10 +488,13 @@ export default Form.create()(({ form, showNotification, match, history, state })
});
const ExpertDetail = (record)=>{
const unDisabled = record.expertReview && (record.status === 1 || record.status === 3);
return <div className="expert_detail_div">
<div> 任务编号{record.number} </div>
<div> 截稿时间{record.collectingEndTime || '--'} </div>
<div> 稿件数{record.papersCount || '--'} </div>
<div> 专家评审信息: </div>
<div> 评审规则 {record.assignRuleAndExperts ? <Button className='c2a3 bor' onClick={()=>{viewRules(record)}}>查看</Button> : unDisabled ? <Button className="c2a3 bor" href={`/managements/expert/task/review/rules/${1}/${record.id}/?status=${record.status}&name=${record.name}&createdAt=${record.createdAt}&collectingEndTime=${record.collectingEndTime}&choosingDays=${record.choosingDays}`}>编辑</Button> : <Button className='c2a3 disabled'>编辑</Button>}</div>
<div> 专家选取 {record.assignRuleAndExperts ? <Button className='c2a3 bor' onClick={()=>{viewExperts(record)}}>查看</Button> : unDisabled ? <Button className="c2a3 bor" href={`/managements/expert/task/review/select/${1}/${record.id}/?name=${record.name}`}>选择</Button> : <Button className='c2a3 disabled'>选择</Button>}</div>
<div> 评审任务 {record.assignRuleAndExperts ? <Button className='c2a3 disabled'>已发布</Button> : unDisabled ? <Button className='c2a3 full' onClick={()=>{publishTaskReview(record)}}>发布</Button> : <Button className='c2a3 disabled'>发布</Button>}</div>
<div> 评审结果 {record.assignRuleAndExperts ? <Button className="c2a3 bor" href={`/managements/expert/task/review/results/${1}/${record.id}/#status=${record.status}&name=${record.name}&taskModeId=${record.taskModeId}`}>查看</Button>:<Button className='c2a3 disabled'>查看</Button>}</div>
</div>
}
@ -556,28 +503,29 @@ export default Form.create()(({ form, showNotification, match, history, state })
}
return (
<div className="centerbox task-manage-all ">
<div className="search-screen" >
{helper(
"任务名称",
"nameInput",
[{ max: 20, message: '长度不能超过20个字符' }],
<Input
placeholder="输入任务名称进行检索"
/>
)}
<div className="task-manage-all ">
<div className='management-content-head'>
<p className='font-18'>创客任务列表</p>
<div className="search-task" >
{helper(
"任务名称",
"nameInput",
[{ max: 20, message: '长度不能超过20个字符' }],
<Input
placeholder="输入任务名称进行检索"
/>
)}
{helper(
"发布主体名称",
"enterpriseNameInput",
[{ max: 20, message: '长度不能超过20个字符' }],
<Input
placeholder="输入发布主体名称进行检索"
/>
)}
{helper(
"发布主体名称",
"enterpriseNameInput",
[{ max: 20, message: '长度不能超过20个字符' }],
<Input
placeholder="输入发布主体名称进行检索"
/>
)}
<div className="center-right-but">
<div className="center-right-but time">
{helper(
"发布时间:",
@ -600,83 +548,151 @@ export default Form.create()(({ form, showNotification, match, history, state })
placeholder="请选择结束时间"
/>
)}
</div>
<div className="button-div">
{/* <a href="/admin/tasks.xlsx" class="fr edu-default-btn edu-blueback-btn plr30">导出</a> */}
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
<Button className="mr10" onClick={clearSearch}>清除</Button>
<Button className="mr10" type="primary" onClick={downloadFile}>导出</Button>
</div>
{helper(
"任务状态",
"taskMode",
[],
<Select
className="column-select"
showArrow
onChange={(value)=>{setStatusString(value);setCurPage1(1);}}
>
<Option key={'0,1,2,3,4,5,6,7,8,9'} >全部</Option>
{
taskStatusAllArr.map(item => {
return <Option key={item.dicItemCode} >{item.dicItemName}</Option>
})
}
</Select>,
'0,1,2,3,4,5,6,7,8,9'
)}
{helper(
"应征者公示",
"showUserMode",
[],
<Select
className="column-select"
showArrow
placeholder="请选择审核状态"
onChange={(value)=>{setShowUserMode(value);setCurPage1(1);}}
>
<Option key={'0,1,2'}>全部</Option>
{
showUserModeArr.map(item => {
return <Option key={item.dicItemCode}>{item.dicItemName}</Option>
})
}
</Select>,
'0,1,2'
)}
{helper(
"发布方式",
"publishMode1",
[],
<Select
className="column-select"
showArrow
onChange={(value)=>{setPublishMode(value);setCurPage1(1);}}
>
<Option key={'0,1'} >全部</Option>
<Option key={'0'} >自主提交</Option>
<Option key={'1'} >统筹任务</Option>
</Select>,
'0,1'
)}
{helper(
"专家评审状态",
"expertReviewStatus",
[],
<Select
className="column-select"
showArrow
onChange={(value)=>{setExpertReview(value);setCurPage1(1);}}
>
<Option key={'-1'} >全部</Option>
<Option key={'1'} >已提交评审</Option>
<Option key={'0'} >未提交评审</Option>
</Select>,
'-1'
)}
{/* <div className='center-right-but search'> */}
{helper(
"显示状态",
"showStatus",
[],
<Select
className="column-select"
showArrow
onChange={changeShow}
>
<Option key={'0'} >正常显示</Option>
<Option key={'1'} >已隐藏</Option>
</Select>,
'0'
)}
{helper(
"是否推荐",
"isRecommend",
[],
<Select
className="column-select"
showArrow
onChange={changeRecommend}
>
<Option key={'all'} >不限</Option>
<Option key={'0'} >未推荐</Option>
<Option key={'1'} >已推荐</Option>
</Select>,
'all'
)}
{helper(
"排序",
"sortBy",
[],
<Select
className="column-select"
showArrow
onChange={changeSortName}
>
<Option key={'createdAt'} >创建时间</Option>
<Option key={'publishedAt'} >发布时间</Option>
</Select>,
'createdAt'
)}
<div className="button-div">
{/* <a href="/admin/tasks.xlsx" class="fr edu-default-btn edu-blueback-btn plr30">导出</a> */}
<Button className="mr10" type="primary" onClick={onSearch}>搜索</Button>
<Button className="mr10" onClick={clearSearch}>清除</Button>
<Button className="mr10" type="primary" onClick={downloadFile}>导出</Button>
</div>
<span className={classNames({ "sort-active": sort === 'Desc', 'sort-icon': true, 'mt5': true })} onClick={() => { changeSort('Desc') }}>
<i className="fa fa-long-arrow-down font-16 "></i>
</span>
<span className={classNames({ "sort-active": sort === 'Asc', 'sort-icon': true, 'mt5': true })} onClick={() => { changeSort('Asc') }}>
<i className="fa fa-long-arrow-up font-16 "></i>
</span>
{/* </div> */}
</div>
</div>
<div className="select-box">
<Form.Item className="inline-form" label="显示状态">
<Select
style={{ width: '200px' }}
showArrow
onChange={changeShow}
defaultValue='0'
>
<Option key={'0'} >正常显示默认</Option>
<Option key={'1'} >已隐藏</Option>
</Select>
</Form.Item>
<Form.Item className="inline-form" label="是否推荐">
<Select
style={{ width: '200px' }}
showArrow
onChange={changeRecommend}
defaultValue='all'
>
<Option key={'all'} >全部</Option>
<Option key={'0'} >未推荐</Option>
<Option key={'1'} >已推荐</Option>
</Select>
</Form.Item>
<Form.Item className="inline-form" label="排序">
<Select
style={{ width: '200px' }}
showArrow
onChange={changeSortName}
defaultValue='createdAt'
>
<Option key={'createdAt'} >创建时间</Option>
<Option key={'publishedAt'} >发布时间</Option>
</Select>
<span className={classNames({ "sort-active": sort === 'Desc', 'sort-icon': true, 'ml10': true })} onClick={() => { changeSort('Desc') }}>
<i className="fa fa-long-arrow-down font-16 "></i>
</span>
<span className={classNames({ "sort-active": sort === 'Asc', 'sort-icon': true })} onClick={() => { changeSort('Asc') }}>
<i className="fa fa-long-arrow-up font-16 "></i>
</span>
</Form.Item>
</div>
<div className="center-content">
<Table
<div className="center-content taskListCont">
<PaginationTable
loading={loading}
rowKey={(row) => row.id}
dataSource={taskList}
columns={columns}
pagination={false}
className="mt10"
total={total}
current={curPage}
setCurPage={(page)=>{setCurPage1(page)}}
className="expertReviewTable"
expandedRowRender={ExpertDetail}
expandedRowKeys={reviewTaskId}
/>
{total > 10 &&
<Pagination
onChange={(page) => { setCurPage1(page) }}
current={curPage}
total={total}
/>}
</div>
</div>
)
}

View File

@ -1,14 +1,34 @@
.search-screen {
.management-content-head{
background-color: #fff;
margin-top: 1rem;
padding: 1.5rem;
border-radius:4px;
box-shadow:0px 0px 10px rgba(88, 116, 255, 0.18);
>p{
color:#18191e;
padding-bottom: 10px;
border-bottom: 1px solid #e2e6f5;
}
}
.taskPopover{
p{
color:#20294a;
&:last-child{
margin-left: 14px;
}
span{
color:#596078;
margin-right: 5px;
}
}
}
.search-task {
display: flex;
flex-flow: row wrap;
justify-content: space-between;
margin: 1.25rem 0;
padding: 1.25rem;
background-color: #fff;
border-bottom: 1px solid #dedede;
justify-content: flex-start;
margin: 20px 0 0;
> .ant-row {
min-width: 41%;
min-width: 20%;
margin-right: 2rem;
.ant-form-item-label {
float: left;
@ -19,34 +39,75 @@
}
.center-right-but {
display: flex;
.ant-form-item {
margin: 0 1rem 0 0;
}
.ant-form-item-control-wrapper {
display: inline-block;
}
&.search .ant-form-item{
margin: 0 5rem 0 0;
}
&.time{
margin: 0 2rem 24px 0;
}
}
.button-div {
margin-right: 1.5rem;
.ant-row .ant-form-item-label{
margin-right: 20px;
label::after{
content: none;
}
}
}
.task-manage-all {
.column-select {
min-width: 100px;
.ant-select-selection {
background: #fafafa;
border: 0;
}
width: 100%;
}
.ant-table-thead > tr > th,
.ant-table-tbody > tr > td {
padding: 1rem 0.1rem;
text-align: center;
padding: 1rem 1rem;
text-align: left;
&, & div{
color:#20294a;
}
.ant-btn{
padding: 0 9px;
}
.f20{
border-color:#f20000;
span{
color:#f20000;
}
}
.f89{
border-color:#f89d00;
span{
color:#f89d00;
}
}
.c2a3{
border-color:#2a3ee9;
&.bor{
background-color: #fff;
span{color:#2a3ee9;}
}
&.full{
background-color:#2a3ee9;
span{color: white;}
}
&.disabled{
background-color:#f2f2f2;
border: none;
span{color:#a6adc4;}
}
}
}
a.primary-link {
color: #1890ff;
color: #20294a;
}
.select-box{
@ -60,12 +121,16 @@
}
.expert_detail_div{
display: flex;
justify-content: space-around;
align-items: center;
div{
margin-right: 48px;
.ant-btn{
margin-left: 10px;
width: 66px;
border-radius: 4px;
}
}
}
// .ant-table-row-collapsed::after, .ant-table-row-expanded::after {
// content: url('./image/down.svg');
// }
}
.inline-form {
@ -138,3 +203,31 @@
padding: 3px 8px;
}
}
.taskListCont{
.publishMode{
position: relative;
&:before{
content: ' ';
position: absolute;
top: 8px;
left: -12px;
width: 6px;
height: 6px;
border-radius: 50%;
}
}
.mode0:before{
background-color: #2a3ee9;
}
.mode1:before{
background-color: #00dc51;
}
table tr td:first-child, table tr th:first-child{
display: none;
}
tr.ant-table-expanded-row, tr.ant-table-expanded-row:hover{
background-color:#fbfbff;
// td{padding: 0.5rem 1rem;}
}
tr.ant-table-expanded-row td{padding: 0.5rem 1rem;}
}

View File

@ -47,6 +47,9 @@ export default Form.create()(({ form, showNotification, match, history }) => {
setLoading(true);
getTaskAdminList(params).then(data => {
if (data) {
if((data.rows && data.rows.length<=0) && curPage>1){
setCurPage(curPage-1);
}
setTaskList(data.rows);
setTotal(data.total);
}
@ -100,7 +103,7 @@ export default Form.create()(({ form, showNotification, match, history }) => {
}, [])
return (
<div className="centerbox task-manage">
<div className="task-manage">
<div className="center-screen" >
<div className="center-left-but">
<Button className="circle-button" type={approve === 1 ? 'primary' : ''} onClick={() => { changeApprove(1) }}>待审批</Button>

View File

@ -54,14 +54,10 @@ class NewHeader extends Component {
settings: null,
goshowqqgtounp: false,
visiblemyss: false,
isExpert: false,
visible:false, //浮动消息框展示控制
}
}
componentDidMount() {
getUserInfo().then(response =>{
response && this.setState({isExpert: response.data && response.data.expert});
});
// this.getAppdata();
this.geturlsdata();
window._header_componentHandler = this;
@ -638,7 +634,7 @@ class NewHeader extends Component {
goshowqqgtounp,
visible,
} = this.state;
let activeIndex =match.path === '/'?true: '';
let activeIndex =match.path === '/' || (match.path&&match.path.startsWith('/managements')) || (match.path&&match.path.startsWith('/admin'))?true: '';
let headtypes = '/';
if (settings) {
if (settings.navbar) {

View File

@ -19,7 +19,7 @@ body>.-task-title {
min-width: 1200px;
max-width: unset;
height: 100%;
min-height: 70vh;
min-height: calc(100vh - 177px);
overflow: hidden;
}
.newHeaders{

View File

@ -3,7 +3,7 @@ import Header from '../../forge/Head/Header';
import NewHeader from './NewHeader';
import NewFooter from './NewFooter';
import { downloadFile } from 'educoder';
import { getCurrentExpert } from 'src/military/expert/api';
import { getCurrentExpert, getUserInfo } from 'src/military/expert/api';
import axios from 'axios';
import { Spin } from 'antd';
import './TPMIndex.css';
@ -28,13 +28,14 @@ export function TPMIndexHOC(WrappedComponent, headFoot) {
dataquerys: {},
isloginCancel: undefined,
mygetHelmetapi: null,
giteaVisible:false,
email:undefined,
completeProfile:false,
showCP:false,
showNotice:true,
giteaVisible: false,
email: undefined,
completeProfile: false,
showCP: false,
showNotice: true,
gopage: undefined,
Footerdown: undefined,
menuList:[],
}
}
@ -158,11 +159,11 @@ export function TPMIndexHOC(WrappedComponent, headFoot) {
fetchUsers = () => {
if (this.props.match.path === "/") {
this.setState({
publicNav:true
publicNav: true
})
}else{
} else {
this.setState({
publicNav:false
publicNav: false
})
}
let url = `/users/get_user_info.json`;
@ -171,21 +172,21 @@ export function TPMIndexHOC(WrappedComponent, headFoot) {
this.initCommonState(response.data)
this.setState({
tpmLoading: false,
completeProfile:response.data.profile_completed
completeProfile: response.data.profile_completed
})
if(response.data && response.data.login){
if(response.data.need_edit_info){
if (response.data && response.data.login) {
if (response.data.need_edit_info) {
this.setState({
giteaVisible:true,
email:response.data.email
giteaVisible: true,
email: response.data.email
})
}
}
if(response.data && response.data.login){
if(response.data.need_edit_info){
if (response.data && response.data.login) {
if (response.data.need_edit_info) {
this.setState({
giteaVisible:true,
email:response.data.email
giteaVisible: true,
email: response.data.email
})
}
}
@ -195,7 +196,7 @@ export function TPMIndexHOC(WrappedComponent, headFoot) {
// 考虑到以后部分系统不会用到专家评审系统所以这里没有使用Promise.All
getCurrentExpert().then(res => {
if(res){
if (res) {
let isExpert = false;
let expertId = '';
let expertDraft = false;
@ -218,6 +219,18 @@ export function TPMIndexHOC(WrappedComponent, headFoot) {
}).catch((error) => {
console.log(error)
});
getUserInfo().then(response => {
// response && this.setState({isExpert: response.data && response.data.expert});
if (response) {
// this.setState({ isExpert: response.data && response.data.expert });
// localStorage.setItem('menuList', JSON.stringify(response.data.menuNodes));
this.setState({menuList:response.data.menuNodes})
}
}).catch((error) => {
console.log(error)
});
}
}).catch((error) => {
console.log(error)
@ -244,56 +257,56 @@ export function TPMIndexHOC(WrappedComponent, headFoot) {
return this.state.current_user && this.state.current_user.login != ''
}
onOk =(values)=>{
onOk = (values) => {
let url = `/users/sync_user_info.json`;
const { current_user } = this.state;
axios.post(url,{
login:current_user && current_user.login,
axios.post(url, {
login: current_user && current_user.login,
...values
}).then(result=>{
if(result && result.data && result.data.status === 0){
}).then(result => {
if (result && result.data && result.data.status === 0) {
this.setState({
giteaVisible:false,
email:undefined
giteaVisible: false,
email: undefined
})
window.location.reload();
}
}).catch(error=>{})
}).catch(error => { })
}
hideSystemNotice=()=>{
hideSystemNotice = () => {
this.setState({
showNotice:false
showNotice: false
})
}
showCompeleteDialog=()=>{
showCompeleteDialog = () => {
this.setState({
showCP:true
showCP: true
})
}
render() {
let { isRender , current_user , giteaVisible , email , completeProfile , showCP , showNotice , publicNav , mygetHelmetapi ,Footerdown} = this.state;
let { isRender, current_user, giteaVisible, email, completeProfile, showCP, showNotice, publicNav, mygetHelmetapi, Footerdown } = this.state;
const common = {
showLoginDialog: this.showLoginDialog,
checkIfLogin: this.checkIfLogin,
resetUserInfo:this.fetchUsers,
showCompeleteDialog:this.showCompeleteDialog
resetUserInfo: this.fetchUsers,
showCompeleteDialog: this.showCompeleteDialog
};
let competition = this.props.match.path.includes('/competition');
return (
<div className="indexHOC">
<SystemNotice
<SystemNotice
showNotice={showNotice}
system_notification={mygetHelmetapi && mygetHelmetapi.system_notification}
history={this.props.history}
system_notification={mygetHelmetapi && mygetHelmetapi.system_notification}
history={this.props.history}
login={current_user && current_user.login}
hideSystemNotice={this.hideSystemNotice}
/>
<EducoderAccount visible={giteaVisible} email={email} onOk={this.onOk}/>
<ProfileModal
visible={!completeProfile && showCP}
onCancel={()=>{this.setState({showCP:false})}}
<EducoderAccount visible={giteaVisible} email={email} onOk={this.onOk} />
<ProfileModal
visible={!completeProfile && showCP}
onCancel={() => { this.setState({ showCP: false }) }}
history={this.props.history}
/>
{isRender === true ? <LoginDialog

View File

@ -14,3 +14,47 @@
.login-box{
font-size: 15px;
}
/* 新版首页头部样式 */
.homePage.newHeaders {
background-color: #0037af;
z-index: 1000;
}
.homePage .newFooter{
background: inherit;
}
.homePage .head-nav {
min-width: auto;
}
.homePage .head-nav ul#header-nav li a {
font-size: 1em;
color: #fff;
}
.homePage .head-nav ul#header-nav li:hover a,
.homePage .head-nav ul#header-nav li.active a {
color: #ffa13a;
}
.homePage .head-nav ul#header-nav li.active a::after {
background-color: #ffa13a;
}
.homePage .logoDiv img {
min-width: 2.8125em;
height: 2.8125em;
}
.homePage .color-home {
color: #fff;
}
.homePage .color-home:hover {
color: #4154f1;
}
.homePage .register-button {
height: 3em;
margin-left: 1.25em;
padding: 0 1.5625em;
font-size: 0.875em;
}
/* 新版首页头部样式 */