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

This commit is contained in:
何童崇 2022-01-13 11:34:49 +08:00
commit b730c6de53
12 changed files with 109 additions and 85 deletions

View File

@ -53,21 +53,21 @@ const AdminPage = (propsF) => {
></Route>
{/* 创客任务评审规则 */}
<Route
path="/expert/admin/task/review/rules"
path="/expert/admin/task/review/rules/:taskId"
render={(props) => (
<ReviewRules {...propsF} {...props} />
)}
></Route>
{/* 创客任务选择评审专家 */}
<Route
path="/expert/admin/task/review/select"
path="/expert/admin/task/review/select/:taskId"
render={(props) => (
<SelectExpert {...propsF} {...props} />
)}
></Route>
{/* 创客任务评审结果查看 */}
<Route
path="/expert/admin/task/review/results"
path="/expert/admin/task/review/results/:taskId"
render={(props) => (
<ReviewResult {...propsF} {...props} />
)}

View File

@ -1,4 +1,4 @@
import React, { useState, forwardRef } from "react";
import React, { useState, forwardRef, useEffect } from "react";
import { Input } from 'antd';
const { TextArea } = Input;
@ -6,6 +6,12 @@ const { TextArea } = Input;
//
const WordsInput = forwardRef((props, _ref) => {
const [wordCount, setWordCount] = useState(0);
const {value} = props;
//
useEffect(()=>{
setWordCount(value && value.length || 0);
},[props])
return(
<div style={{position:'relative'}}>
<TextArea {...props} onChange={(e)=>{setWordCount(e.target.value.length);props.onChange(e.target.value)}}/>

View File

@ -144,18 +144,9 @@ function ReviewTasks({ showNotification, match, history, current_user }) {
}
useEffect(() => {
let rules = undefined;
getRules({ containerId, containerType, statusString: -1 }).then(response => {
if (response && response.message === "success") {
let criterias = [];
response.data.criteriaOne && (criterias[criterias.length] = (criterias.length + 1) + "、" + response.data.criteriaOne);
response.data.criteriaTwo && (criterias[criterias.length] = (criterias.length + 1) + "、" + response.data.criteriaTwo);
response.data.criteriaThree && (criterias[criterias.length] = (criterias.length + 1) + "、" + response.data.criteriaThree);
response.data.criteriaFour && (criterias[criterias.length] = (criterias.length + 1) + "、" + response.data.criteriaFour);
response.data.criteriaFive && (criterias[criterias.length] = (criterias.length + 1) + "、" + response.data.criteriaFive);
response.data.criterias = criterias;
rules = response.data;
setRules(rules);
setRules(response.data);
}
});
}, [])
@ -222,8 +213,11 @@ function ReviewTasks({ showNotification, match, history, current_user }) {
typeof item.gradesFour === 'number' && gradesArr.push(item.gradesFour);
typeof item.gradesFive === 'number' && gradesArr.push(item.gradesFive);
if (gradesArr.length === gradesNum) {
let sum = gradesArr.reduce((previousValue, currentValue) => { return previousValue + currentValue }, 0);
dataListNew[index].gradesAverage = (sum / gradesNum).toFixed(2);
const sum = gradesArr.reduce((previousValue, currentValue) => { return previousValue + currentValue }, 0);
const ave = (sum / gradesNum).toFixed(2);
dataListNew[index].gradesAverage = ave > 100 ? 100: ave;
}else{
dataListNew[index].gradesAverage = '';
}
}

View File

@ -1,13 +1,12 @@
import React, { useState, useCallback, useMemo, useEffect } from "react";
import { Button, Modal } from 'antd';
import React, { useState, useEffect } from "react";
import { Modal } from 'antd';
import Paginationtable from "../../../components/paginationTable";
import { getOpsScoringDetails } from "../../api";
import { httpUrl } from '../../fetch';
import { getOpsScoringDetails, getRules } from "../../api";
import './index.scss';
import '../../index.scss';
function GradesModal({ setVisible, visible, opsId, opsType }) {
function GradesModal({ setVisible, visible, opsId, opsType, taskId }) {
// table
const [loading, setLoading] = useState(false);
const [dataList, setDataList] = useState([]);
@ -88,7 +87,7 @@ function GradesModal({ setVisible, visible, opsId, opsType }) {
}
}];
let gradesNum = rules.criterias && rules.criterias.length || 5;
let gradesNum = rules && rules.criterias && rules.criterias.length || 5;
if (gradesNum) {
let thisGradesColumns = gradesColumns.slice(0, gradesNum);
@ -103,6 +102,17 @@ function GradesModal({ setVisible, visible, opsId, opsType }) {
opsType,
orderBy: '',
};
//
const paramsRule = {
containerId: taskId,
containerType: 1,
statusString: '-1,1',
};
taskId && getRules(paramsRule).then(response=>{
if(response && response.message === "success"){
setRules(response.data);
}
});
opsId && getOpsScoringDetails(params).then(res => {
if (res.data && res.data.length) {
setDataList(res.data);

View File

@ -7,9 +7,11 @@ import { Checkbox, Input, message, Modal } from "antd";
import sucess from './image/sucess.svg';
import './index.scss';
import '../index.scss';
import { queryString } from "educoder";
function ReviewResult({ location, history }) {
const { taskRecord } = location && location.state;
function ReviewResult({ history, match }) {
const {taskId} = match.params;
const {status, name, taskModeId} = queryString.parse(window.location.search.slice(1));
const [dataList, setDateList] = useState(undefined);
const [openResultVisible, setOpenResultVisible] = useState(false);
const [winIds, setWinIds] = useState(undefined);
@ -49,7 +51,7 @@ function ReviewResult({ location, history }) {
ket: 'isWin',
align: 'center',
render: (text, record) => {
return taskRecord.status === 4 ? <Checkbox onChange={(e)=>{changeIsWin(record.applicantInfo.id, e.target.checked)}}>胜出</Checkbox> : record.isWin ? <div className="sucess df"><img src={sucess}/>胜出</div>:'未胜出';
return status == 4 ? <Checkbox onChange={(e)=>{changeIsWin(record.applicantInfo.id, e.target.checked)}}>胜出</Checkbox> : record.isWin ? <div className="sucess df"><img src={sucess}/>胜出</div>:'未胜出';
}
}
];
@ -57,7 +59,7 @@ function ReviewResult({ location, history }) {
useEffect(()=>{
//
const params = {
containerId: taskRecord.id,
containerId: taskId,
containerType: 1,
isDistinct: true,
expertId: -1,
@ -65,10 +67,11 @@ function ReviewResult({ location, history }) {
}
getScoringDetails(params).then(response=>{
if(response && Array.isArray(response.data)){
//finalGrades null 0
let index = 1;
response.data.map(item=>{item.id = index++;setResult(item.finalGrades) })
taskRecord && taskRecord.status >4 ? getWinnersAndPublicists({
containerId: taskRecord.id,
status >4 ? getWinnersAndPublicists({
containerId: taskId,
containerType: 1
}).then(res=>{
if(res && res.message === "success"){
@ -87,7 +90,6 @@ function ReviewResult({ location, history }) {
setOpsId(item.opsId);
setOpsType(item.opsType);
setVisible(true);
console.log(item);
}
function changeIsWin(id, checked){
@ -97,12 +99,12 @@ function ReviewResult({ location, history }) {
}
function openResult(){
if(!result){
if(result === null){
message.error("还没有到评审结束时间,不能公示结果! ");
return;
}
if(winIds && winIds.length>0){
taskRecord.taskModeId == 1 && winIds.length >1 ? message.error("此任务是单人悬赏模式, 只能设置一个中标者 ! ") : setOpenResultVisible(true);
taskModeId == 1 && winIds.length >1 ? message.error("此任务是单人悬赏模式, 只能设置一个中标者 ! ") : setOpenResultVisible(true);
}
}
@ -120,7 +122,7 @@ function ReviewResult({ location, history }) {
const ids = [];
ids[ids.length] = dataList.filter(item=>item.id<=openRange).map(i=>i.applicantInfo.id);
let params = {
containerId : taskRecord.id,
containerId : taskId,
containerType: 1,
id: 0,
publicityUserIds : dataList.filter(item=>item.id<=openRange).map(i=>i.applicantInfo.id).toString(),
@ -141,10 +143,10 @@ function ReviewResult({ location, history }) {
<span className="font-16 font-w">评审结果</span>
<button className="but41_border goback_but" onClick={()=>{history.goBack()}}>返回上一页</button>
</div>
<p className="mt10"><span className="font-w">任务名称</span><span className="ml10">{taskRecord.name}</span></p>
<p className="mt10 pb20"><span className="font-w">任务链接</span><Link className="taskLink ml10" target="_blank" to={`/task/taskDetail/${taskRecord.id}`} >{`${window.location.host}/task/taskDetail/${taskRecord.id}`}</Link></p>
<p className="mt10"><span className="font-w">任务名称</span><span className="ml10">{decodeURI(name)}</span></p>
<p className="mt10 pb20"><span className="font-w">任务链接</span><Link className="taskLink ml10" target="_blank" to={`/task/taskDetail/${taskId}`} >{`${window.location.host}/task/taskDetail/${taskId}`}</Link></p>
</div>
{taskRecord.status > 3 ? <React.Fragment>
{status > 3 ? <React.Fragment>
<p className="font-16 font-w mb10">应征者排名</p>
<PaginationTable
dataSource= {dataList}
@ -152,9 +154,9 @@ function ReviewResult({ location, history }) {
scroll={{ y: 400 }}
/>
<div className="openResult">
{taskRecord.status === 4 && <button className={(winIds && taskRecord.taskModeId == 1 && winIds.length >1) || !result ? 'disableBut': 'but41_fill'} onClick={openResult}>公示结果</button>}
{status == 4 && <button className={(winIds && taskModeId == 1 && winIds.length >1) || result === null ? 'disableBut': 'but41_fill'} onClick={openResult}>公示结果</button>}
</div>
</React.Fragment>:<div className="nodata font-w font-22">暂无数据此任务暂未进入成果评选阶段</div>}
</React.Fragment>:<div className="nodata font-20">暂无数据此任务暂未进入成果评选阶段</div>}
<Modal
title= "请确认公示范围"
visible= {openResultVisible}
@ -175,6 +177,7 @@ function ReviewResult({ location, history }) {
setVisible={setVisible}
opsId={opsId}
opsType={opsType}
taskId={taskId}
/>
</div>
)

View File

@ -32,8 +32,8 @@
font-weight: bold;
}
.nodata{
height: 350px;
line-height: 350px;
height: 300px;
line-height: 300px;
text-align: center;
}
.sucess{

View File

@ -1,39 +1,42 @@
import React, { useEffect, useState } from "react";
import { DatePicker, Form, message,Input } from "antd";
import { DatePicker, Form, message } from "antd";
import WordsInput from "../components/wordsInput";
import './index.scss';
import '../index.scss';
import Link from "react-router-dom/Link";
import { editRules, getRules, updateRules } from "../api";
import moment from "moment";
import { queryString } from "educoder";
const {RangePicker} = DatePicker;
function ReviewRules({ location, form, history }) {
function ReviewRules({form, history, match}) {
const id = match.params.taskId;
const {name, status, createdAt, collectingEndTime, collectingDays} = queryString.parse(window.location.search.slice(1));
const { getFieldDecorator,setFieldsValue } = form;
const { taskRecord } = location && location.state;
//
const [ initValue, setInitValue] = useState(false);
const disabledDate = (current) =>{
if(taskRecord.status === 1){
return current && current < moment(taskRecord.createdAt).endOf('day');
}else if(taskRecord.status === 3){
const endDate = new Date((new Date(taskRecord.collectingEndTime)/1000 + 86400*taskRecord.collectingDays)*1000);
return current && current < moment(taskRecord.collectingEndTime).endOf('day') || current > moment(endDate).endOf('day');
if(status == 1){
return current && current < moment(createdAt.replace("%20", " ")).endOf('day');
}else if(status == 3){
const endDate = new Date((new Date(collectingEndTime.replace("%20", " "))/1000 + 86400*collectingDays)*1000);
return current && current < moment(collectingEndTime.replace("%20", " ")).endOf('day') || current > moment(endDate).endOf('day');
}
}
useEffect(()=>{
//
const params = {
containerId: taskRecord.id,
containerId: id,
containerType: 1,
statusString: 3,
};
getRules(params).then(response=>{
if(response && response.message === "success"){
setFieldsValue(response.data);
const { criteriaFive, criteriaFour, criteriaOne, criteriaThree, criteriaTwo, rule } = response.data;
const data = { criteriaFive, criteriaFour, criteriaOne, criteriaThree, criteriaTwo, rule }
setFieldsValue(data);
setInitValue(response.data);
}
})
@ -43,8 +46,8 @@ function ReviewRules({ location, form, history }) {
form.validateFields((err, values) => {
if (!err) {
let data = {
containerId: taskRecord.id,
containerName: taskRecord.name,
containerId: id,
containerName: decodeURI(name),
containerType: 1,
criteriaOne: values.criteriaOne,
reviewStartOn: values.reviewDate[0].format('YYYY-MM-DD HH:mm:ss'),
@ -88,8 +91,8 @@ function ReviewRules({ location, form, history }) {
<span className="font-16 font-w color-grey3">任务信息</span>
<button className="but41_border goback_but" onClick={()=>{history.goBack()}}>返回上一页</button>
</div>
<p className="mt10"><span className="font-w color-grey3">任务名称</span><span className="ml10 color-grey3">{taskRecord.name}</span></p>
<p className="mt10 pb20"><span className="font-w color-grey3">任务链接</span><Link className="taskLink ml10" target="_blank" to={`/task/taskDetail/${taskRecord.id}`} >{`${window.location.host}/task/taskDetail/${taskRecord.id}`}</Link></p>
<p className="mt10"><span className="font-w color-grey3">任务名称</span><span className="ml10 color-grey3">{decodeURI(name)}</span></p>
<p className="mt10 pb20"><span className="font-w color-grey3">任务链接</span><Link className="taskLink ml10" target="_blank" to={`/task/taskDetail/${id}`} >{`${window.location.host}/task/taskDetail/${id}`}</Link></p>
</div>
<Form className="pt10">
<Form.Item

View File

@ -33,9 +33,9 @@
}
.ant-input{
background-color: white !important;
}
.has-success .ant-input, .ant-input:hover{
border: 1px solid #5d6eff !important;
&:hover{
border: 1px solid #5d6eff !important;
}
}
}
.rules_buttom{

View File

@ -6,15 +6,17 @@ import Paginationtable from "../../components/paginationTable";
import './index.scss';
import '../index.scss';
import { Link } from "react-router-dom";
import { queryString } from "educoder";
const { TabPane } = Tabs;
const { Option } = Select;
const { Search } = Input;
function SelectExpert(props) {
const { history, form, location, current_user } = props;
const { history, form, current_user, match } = props;
const { taskId} = match.params;
const { name} = queryString.parse(window.location.search.slice(1));
const { getFieldDecorator, setFieldsValue } = form;
const { taskRecord } = location && location.state;
const [reload, setReload] = useState();
const [loading, setLoading] = useState(false);
const [curPage, setCurPage] = useState(1);
@ -133,11 +135,20 @@ function SelectExpert(props) {
</div>
}
const TaskMess = ()=>{
return <div>
<div className="box"></div>
<p className="font-16 pt15 font-w color-grey3">任务信息</p>
<p className="mt10"><span className="font-w color-grey3">任务名称</span><span className="ml10 color-grey3">{decodeURI(name)}</span></p>
<p className="mt10 pb20"><span className="font-w color-grey3">任务链接</span><Link className="taskLink ml10" target="_blank" to={`/task/taskDetail/${taskId}`} >{`${window.location.host}/task/taskDetail/${taskId}`}</Link></p>
</div>
}
//
useEffect(()=>{
setLoading(true);
const params = {
containerId: taskRecord.id,
containerId: taskId,
containerType: 1,
curPage:curPage,
pageSize: 10000,
@ -186,7 +197,7 @@ function SelectExpert(props) {
useEffect(()=>{
setLoading(true);
const params = {
containerId: taskRecord.id,
containerId: taskId,
containerType: 1,
curPage,
pageSize,
@ -242,8 +253,8 @@ function SelectExpert(props) {
const SelectExperts = (id) =>{
const params = {
assignorId: parseInt(current_user.user_id),
containerId: taskRecord.id,
containerName: taskRecord.name,
containerId: taskId,
containerName: decodeURI(name),
containerType: 1,
expertIds: id.toString(),
status: 3
@ -282,15 +293,10 @@ function SelectExpert(props) {
<button className="but41_border goback_but mr25" onClick={()=>{history.goBack()}}>返回上一页</button>
</div>
<Tabs defaultActiveKey="0" type="card" onChange={(activeKey)=>{setActiveKey(activeKey);setSelectedRowKeys([]);setCurPage(1);}}>
<div>
<div className="box"></div>
<p className="font-16 pt15 font-w color-grey3">任务信息</p>
<p className="mt10"><span className="font-w color-grey3">任务名称</span><span className="ml10 color-grey3">{taskRecord.name}</span></p>
<p className="mt10 pb20"><span className="font-w color-grey3">任务链接</span><Link className="taskLink ml10" target="_blank" to={`/task/taskDetail/${taskRecord.id}`} >{`${window.location.host}/task/taskDetail/${taskRecord.id}`}</Link></p>
</div>
<TabPane tab="已选专家" key="0">
<TaskMess/>
<div className="df mb20">
<p className="font-16 font-w color-grey3">已选取评审专家</p>
<p className="font-16 font-w color-grey3 select_title">已选取评审专家</p>
<div>
{/* <button className="but41_fill" onClick={() => {selectedRowKeys && selectedRowKeys.length>0 && setOkConfirmDelete(true)}}>批量删除</button> */}
<Modal
@ -319,8 +325,9 @@ function SelectExpert(props) {
/>
</TabPane>
<TabPane tab="专家选取" key="1">
<TaskMess/>
<div className="df mb20">
<p className="font-16 font-w color-grey3">添加评审专家</p>
<p className="font-16 font-w color-grey3 select_title">添加评审专家</p>
<div>
<button className="but41_fill" onClick={() => {selectedRowKeys && selectedRowKeys.length>0 && setOkConfirmExps(true)}}>批量添加</button>
{allSelectedExpertsId && allSelectedExpertsId.size === total ? <button className="invalid_extraction butE3_border ml20">随机抽取</button> : <button className="but41_fill ml20" onClick={() => setOkConfirmExtract(true)}>随机抽取</button>}

View File

@ -77,12 +77,12 @@
.invalid_extraction{
background: #F8F8F8;
}
.ant-tabs-nav.ant-tabs-nav-animated>div div:first-child{
display: none;
}
.pagination-table .ant-table-thead > tr > th span, .ant-form label{
font-weight: bold;
}
.select_title{
height: 36px;
}
}
.expert_modal.extract{
.ant-modal-content {

View File

@ -85,7 +85,8 @@ export default Form.create()(({ form, showNotification, match, history, state })
if (values.endTime) values.endTime = values.endTime.format(format);
if (values.checkStatus === '0,1,2') values.checkStatus = '';
setSearchObj(values);
window.location.href=`/task/taskAdmin`;
setCurPage1(1);
// window.location.href=`/task/taskAdmin`;
}
function clearSearch() {
@ -113,7 +114,7 @@ export default Form.create()(({ form, showNotification, match, history, state })
className="column-select"
showArrow
defaultValue={'-1'}
onChange={setExpertReview}
onChange={(value)=>{setExpertReview(value);setCurPage1(1);}}
>
<Option key={'-1'} >专家评审</Option>
<Option key={'1'} >已提交评审</Option>
@ -141,7 +142,7 @@ export default Form.create()(({ form, showNotification, match, history, state })
className="column-select"
showArrow
defaultValue={'0,1'}
onChange={setPublishMode}
onChange={(value)=>{setPublishMode(value);setCurPage1(1);}}
>
<Option key={'0,1'} >发布方式</Option>
<Option key={'0'} >自主提交</Option>
@ -157,7 +158,7 @@ export default Form.create()(({ form, showNotification, match, history, state })
className="column-select"
showArrow
defaultValue={'0,1,2,3,4,5,6,7,8,9'}
onChange={setStatusString}
onChange={(value)=>{setStatusString(value);setCurPage1(1);}}
>
<Option key={'0,1,2,3,4,5,6,7,8,9'} >任务状态</Option>
{
@ -223,14 +224,14 @@ export default Form.create()(({ form, showNotification, match, history, state })
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={{ pathname:'/expert/admin/task/review/rules', state: { 'taskRecord': record}}}>编辑</Link> : <span className='gary_span'>编辑</span>
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={`/expert/admin/task/review/rules/${record.id}/?status=${record.status}&name=${record.name}&createdAt=${record.createdAt}&collectingEndTime=${record.collectingEndTime}&collectingDays=${record.collectingDays}`}>编辑</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={{ pathname: '/expert/admin/task/review/select', state: { 'taskRecord': record } }}>选择</Link> : <span className='gary_span'>编辑</span>
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={`/expert/admin/task/review/select/${record.id}/?name=${record.name}`}>选择</Link> : <span className='gary_span'>选择</span>
}
},
{
@ -244,7 +245,7 @@ export default Form.create()(({ form, showNotification, match, history, state })
title: '评审结果',
dataIndex: 'expertReview2',
render: (text, record) => {
return record.assignRuleAndExperts ? <Link className="line_1 primary-link" to={{ pathname: '/expert/admin/task/review/results', state: { 'taskRecord': record } }}>查看</Link>:<span className='gary_span'>查看</span>
return record.assignRuleAndExperts ? <Link className="line_1 primary-link" to={`/expert/admin/task/review/results/${record.id}/?status=${record.status}&name=${record.name}&taskModeId=${record.taskModeId}`}>查看</Link>:<span className='gary_span'>查看</span>
}
},
{
@ -391,7 +392,7 @@ export default Form.create()(({ form, showNotification, match, history, state })
<div>{rules && rules.rule}</div>
<p>评分标准</p>
<div>
{rules.criterias.map(item=>{return <p>{item}</p>})}
{rules.criterias.map(item=>{return <p key={Math.random()}>{item}</p>})}
</div>
<p>评审时间</p>
<div>{rules.reviewData}</div>
@ -433,7 +434,7 @@ export default Form.create()(({ form, showNotification, match, history, state })
<div>{rules && rules.rule}</div>
<p>评分标准</p>
<div>
{rules.criterias.map(item=>{return <p>{item}</p>})}
{rules.criterias.map(item=>{return <p key={Math.random()}>{item}</p>})}
</div>
<p>评审时间</p>
<div>{rules.reviewData}</div>
@ -464,7 +465,7 @@ export default Form.create()(({ form, showNotification, match, history, state })
<PaginationTable
dataSource={selectedExperts}
columns={columnsExperts}
scroll={{ y: 400 }}/>,
scroll={{ y: 395 }}/>,
});
}, 300);
}

View File

@ -118,6 +118,6 @@
}
}
.pagination-table .ant-table-tbody > tr > td{
padding: 1px 8px;
padding: 3px 8px;
}
}