forked from Gitlink/forgeplus-react
601 lines
22 KiB
JavaScript
601 lines
22 KiB
JavaScript
import React, { forwardRef, useCallback, useEffect, useState } from 'react';
|
||
import { Form, Radio, Input, InputNumber, Icon, Button, Modal, Checkbox } from 'antd';
|
||
import classNames from 'classnames';
|
||
import moment from 'moment';
|
||
import ReactWEditor from 'wangeditor-for-react';
|
||
import { Link } from "react-router-dom";
|
||
import Upload from '../../components/Upload';
|
||
import { httpUrl } from '../fetch';
|
||
import { getTaskDetail, addTask, updateTask, updatePublishedTask, getTaskCategory, getCompanyInfo } from '../api';
|
||
import { formItemLayout, formModalLayout } from '../static';
|
||
import { editorConfig } from '../../components/config';
|
||
import CodeModal from './codeModal';
|
||
import './index.scss';
|
||
import { Confirm } from '../../components/ModalFun';
|
||
|
||
|
||
const { info } = Modal;
|
||
|
||
|
||
|
||
export default Form.create()(forwardRef(({ current_user, form, showNotification, match, history }, ref) => {
|
||
|
||
const [taskCategoryArr, setTaskCategoryArr] = useState([]);
|
||
const [fileList, setFileList] = useState(null);
|
||
|
||
const [publishMode, setPublishMode] = useState('0'); //发布方式
|
||
const [categoryId, setCategoryId] = useState('7'); //所在领域
|
||
const [descriptionHtml, setDescriptionHtml] = useState(''); //详情的富文本
|
||
const [enterpriseName, setEnterpriseName] = useState(''); //主体信息
|
||
const [displayTime, setDisplayTime] = useState(() => {
|
||
return {
|
||
collectingTime: getSomeDayAfter(30),
|
||
choosingTime: getSomeDayAfter(30 + 15),
|
||
makePublicTime: getSomeDayAfter(30 + 15 + 7),
|
||
signingTime: getSomeDayAfter(30 + 15 + 7 + 15),
|
||
payingTime: getSomeDayAfter(30 + 15 + 7 + 15 + 15)
|
||
}
|
||
}); //节点时间
|
||
const [visible, setVisible] = useState(false);
|
||
const [num, setNum] = useState(0) // 倒计时
|
||
const [isSend, setIsSend] = useState(false) // 是否发送验证码
|
||
const [published, setPublished] = useState(false); //是否已发布
|
||
const [status, setStatus] = useState(0); //任务当前状态
|
||
const [publishedAt, setPublishedAt] = useState();
|
||
|
||
const id = match.params.taskId;
|
||
const { getFieldDecorator, validateFields, setFieldsValue, getFieldsValue } = form;
|
||
|
||
// 根据是否传id判断是新增还是修改,根据状态判定是否是发布后的修改
|
||
useEffect(() => {
|
||
if (id) {
|
||
getTaskDetail(id).then(data => {
|
||
console.log('data');
|
||
console.log(data.status);
|
||
// 如果发布了, 且用户不是管理员,那么返回之前的页面
|
||
if (data.status > 2 && !(current_user && current_user.admin)) {
|
||
history.go(-1);
|
||
}
|
||
if (data.status > 2) {
|
||
setPublished(true);
|
||
setStatus(data.status);
|
||
setPublishedAt(data.publishedAt || data.createdAt)
|
||
}else{
|
||
// 只有发布之前,才能更新发布人
|
||
CompanyInfo();
|
||
}
|
||
let formValue = {
|
||
name: data.name,
|
||
contactName: data.contactName,
|
||
contactPhone: data.contactPhone,
|
||
uploadFileNumbers: data.uploadFileNumbers,
|
||
|
||
bounty: data.bounty,
|
||
taskModeId: data.taskModeId,
|
||
collectionMode: data.collectionMode,
|
||
publishMode: data.publishMode + '',
|
||
|
||
description: data.description,
|
||
collectingDays: data.collectingDays,
|
||
choosingDays: data.choosingDays,
|
||
makePublicDays: data.makePublicDays,
|
||
signingDays: data.signingDays,
|
||
payingDays: data.payingDays,
|
||
expertReview: data.expertReview
|
||
};
|
||
if (data.tasksAttachments && data.tasksAttachments.length) {
|
||
for (const item of data.tasksAttachments) {
|
||
item.name = item.fileName;
|
||
item.size = item.fileSize;
|
||
item.uid = "rc-upload" + item.id
|
||
}
|
||
setFileList(data.tasksAttachments);
|
||
}
|
||
setFieldsValue(formValue);
|
||
setEnterpriseName(data.enterpriseName);
|
||
setCategoryId(data.categoryId);
|
||
setDescriptionHtml(data.description);
|
||
setPublishMode(data.publishMode + '');
|
||
|
||
let publishedAt = (data.publishedAt || data.createdAt);
|
||
|
||
let collectingTime = getSomeDayAfter(data.collectingDays, publishedAt);
|
||
let choosingTime = getSomeDayAfter(data.collectingDays + data.choosingDays, publishedAt);
|
||
let makePublicTime = getSomeDayAfter(data.collectingDays + data.choosingDays + data.makePublicDays, publishedAt);
|
||
let signingTime = getSomeDayAfter(data.collectingDays + data.choosingDays + data.makePublicDays + data.signingDays, publishedAt);
|
||
let payingTime = getSomeDayAfter(data.collectingDays + data.choosingDays + data.makePublicDays + data.signingDays + data.payingDays, publishedAt);
|
||
setDisplayTime({ collectingTime, choosingTime, makePublicTime, signingTime, payingTime });
|
||
});
|
||
} else {
|
||
let formValue = {
|
||
contactName: current_user.username || current_user.login,
|
||
contactPhone: current_user.contactPhone,
|
||
taskModeId: 1,
|
||
collectionMode: 1,
|
||
publishMode: '0',
|
||
collectingDays: 30,
|
||
choosingDays: 15,
|
||
makePublicDays: 7,
|
||
signingDays: 15,
|
||
payingDays: 15,
|
||
};
|
||
setFieldsValue(formValue);
|
||
setCategoryId('7');
|
||
CompanyInfo();
|
||
}
|
||
}, [id]);
|
||
|
||
function CompanyInfo(){
|
||
getCompanyInfo().then(res => {
|
||
if (res && res.message === 'success') {
|
||
setEnterpriseName(res.data.enterpriseName);
|
||
setFieldsValue({
|
||
contactPhone: res.data.phone,
|
||
contactName: res.data.userName,
|
||
})
|
||
} else {
|
||
showNotification(res.message);
|
||
}
|
||
});
|
||
}
|
||
|
||
useEffect(() => {
|
||
getTaskCategory().then(data => {
|
||
if (data) {
|
||
for (const item of data) {
|
||
item.dicItemCode = item.id;
|
||
item.dicItemName = item.name;
|
||
}
|
||
setTaskCategoryArr(data);
|
||
}
|
||
});
|
||
}, []);
|
||
|
||
/** 倒计时显示*/
|
||
useEffect(() => {
|
||
let timer = 0;
|
||
if (isSend && num !== 0) {
|
||
timer = setInterval(() => {
|
||
setNum(n => {
|
||
if (n === 1) {
|
||
setIsSend(false)
|
||
clearInterval(timer)
|
||
}
|
||
return n - 1;
|
||
});
|
||
}, 1000);
|
||
}
|
||
return () => {
|
||
// 组件销毁时,清除定时器
|
||
clearInterval(timer)
|
||
};
|
||
}, [isSend]);
|
||
|
||
// 计算发布以后多久
|
||
function getSomeDayAfter(nDay, publishedAt) {
|
||
return publishedAt ? moment(new Date(publishedAt).setDate((publishedAt ? new Date(publishedAt) : new Date()).getDate() + nDay)).format('YYYY-MM-DD HH:mm') :
|
||
moment(new Date().setDate(new Date().getDate() + nDay)).format('YYYY-MM-DD HH:mm');
|
||
}
|
||
|
||
// 上传附件后得到的文件数组
|
||
function UploadFunc(fileList) {
|
||
setFileList(fileList);
|
||
let files = [];
|
||
for (const item of fileList) {
|
||
if (item) {
|
||
let itemId = (item.response && item.response.data && item.response.data.id) || item.id;
|
||
itemId && files.push(itemId);
|
||
}
|
||
}
|
||
setFieldsValue({
|
||
uploadFileNumbers: files.join()
|
||
});
|
||
}
|
||
|
||
const helper = useCallback(
|
||
(label, name, rules, widget, initialValue, rightComponent) => (
|
||
<Form.Item label={label}>
|
||
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
|
||
{rightComponent}
|
||
</Form.Item>
|
||
), []);
|
||
|
||
const helperNoLabel = useCallback(
|
||
(title, name, rules, widget, displayTime) => {
|
||
let active = (status == 3 && title == '成果提交') || (status == 4 && title == '成果评选') || (status == 5 && title == '结果公示') || (status == 6 && title == '任务协议签订');
|
||
return (
|
||
<div className="timing_task" key={name}>
|
||
<div className="mbt10 color-grey-9 lineh-35"><span className={`inline-span ${active ? 'active' : ''}`}>{title}</span></div>
|
||
<Form.Item className="no-label">
|
||
{getFieldDecorator(name, { rules, validateFirst: true, })(widget)}
|
||
</Form.Item>
|
||
<span className="days-word color-grey-9 ">天</span>
|
||
{publishMode == '0' && <p className="display-time">{displayTime}</p>}
|
||
</div>
|
||
)
|
||
}, [publishMode, status]);
|
||
|
||
// 新增或者修改后的处理函数
|
||
const publishDeal = useCallback((status, publishMode, res) => {
|
||
if (res && res.data) {
|
||
if (!status) {
|
||
history.push("/task/myTask?published=false");
|
||
showNotification("任务保存成功!");
|
||
} else if (current_user.admin && status>2) {
|
||
history.push(`/task/taskDetail/${id}`);
|
||
showNotification("任务修改成功!");
|
||
} else if (current_user.admin) {
|
||
history.push("/task");
|
||
showNotification("任务发布成功!");
|
||
} else {
|
||
info({
|
||
title: '提示',
|
||
content: <div>
|
||
<h4>发布申请已提交,请等待管理员的审核</h4>
|
||
<p>我们将在1-2个工作日内完成审核</p>
|
||
</div>,
|
||
onOk() {
|
||
history.push("/task/myTask?published=false");
|
||
},
|
||
});
|
||
}
|
||
} else {
|
||
showNotification(res.message);
|
||
}
|
||
}, []);
|
||
|
||
// 发布/保存
|
||
function saveItem(status) {
|
||
validateFields((error, values) => {
|
||
if (!error) {
|
||
let params = {
|
||
...values,
|
||
status,
|
||
enterpriseName: enterpriseName,
|
||
categoryId,
|
||
};
|
||
params.expertReview=Boolean(params.expertReview);
|
||
let dateSum = params.collectingDays + params.choosingDays + params.makePublicDays + params.signingDays + params.payingDays;
|
||
if (dateSum > 180) {
|
||
showNotification("任务天数总和不得超过180天!");
|
||
return;
|
||
}
|
||
if (status > 2) {
|
||
updatePublishedTask({
|
||
id: id,
|
||
bounty: values.bounty,
|
||
choosingDays: values.choosingDays,
|
||
collectingDays: values.collectingDays,
|
||
currentUserId: current_user.user_id,
|
||
description: values.description,
|
||
makePublicDays: values.makePublicDays,
|
||
name: values.name,
|
||
payingDays: values.payingDays,
|
||
signingDays: values.signingDays,
|
||
uploadFileNumbers:values.uploadFileNumbers
|
||
}).then(res => {
|
||
publishDeal(status, publishMode, res);
|
||
});
|
||
} else if (id) {
|
||
// 编辑
|
||
params.id = id;
|
||
updateTask(params).then(res => {
|
||
publishDeal(status, publishMode, res);
|
||
});
|
||
} else {
|
||
// 新增
|
||
addTask(params).then(res => {
|
||
publishDeal(status, publishMode, res);
|
||
});
|
||
}
|
||
}
|
||
})
|
||
}
|
||
|
||
function changeDate(v, field) {
|
||
if (typeof v !== 'number' || v < 0) {
|
||
return;
|
||
}
|
||
let values = getFieldsValue();
|
||
values[field] = v;
|
||
let collectingTime = getSomeDayAfter(values.collectingDays, publishedAt);
|
||
let choosingTime = getSomeDayAfter(values.collectingDays + values.choosingDays, publishedAt);
|
||
let makePublicTime = getSomeDayAfter(values.collectingDays + values.choosingDays + values.makePublicDays, publishedAt);
|
||
let signingTime = getSomeDayAfter(values.collectingDays + values.choosingDays + values.makePublicDays + values.signingDays, publishedAt);
|
||
let payingTime = getSomeDayAfter(values.collectingDays + values.choosingDays + values.makePublicDays + values.signingDays + values.payingDays, publishedAt);
|
||
|
||
setDisplayTime({ collectingTime, choosingTime, makePublicTime, signingTime, payingTime });
|
||
}
|
||
|
||
function changeContactPhone(e) {
|
||
console.log(e);
|
||
setFieldsValue({
|
||
contactPhone: e
|
||
})
|
||
}
|
||
|
||
function editPublished() {
|
||
Confirm({
|
||
title: '提醒',
|
||
content: <div>
|
||
<p>确认更改该创客任务内容?</p>
|
||
</div>,
|
||
onOk: () => {
|
||
saveItem(status)
|
||
},
|
||
onCancel:()=>{
|
||
history.push(`/task/taskDetail/${id}`);
|
||
}
|
||
});
|
||
}
|
||
return (
|
||
<div className="centerbox">
|
||
<div className="head-navigation">
|
||
<Link to="/task">创客空间 ></Link>
|
||
<Link to="/task">任务大厅 ></Link>
|
||
<span >需求提报 </span>
|
||
</div>
|
||
<p className="font-18 font-bd mb15">任务提交</p>
|
||
|
||
<div className="edu-back-white mb30">
|
||
<div className="padding30 bor-bottom-greyE">
|
||
<p className="partTitle">联系方式<span className="color-red font-14">(*必填)</span></p>
|
||
|
||
<Form {...formItemLayout}>
|
||
<Form.Item label='主体信息:'>
|
||
{enterpriseName}
|
||
</Form.Item>
|
||
|
||
{helper(
|
||
"联系人:",
|
||
"contactName",
|
||
[{ required: true, message: "请输入联系人" }],
|
||
<Input
|
||
disabled={published}
|
||
className="contact-input"
|
||
placeholder="请输入联系人"
|
||
/>
|
||
)}
|
||
|
||
{helper(
|
||
"联系电话:",
|
||
"contactPhone",
|
||
[{ required: true, message: "请输入联系电话" }],
|
||
<Input
|
||
className="contact-input"
|
||
placeholder="请输入联系电话"
|
||
disabled
|
||
/>, '', <Icon className="editPhone" type="edit" onClick={() => { setVisible(true) }} />
|
||
)}
|
||
|
||
</Form>
|
||
</div>
|
||
|
||
<div className="padding30 bor-bottom-greyE">
|
||
<p className="partTitle">任务内容<span className="color-red font-14">(*必填)</span></p>
|
||
|
||
<div className="pl15 task-edit-content">
|
||
<p className="color-grey3 mb20">选择任务所在领域</p>
|
||
|
||
<div className="mb20 clearfix areaDiv" >
|
||
{
|
||
taskCategoryArr.map(item => {
|
||
return <button
|
||
className={classNames({ "choose-button": true, "active": item.dicItemCode == categoryId })}
|
||
key={item.dicItemCode}
|
||
onClick={() => { setCategoryId(item.dicItemCode) }}
|
||
>{item.dicItemName}</button>
|
||
})
|
||
}
|
||
</div>
|
||
|
||
{helper(
|
||
"",
|
||
"name",
|
||
[{ required: true, message: "请用一句话概括您要做什么?比如:开源项目网站开发,最大限制200个字符" },
|
||
{ max: 200, message: '长度不能超过200个字符' }],
|
||
<Input
|
||
placeholder="请用一句话概括您要做什么?比如:开源项目网站开发,最大限制200个字符"
|
||
/>
|
||
)}
|
||
|
||
<Form.Item >
|
||
{(!id || (id && descriptionHtml)) && <ReactWEditor
|
||
defaultValue={descriptionHtml}
|
||
config={{
|
||
...editorConfig,
|
||
placeholder: "把您的任务内容补充详细一些吧,越清晰具体,任务完成质量越高哟~",
|
||
}}
|
||
onChange={(html) => { setFieldsValue({ description: html }) }}
|
||
/>}
|
||
{/* 用一个隐藏的input实现上必填校验 */}
|
||
{getFieldDecorator('description', {
|
||
rules: [{ required: true, message: "把您的任务内容补充详细一些吧,越清晰具体,任务完成质量越高哟~" }],
|
||
validateFirst: true
|
||
})(<Input style={{ display: 'none' }} />)}
|
||
</Form.Item>
|
||
|
||
<p className="color-grey3 mb10 mt20">
|
||
<span className="color-orange mr2 ">*</span>
|
||
注:任务发布之后,将会公开展示在交易中心。不要把与项目、客户相关等隐私信息,以及QQ号、微信号、电话号码等联系方式填写在任务中。
|
||
</p>
|
||
|
||
<Form.Item >
|
||
{getFieldDecorator('expertReview', {
|
||
validateFirst: true,
|
||
defaultValue:false,
|
||
valuePropName:"checked"
|
||
})(<Checkbox className="color-grey-3" disabled={published}>是否增加专家评审流程?添加后可联系管理员发布此专家评审任务</Checkbox>)}
|
||
</Form.Item>
|
||
|
||
<Form.Item >
|
||
<Upload
|
||
className="commentStyle"
|
||
load={UploadFunc}
|
||
size={150}
|
||
showNotification={showNotification}
|
||
actionUrl={httpUrl}
|
||
fileList={fileList}
|
||
/>
|
||
{getFieldDecorator('uploadFileNumbers', {
|
||
validateFirst: true
|
||
})(<Input style={{ display: 'none' }} />)}
|
||
</Form.Item>
|
||
</div>
|
||
</div>
|
||
|
||
<div className="padding30 ">
|
||
<p className="partTitle">选择任务周期、价格和发布模式<span className="color-red font-14">(*必填)</span></p>
|
||
<Form className="gray-form" {...formItemLayout}>
|
||
{helper(
|
||
"赏金:",
|
||
"bounty",
|
||
[{ required: true, message: "您打算支付多少赏金呢" }],
|
||
<InputNumber
|
||
min={1}
|
||
max={99999999}
|
||
className="number-input"
|
||
placeholder="您打算支付多少赏金呢"
|
||
formatter={value => `${value}¥`}
|
||
/>
|
||
)}
|
||
|
||
{helper(
|
||
"悬赏模式:",
|
||
"taskModeId",
|
||
[{ required: true, message: "请选择悬赏模式" }],
|
||
<Radio.Group disabled={published}>
|
||
<Radio value={1}>单人悬赏,只设置一个中标者</Radio>
|
||
<Radio value={2}>多人悬赏,设置多分中标分享赏金</Radio>
|
||
<Radio value={3}>计件悬赏,合格一稿,支付一稿(稿件数量≥2件)</Radio>
|
||
</Radio.Group>
|
||
)}
|
||
|
||
{helper(
|
||
"征集方式:",
|
||
"collectionMode",
|
||
[{ required: true, message: "请选择征集方式" }],
|
||
<Radio.Group disabled={published}>
|
||
<Radio value={1}>创意征集,应征者以开放讨论的形式参与</Radio>
|
||
<Radio value={0}>物化成果征集,应征者以各自提交成果物的形式参与</Radio>
|
||
</Radio.Group>
|
||
)}
|
||
|
||
{helper(
|
||
"发布方式:",
|
||
"publishMode",
|
||
[{ required: true, message: "请选择发布方式" }],
|
||
<Radio.Group disabled={published} onChange={(e) => { setPublishMode(e.target.value) }}>
|
||
<Radio value={'0'}>自主提交方式,由发布方自行支付赏金,一键自助发布</Radio>
|
||
<Radio value={'1'}>统筹任务,由平台支付赏金,需经过平台遴选方能发布</Radio>
|
||
</Radio.Group>
|
||
)}
|
||
|
||
<div className="task-setting-days">
|
||
<div className="timing_task">
|
||
<div className="mbt10 color-grey-9 lineh-35"><span className="inline-span active">需求提报</span></div>
|
||
<div className="color-grey-9 ">自主提交:立即发布</div>
|
||
<div className="color-grey-9 ">统筹任务:遴选后发布</div>
|
||
</div>
|
||
|
||
{helperNoLabel(
|
||
"成果提交",
|
||
"collectingDays",
|
||
[{ required: true, message: "请输入天数" }],
|
||
<InputNumber
|
||
className="date-input"
|
||
onChange={(v) => { changeDate(v, 'collectingDays') }}
|
||
min={1}
|
||
max={180}
|
||
disabled={status > 2}
|
||
/>,
|
||
displayTime.collectingTime
|
||
)}
|
||
{/* <div className="color-grey-9 format-time-days-1 format-time-day-show">2021-06-16 07:10</div> */}
|
||
{/* <div className="days-error"><span className="color-red none">成果提交时间不能为空</span></div> */}
|
||
|
||
{helperNoLabel(
|
||
"成果评选",
|
||
"choosingDays",
|
||
[{ required: true, message: "请输入天数" }],
|
||
<InputNumber
|
||
className="date-input"
|
||
onChange={(v) => { changeDate(v, 'choosingDays') }}
|
||
min={1}
|
||
max={180}
|
||
disabled={status > 3}
|
||
/>,
|
||
displayTime.choosingTime
|
||
)}
|
||
|
||
{helperNoLabel(
|
||
"结果公示",
|
||
"makePublicDays",
|
||
[{ required: true, message: "请输入天数" }],
|
||
<InputNumber
|
||
className="date-input"
|
||
onChange={(v) => { changeDate(v, 'makePublicDays') }}
|
||
min={1}
|
||
max={180}
|
||
disabled={status > 4}
|
||
/>,
|
||
displayTime.makePublicTime
|
||
)}
|
||
|
||
{helperNoLabel(
|
||
"任务协议签订",
|
||
"signingDays",
|
||
[{ required: true, message: "请输入天数" }],
|
||
<InputNumber
|
||
className="date-input"
|
||
onChange={(v) => { changeDate(v, 'signingDays') }}
|
||
min={1}
|
||
max={180}
|
||
/>,
|
||
displayTime.signingTime
|
||
)}
|
||
|
||
{helperNoLabel(
|
||
"支付",
|
||
"payingDays",
|
||
[{ required: true, message: "请输入天数" }],
|
||
<InputNumber
|
||
className="date-input"
|
||
onChange={(v) => { changeDate(v, 'payingDays') }}
|
||
min={1}
|
||
max={180}
|
||
/>,
|
||
displayTime.payingTime
|
||
)}
|
||
|
||
<div className="timing_task">
|
||
<div className="mbt10 color-grey-9 lineh-35"><span className="inline-span">任务完成</span></div>
|
||
<div className="color-grey-9 ">支付确认后,任务完成</div>
|
||
</div>
|
||
</div>
|
||
|
||
<p className="color-grey3 mb10 ml40 mt20">
|
||
<span className="color-orange mr2 ">*</span>
|
||
注:任务天数总和不得超过180天。
|
||
</p>
|
||
</Form>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
{
|
||
published ? <Button className="mr20" type={"primary"} onClick={editPublished}>确认修改</Button> : <div>
|
||
<Button className="mr20" type={"primary"} onClick={() => { saveItem(1) }}>发布</Button>
|
||
<Button className="mr20" type={"primary"} onClick={() => { saveItem(0) }}>保存</Button>
|
||
<Button onClick={() => { history.go(-1) }}>取消</Button>
|
||
</div>
|
||
}
|
||
|
||
|
||
<CodeModal visible={visible} setVisible={setVisible} changeContactPhone={changeContactPhone} />
|
||
|
||
</div>
|
||
)
|
||
})
|
||
)
|