forked from Gitlink/forgeplus-react
上传需求代码,微调成果库代码
This commit is contained in:
parent
db702ed816
commit
563ca38d45
42
src/App.js
42
src/App.js
|
|
@ -76,8 +76,13 @@ const EducoderLogin = Loadable({
|
|||
})
|
||||
|
||||
// 成果库
|
||||
const Achieve=Loadable({
|
||||
loader: () => import('./achieveRequirement/index'),
|
||||
const Achieve = Loadable({
|
||||
loader: () => import('./achieveRequirement/achieve'),
|
||||
loading: Loading,
|
||||
})
|
||||
// 需求管理
|
||||
const Requirement = Loadable({
|
||||
loader: () => import('./achieveRequirement/requirement'),
|
||||
loading: Loading,
|
||||
})
|
||||
|
||||
|
|
@ -265,15 +270,8 @@ class App extends Component {
|
|||
(props) => {
|
||||
return (<InfosIndex {...this.props} {...this.state} />)
|
||||
}
|
||||
}></Route>
|
||||
<Route exact path="/"
|
||||
render={
|
||||
(props) => (
|
||||
<Projects {...this.props} {...props} {...this.state}></Projects>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
}></Route>
|
||||
|
||||
{/*成果库*/}
|
||||
<Route
|
||||
path={"/achieve"}
|
||||
|
|
@ -284,9 +282,29 @@ class App extends Component {
|
|||
}>
|
||||
</Route>
|
||||
|
||||
{/*需求管理/创客行动*/}
|
||||
<Route
|
||||
path={"/requirement"}
|
||||
render={
|
||||
(props) => {
|
||||
return (<Requirement {...this.props} {...props} {...this.state} />)
|
||||
}
|
||||
}>
|
||||
</Route>
|
||||
|
||||
<Route exact path="/"
|
||||
render={
|
||||
(props) => (
|
||||
<Projects {...this.props} {...props} {...this.state}></Projects>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
|
||||
|
||||
<Route component={Shixunnopage} />
|
||||
|
||||
|
||||
|
||||
</Switch>
|
||||
</Router>
|
||||
</MuiThemeProvider>
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ class Index extends Component {
|
|||
return (
|
||||
<div className="newMain clearfix">
|
||||
<Switch {...this.props}>
|
||||
|
||||
<Route
|
||||
path="/achieve/achieveDetail/:achieveId"
|
||||
render={(props) => (
|
||||
|
|
@ -60,6 +61,12 @@ class Index extends Component {
|
|||
<AchieveEdit {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/achieve"
|
||||
render={(props) => (
|
||||
<AchieveIndex {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/"
|
||||
render={(props) => (
|
||||
|
|
@ -30,23 +30,4 @@
|
|||
}
|
||||
}
|
||||
|
||||
// 文件预览modal样式
|
||||
.file-modal {
|
||||
width: 800px !important;
|
||||
.ant-modal-body {
|
||||
padding-top: 40px;
|
||||
.pdf-box {
|
||||
height: 70vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
.ant-modal-close {
|
||||
top: 0 !important;
|
||||
}
|
||||
.show-img {
|
||||
width: 100%;
|
||||
}
|
||||
.react-pdf__Page__canvas {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,10 @@ const { TextArea } = Input;
|
|||
|
||||
export default Form.create()(
|
||||
forwardRef(({ form, showNotification, match, history }, ref) => {
|
||||
|
||||
const [shareType, setShareType] = useState([]);
|
||||
const [tagType, setTagType] = useState([]);
|
||||
const [fileList, setFileList] = useState(null);
|
||||
const [achievementFiles, setAchievementFiles] = useState(undefined);
|
||||
const [achievementFileTypes, setAchievementFileTypes] = useState(undefined);
|
||||
const [achievementFileTypes, setAchievementFileTypes] = useState('');
|
||||
|
||||
const id = match.params.achieveId;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||
|
|
@ -27,7 +25,8 @@ export default Form.create()(
|
|||
achievementTypeId: data.achievementTypeId,
|
||||
achievementBelong: data.achievementBelong,
|
||||
achievementLabel: data.achievementLabel,
|
||||
achievementRemark: data.achievementRemark
|
||||
achievementRemark: data.achievementRemark,
|
||||
achievementFiles: data.achievementFiles
|
||||
};
|
||||
setFieldsValue(formValue);
|
||||
if (data.achievementAttachments.length) {
|
||||
|
|
@ -51,11 +50,19 @@ export default Form.create()(
|
|||
});
|
||||
}, []);
|
||||
|
||||
|
||||
// 上传附件后得到的文件id数组
|
||||
function UploadFunc(ids, types) {
|
||||
setAchievementFiles(ids);
|
||||
setAchievementFileTypes(types);
|
||||
// 上传附件后得到的文件数组
|
||||
function UploadFunc(fileList) {
|
||||
setFileList(fileList);
|
||||
let files = [];
|
||||
let fileTypes = [];
|
||||
for (const item of fileList) {
|
||||
files.push(item.id || item.response.data.id);
|
||||
fileTypes.push(item.fileType || item.response.data.fileType);
|
||||
}
|
||||
setFieldsValue({
|
||||
achievementFiles: files.join()
|
||||
});
|
||||
setAchievementFileTypes(fileTypes.join());
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
|
|
@ -74,7 +81,7 @@ export default Form.create()(
|
|||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 12 },
|
||||
sm: { span: 20 },
|
||||
sm: { span: 16 },
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -92,18 +99,18 @@ export default Form.create()(
|
|||
};
|
||||
|
||||
// 修改
|
||||
function editItem() {
|
||||
if (!achievementFiles.length) {
|
||||
showNotification("请上传成果文件!");
|
||||
return;
|
||||
}
|
||||
function saveItem() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
let params = { ...values, achievementFiles, achievementFileTypes, uploadUserId: 1, };
|
||||
let params = {
|
||||
...values,
|
||||
achievementFileTypes,
|
||||
};
|
||||
params.achievementLabel = params.achievementLabel.join();
|
||||
|
||||
if (id) {
|
||||
// 编辑
|
||||
params.id = id;
|
||||
editAchieve(params).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification("成果更新成功!");
|
||||
|
|
@ -114,9 +121,10 @@ export default Form.create()(
|
|||
});
|
||||
} else {
|
||||
// 新增
|
||||
params.uploadUserId = 1;
|
||||
addAchieve(params).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification("成果更新成功!");
|
||||
showNotification("成果新增成功!");
|
||||
history.go(-1);
|
||||
} else {
|
||||
showNotification(res.message);
|
||||
|
|
@ -132,7 +140,7 @@ export default Form.create()(
|
|||
<div className="center-content">
|
||||
|
||||
<div className="centerScreen">
|
||||
<div className="center-left-but">修改成果</div>
|
||||
<div className="center-left-but">{id ? '修改' : '新增'}成果</div>
|
||||
</div>
|
||||
|
||||
<Form className="achieve-form" {...formItemLayout}>
|
||||
|
|
@ -141,6 +149,7 @@ export default Form.create()(
|
|||
"achievementName",
|
||||
[{ required: true, message: "请输入成果名称" }],
|
||||
<Input
|
||||
className="edit-input"
|
||||
placeholder="请输入成果名称"
|
||||
/>
|
||||
)}
|
||||
|
|
@ -149,7 +158,8 @@ export default Form.create()(
|
|||
"成果类别:",
|
||||
"achievementTypeId",
|
||||
[{ required: true, message: "请选择成果类别" }],
|
||||
<Select placeholder="请选择成果类别" style={{ width: "350px" }}
|
||||
<Select placeholder="请选择成果类别"
|
||||
className="edit-input"
|
||||
>
|
||||
{
|
||||
shareType.map(item => {
|
||||
|
|
@ -164,6 +174,7 @@ export default Form.create()(
|
|||
"achievementBelong",
|
||||
[{ required: true, message: "请输入单位名称" }],
|
||||
<Input
|
||||
className="edit-input"
|
||||
placeholder="请输入单位名称"
|
||||
/>
|
||||
)}
|
||||
|
|
@ -177,6 +188,11 @@ export default Form.create()(
|
|||
actionUrl={httpUrl}
|
||||
fileList={fileList}
|
||||
/>
|
||||
|
||||
{/* 用一个隐藏的input实现上传文件的必填校验 */}
|
||||
{getFieldDecorator('achievementFiles', {
|
||||
rules: [{ required: true, message: "请上传成果文件" }], validateFirst: true
|
||||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
|
||||
{helper(
|
||||
|
|
@ -184,7 +200,8 @@ export default Form.create()(
|
|||
"achievementLabel",
|
||||
[{ required: true, message: "请选择成果标签" }],
|
||||
<Select
|
||||
placeholder="请选择成果标签" style={{ width: "350px" }}
|
||||
className="edit-input"
|
||||
placeholder="请选择成果标签"
|
||||
mode="tags"
|
||||
tokenSeparators={[',']}
|
||||
>
|
||||
|
|
@ -207,7 +224,7 @@ export default Form.create()(
|
|||
)}
|
||||
|
||||
<Form.Item {...tailFormItemLayout}>
|
||||
<Button className="mr20" type={"primary"} onClick={editItem}>保存</Button>
|
||||
<Button className="mr20" type={"primary"} onClick={saveItem}>保存</Button>
|
||||
<Button onClick={() => { history.go(-1) }}>取消</Button>
|
||||
</Form.Item>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,12 +40,12 @@ export default (props) => {
|
|||
}, [achievementTypeId, achievementFileTypes, orderBy, curPage]);
|
||||
|
||||
|
||||
function changeOptionId(id, type) {
|
||||
function changeOptionId(option, type) {
|
||||
if (type === 'share_type') {
|
||||
setAchievementTypeId(id);
|
||||
setAchievementTypeId(option.id);
|
||||
setCurPage(1);
|
||||
} else if (type === 'file_type') {
|
||||
setAchievementFileTypes(id);
|
||||
setAchievementFileTypes(option.id);
|
||||
setCurPage(1);
|
||||
}
|
||||
}
|
||||
|
|
@ -118,7 +118,7 @@ export default (props) => {
|
|||
<div className={classNames({ 'center-left-butD': true, 'center-left-butDACT': orderBy === 'view_count' })} onClick={() => { changeSort('view_count') }}><Icon type="arrow-down" />最热</div>
|
||||
</div>
|
||||
{
|
||||
current_user.login &&
|
||||
// current_user.login &&
|
||||
<div className="center-right-but">
|
||||
<Button className="mr15 font-12" size="small" type="primary" onClick={goAchieveMine}>我的成果</Button>
|
||||
<Button className="mr20 font-12" size="small" type="primary" onClick={goAdd}><i className="iconfont icon-zaibianji font-12 mr3"></i>发布成果</Button>
|
||||
|
|
@ -139,6 +139,7 @@ export default (props) => {
|
|||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ export default (props) => {
|
|||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export async function getAchieveList(params) {
|
|||
if (res && res.data) {
|
||||
for (const i of res.data.rows) {
|
||||
// 处理分解标签
|
||||
i.achievementLabel = i.achievementLabel.split(',');
|
||||
i.tag = i.achievementLabel.split(',');
|
||||
}
|
||||
}
|
||||
return res.data;
|
||||
|
|
|
|||
|
|
@ -27,9 +27,13 @@ function Uploads({ className, size, actionUrl, fileList, showNotification, load
|
|||
let id = (file.response && file.response.data && file.response.data.id) || file.id;
|
||||
|
||||
// 暂时不直接删除上传的文件,只在最后保存的时候进行修改
|
||||
let nf = files.filter(item => (item.response && item.response.data && item.response.data.id !== id) && (item.id !== id));
|
||||
let nf = files.filter(item => {
|
||||
let itemId = (item.response && item.response.data && item.response.data.id) || item.id;
|
||||
return itemId !== id;
|
||||
});
|
||||
setFiles(nf);
|
||||
fileIdList(nf);
|
||||
// fileIdList(nf);
|
||||
load && load(nf);
|
||||
|
||||
// 发送服务到后台删除文件,同步更新数据
|
||||
// const url = actionUrl + `/busiAttachments/${id}`;
|
||||
|
|
@ -53,19 +57,19 @@ function Uploads({ className, size, actionUrl, fileList, showNotification, load
|
|||
if (info.file.status === 'uploading' || info.file.status === 'done' || info.file.status === 'removed') {
|
||||
let fileList = info.fileList;
|
||||
setFiles(appendFileSizeToUploadFileAll(fileList));
|
||||
if (info.file.status === 'done' || info.file.status === 'removed') fileIdList(fileList);
|
||||
if (info.file.status === 'done' || info.file.status === 'removed') load && load(fileList);
|
||||
}
|
||||
}
|
||||
|
||||
function fileIdList(fileList) {
|
||||
let id = [];
|
||||
let fileType = [];
|
||||
for (const item of fileList) {
|
||||
id.push(item.id || item.response.data.id);
|
||||
fileType.push(item.fileType || item.response.data.fileType);
|
||||
}
|
||||
load && load(id.join(), fileType.join());
|
||||
}
|
||||
// function fileIdList(fileList) {
|
||||
// let id = [];
|
||||
// let fileType = [];
|
||||
// for (const item of fileList) {
|
||||
// id.push(item.id || item.response.data.id);
|
||||
// fileType.push(item.fileType || item.response.data.fileType);
|
||||
// }
|
||||
// load && load(id.join(), fileType.join());
|
||||
// }
|
||||
|
||||
function beforeUpload(file) {
|
||||
const isLt100M = file.size / 1024 / 1024 < size;
|
||||
|
|
|
|||
|
|
@ -3,27 +3,27 @@ import classNames from 'classnames';
|
|||
import './index.scss';
|
||||
|
||||
export default (props) => {
|
||||
const {title, options,changeOptionId ,type} = props;
|
||||
const { title, options, changeOptionId, type } = props;
|
||||
|
||||
const [id, setId] = useState("");
|
||||
const [option, setOption] = useState({ id: "", dicItemName: "" ,dicItemCode:""});
|
||||
|
||||
useEffect(()=>{
|
||||
changeOptionId(id,type);
|
||||
},[id])
|
||||
useEffect(() => {
|
||||
changeOptionId(option, type);
|
||||
}, [option])
|
||||
|
||||
return (
|
||||
|
||||
<div className="shop-box">
|
||||
<div className="choose-title">{title}</div>
|
||||
<div className="choose-list">
|
||||
<div className={classNames({"choose-item-checked":id==="","choose-item":true})} key={"all"} onClick={()=>{setId("")}}>全部</div>
|
||||
{
|
||||
options.map((item) => {
|
||||
return <div className={classNames({"choose-item-checked":id===item.id,"choose-item":true})} key={item.dicItemName} onClick={()=>{setId(item.id)}} >{item.dicItemName}</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className="shop-box">
|
||||
<div className="choose-title">{title}</div>
|
||||
<div className="choose-list">
|
||||
<div className={classNames({ "choose-item-checked": option.id === "", "choose-item": true })} key={"all"} onClick={() => { setOption({ id: "", dicItemName: "" }) }}>全部</div>
|
||||
{
|
||||
options.map((item) => {
|
||||
return <div className={classNames({ "choose-item-checked": option.id === item.id, "choose-item": true })} key={item.dicItemName} onClick={() => { setOption(item) }} >{item.dicItemName}</div>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
)
|
||||
}
|
||||
|
|
@ -1,31 +1,40 @@
|
|||
import React from 'react';
|
||||
import './index.scss';
|
||||
const statusArr = ['待审核', '进行中', '成果验收中', '完成', '审核未通过', '延期', '其他', '验收未通过'];
|
||||
const classArr = ['', 'list-done', 'list-done', 'list-done', 'list-error', '', '', 'list-error'];
|
||||
|
||||
export default (props) => {
|
||||
const { list, itemClick, editItem, deletItem } = props;
|
||||
const { list, itemClick, editItem, deletItem, activeByStatus } = props;
|
||||
|
||||
return (
|
||||
list.map(item => {
|
||||
return (
|
||||
<div className="list-box" key={item.id}>
|
||||
<div className="list-title" onClick={() => { itemClick(item.id) }}>
|
||||
{item.achievementName}
|
||||
{item.achievementName || item.title}
|
||||
{item.status && <span className={classArr[item.status]}>{statusArr[item.status]}</span>}
|
||||
</div>
|
||||
<div >
|
||||
{
|
||||
item.achievementLabel.map(i => {
|
||||
item.tag.map(i => {
|
||||
return <span className="list-tag" key={i + "av"}>{i}</span>;
|
||||
})
|
||||
}
|
||||
</div>
|
||||
<div className="list-other">
|
||||
{item.user && <p>发布者:{item.user.nickname ? item.user.nickname : item.user.login}</p>}
|
||||
<p>发布时间:{item.achievementPublishTime}</p>
|
||||
{item.createUser && <p>发布者:{item.createUser.nickname ? item.createUser.nickname : item.createUser.login}</p>}
|
||||
<p>发布时间:{item.achievementPublishTime || item.createTime}</p>
|
||||
</div>
|
||||
{editItem && <div className="list-box-action">
|
||||
<button onClick={() => { editItem(item.id) }}><i className="iconfont icon-zaibianji font-25"></i></button>
|
||||
<button onClick={() => { deletItem(item.id) }}><i className="iconfont icon-shanchu font-30 "></i></button>
|
||||
</div>}
|
||||
{
|
||||
editItem && <div className="list-box-action">
|
||||
{
|
||||
!activeByStatus || (activeByStatus && item.status == '0' || item.status == '4' || item.status == '5') &&
|
||||
<button onClick={() => { editItem(item.id) }}><i className="iconfont icon-zaibianji font-25"></i></button>
|
||||
}
|
||||
<button onClick={() => { deletItem(item.id) }}><i className="iconfont icon-shanchu font-30 "></i></button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -9,14 +9,12 @@
|
|||
color: #000;
|
||||
cursor: pointer;
|
||||
}
|
||||
.list-title p {
|
||||
display: inline-block;
|
||||
}
|
||||
.list-title p:hover {
|
||||
.list-title:hover {
|
||||
color: #409eff;
|
||||
}
|
||||
.list-title span {
|
||||
padding: 3px 5px;
|
||||
margin-left:.5em;
|
||||
background: #f8c753;
|
||||
font-size: 13px;
|
||||
color: #fff;
|
||||
|
|
@ -25,6 +23,9 @@
|
|||
span.list-done {
|
||||
background: #35d77e;
|
||||
}
|
||||
span.list-error {
|
||||
background: #f56c6c;
|
||||
}
|
||||
|
||||
.list-tag {
|
||||
display: inline-block;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// 本模块公共样式
|
||||
|
||||
.centerbox {
|
||||
width: 1280px;
|
||||
margin:40px auto;
|
||||
width: 80vw;
|
||||
max-width: 1280px;
|
||||
margin: 40px auto;
|
||||
}
|
||||
.center-content {
|
||||
width: 1280px;
|
||||
margin: 20px 0;
|
||||
background: #fff;
|
||||
border: 1px solid #dedede;
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.center-right-but>span{
|
||||
.center-right-but > span {
|
||||
margin: 0 10px;
|
||||
font-size: 16px;
|
||||
color: #0089ff;
|
||||
|
|
@ -61,13 +61,40 @@
|
|||
}
|
||||
|
||||
// 通用标签样式
|
||||
.list-tag{
|
||||
.list-tag {
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
background: #cfe9ff;
|
||||
color: #0089ff;
|
||||
font-size: 14px;
|
||||
border-radius:3px ;
|
||||
border-radius: 3px;
|
||||
padding: 2px 5px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
// 文件预览modal样式
|
||||
.file-modal {
|
||||
width: 800px !important;
|
||||
.ant-modal-body {
|
||||
padding-top: 40px;
|
||||
.pdf-box {
|
||||
height: 70vh;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
}
|
||||
.ant-modal-close {
|
||||
top: 0 !important;
|
||||
}
|
||||
.show-img {
|
||||
width: 100%;
|
||||
}
|
||||
.react-pdf__Page__canvas,
|
||||
.react-pdf__Page__textContent {
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.edit-input {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
import React, { Component } 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 './index.scss';
|
||||
|
||||
const RequireList = Loadable({
|
||||
loader: () => import("./requirement/requireList"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const RequireDetail = Loadable({
|
||||
loader: () => import("./requirement/requireDetail"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
const RequireMine = Loadable({
|
||||
loader: () => import("./requirement/requireMine"),
|
||||
loading: Loading,
|
||||
});
|
||||
const RequireAdd = Loadable({
|
||||
loader: () => import("./requirement/requireEdit"),
|
||||
loading: Loading,
|
||||
});
|
||||
const RequireEdit = Loadable({
|
||||
loader: () => import("./requirement/requireEdit"),
|
||||
loading: Loading,
|
||||
});
|
||||
|
||||
class Index extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="newMain clearfix">
|
||||
<Switch {...this.props}>
|
||||
|
||||
<Route
|
||||
path="/requirement/requireDetail/:requireId"
|
||||
render={(props) => (
|
||||
<RequireDetail {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/requirement/requireMine"
|
||||
render={(props) => (
|
||||
<RequireMine {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/requirement/requireAdd"
|
||||
render={(props) => (
|
||||
<RequireAdd {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/requirement/requireEdit/:requireId"
|
||||
render={(props) => (
|
||||
<RequireEdit {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
<Route
|
||||
path="/requirement"
|
||||
render={(props) => (
|
||||
<RequireList {...this.props} {...props} />
|
||||
)}
|
||||
></Route>
|
||||
|
||||
|
||||
|
||||
{/* <Route
|
||||
exact
|
||||
path="/"
|
||||
render={(props) => (
|
||||
this.props.current_user && this.props.current_user.login ?
|
||||
<Infos {...this.props} {...props} />
|
||||
:
|
||||
<RequireIndex {...this.props} {...props} />
|
||||
)}
|
||||
></Route> */}
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default withRouter(
|
||||
ImageLayerOfCommentHOC({
|
||||
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
|
||||
parentSelector: ".newMain",
|
||||
})(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC(Index))))
|
||||
);
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
import fetch from '../../fetch';
|
||||
|
||||
// 获取字典分类列表
|
||||
export function getDictionary(id) {
|
||||
return fetch({
|
||||
url: '/dicItem/getData?dicTypeCode=' + id,
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
||||
// 需求列表查询
|
||||
export async function getRequirementList(data) {
|
||||
let res = await fetch({
|
||||
url: '/requirement/page',
|
||||
method: 'post',
|
||||
data,
|
||||
});
|
||||
if (res && res.data && res.data.rows) {
|
||||
for (const i of res.data.rows) {
|
||||
// 处理分解标签
|
||||
i.tag = i.tag.split(',');
|
||||
}
|
||||
}
|
||||
return res.data;
|
||||
}
|
||||
|
||||
//新增需求
|
||||
export function addRequirement(data) {
|
||||
return fetch({
|
||||
url: '/requirement/add',
|
||||
method: 'post',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
//删除需求
|
||||
export function deleteRequirement(id) {
|
||||
return fetch({
|
||||
url: '/requirement/delete?id=' + id,
|
||||
method: 'DELETE',
|
||||
});
|
||||
}
|
||||
|
||||
//更新需求
|
||||
export function updateRequirement(data) {
|
||||
return fetch({
|
||||
url: '/requirement/update',
|
||||
method: 'put',
|
||||
data: data
|
||||
});
|
||||
}
|
||||
|
||||
// 需求详情查询
|
||||
export async function getRequirementDetail(id) {
|
||||
let res = await fetch({
|
||||
url: '/requirement/getInfo?id=' + id,
|
||||
method: 'get',
|
||||
});
|
||||
if (res && res.data) {
|
||||
res.data.tag = res.data.tag.split(',');
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
|
||||
//获取用户列表
|
||||
export function getAllUsers() {
|
||||
return fetch({
|
||||
url: '/user/getUsers',
|
||||
method: 'get'
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Descriptions, Modal, Button } from 'antd';
|
||||
import { Document, Page, pdfjs } from 'react-pdf';
|
||||
import DelModal from '../../components/DelModal';
|
||||
import Upload from '../../components/Upload';
|
||||
import { httpUrl } from '../../../fetch';
|
||||
import { deleteRequirement, getRequirementDetail, updateRequirement } from '../api';
|
||||
import './index.scss';
|
||||
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
|
||||
|
||||
export default ({ match, history, current_user, showNotification }) => {
|
||||
const id = match.params.requireId;
|
||||
const [requireForm, setRequireForm] = useState({});
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [visibleAchieve, setVisibleAchieve] = useState(false);
|
||||
const [fileType, setFileType] = useState(4);
|
||||
const [fileUrl, setFileUrl] = useState(4);
|
||||
const [numPages, setNumPages] = useState(null);
|
||||
const [fileList, setFileList] = useState(null);
|
||||
const [edit, setEdit] = useState(false);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
getRequirementDetail(id).then(data => {
|
||||
if (data) {
|
||||
setRequireForm(data);
|
||||
if (data.achievementList) {
|
||||
for (const item of data.achievementList) {
|
||||
item.name = item.fileName;
|
||||
item.size = item.fileSize;
|
||||
item.uid = "rc-upload" + item.id
|
||||
}
|
||||
setFileList(data.achievementList);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, [id, edit]);
|
||||
|
||||
function editItem() {
|
||||
history.push(`/requirement/requireEdit/${id}`);
|
||||
}
|
||||
|
||||
function deletItem() {
|
||||
DelModal(() => {
|
||||
deleteRequirement(id).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification("删除成功");
|
||||
history.go(-1);
|
||||
} else {
|
||||
showNotification("删除失败");
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function downFile(item) {
|
||||
let url = httpUrl + '/busiAttachments/download/' + item.id;
|
||||
window.open(url);
|
||||
}
|
||||
|
||||
function pdfShow(e) {
|
||||
setFileType(e.fileType);
|
||||
if (e.fileType === 1 || e.fileType === 2 || e.fileType === 3) {
|
||||
// pdf||video||img
|
||||
setVisible(true);
|
||||
setFileUrl(httpUrl + '/busiAttachments/view/' + e.id);
|
||||
}
|
||||
}
|
||||
|
||||
function onDocumentLoadSuccess({ numPages }) {
|
||||
setNumPages(numPages);
|
||||
}
|
||||
|
||||
// 上传附件后得到的文件数组
|
||||
function UploadFunc(fileList) {
|
||||
setFileList(fileList);
|
||||
}
|
||||
|
||||
function uploadAchievement() {
|
||||
let files = [];
|
||||
let filestype = [];
|
||||
for (const item of fileList) {
|
||||
files.push(item.id || item.response.data.id);
|
||||
filestype.push(item.fileType || item.response.data.fileType);
|
||||
}
|
||||
let data = {
|
||||
id,
|
||||
achievements: files.toString(),
|
||||
// createUserAccount: sessionStorage.getItem('SET_Account'),//用户信息
|
||||
// createUserName: sessionStorage.getItem('SET_NAME'),
|
||||
status: "2"
|
||||
}
|
||||
updateRequirement(data).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification('更新成果文件成功!');
|
||||
setEdit(!edit);
|
||||
setVisibleAchieve(false);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox">
|
||||
<div className="center-content">
|
||||
<div className="centerScreen">
|
||||
<div className="center-left-but">{requireForm.title}</div>
|
||||
{
|
||||
<div className="center-right-but">
|
||||
{
|
||||
// (role||operator||needsForm.assignedUserLogin==userid||needsForm.createUserAccount==userid)&&(needsForm.status==1||needsForm.status==2||needsForm.status==7||needsForm.status==5)
|
||||
((current_user.admin || current_user.operator || requireForm.assignedUserLogin == current_user.login || requireForm.createUserAccount == current_user.login)
|
||||
&& (requireForm.status == 1 || requireForm.status == 2 || requireForm.status == 7 || requireForm.status == 5)) &&
|
||||
<Button className="mr15 font-12" size="small" type="primary" onClick={() => { setVisibleAchieve(true) }}>上传成果</Button>
|
||||
}
|
||||
|
||||
{
|
||||
requireForm.createUserAccount === current_user.login &&
|
||||
<React.Fragment>
|
||||
<span onClick={editItem}>编辑</span>
|
||||
<span onClick={deletItem}>删除</span>
|
||||
</React.Fragment>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
|
||||
<Descriptions className="item-content" column={1}>
|
||||
<Descriptions.Item label="需求类别">{requireForm.typeName}</Descriptions.Item>
|
||||
<Descriptions.Item label="标签">
|
||||
{
|
||||
requireForm.tag && requireForm.tag.map(itemx => {
|
||||
return <span className="list-tag" key={itemx + 'ax'}>{itemx}</span>
|
||||
})
|
||||
}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="指派人员">{requireForm.assignedUserName}</Descriptions.Item>
|
||||
<Descriptions.Item label="结束时间">{requireForm.endTime}</Descriptions.Item>
|
||||
<Descriptions.Item label="需求描述">{requireForm.remark}</Descriptions.Item>
|
||||
<Descriptions.Item label="需求文件" className="file-list-item">
|
||||
{
|
||||
requireForm.attachmentList && requireForm.attachmentList.map(item => {
|
||||
return <div className="file-list-box" key={item.id + 'down'}>
|
||||
<p onClick={() => { pdfShow(item) }}>{item.fileName}</p>
|
||||
<span className="downP" onClick={() => { downFile(item) }}>下载</span>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
visible={visible}
|
||||
maskClosable={true}
|
||||
closable={true}
|
||||
footer={null}
|
||||
onCancel={() => { setVisible(false) }}
|
||||
className="file-modal"
|
||||
>
|
||||
{
|
||||
fileType === 3 && <div >
|
||||
<img className="show-img" src={fileUrl} alt="" />
|
||||
</div>
|
||||
}
|
||||
{
|
||||
fileType === 2 && <div>
|
||||
<video src={fileUrl} style={{ width: '100%' }} controls="controls">您的浏览器不支持 video 标签。</video>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
fileType === 1 && <div className="pdf-box">
|
||||
{
|
||||
<Document
|
||||
file={fileUrl}
|
||||
onLoadSuccess={onDocumentLoadSuccess}
|
||||
>
|
||||
{new Array(numPages).fill("").map((item, index) => {
|
||||
return (
|
||||
<Page
|
||||
loading=""
|
||||
noData=""
|
||||
key={index}
|
||||
pageNumber={index + 1}
|
||||
renderTextLayer={true}
|
||||
width={750}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Document>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
visible={visibleAchieve}
|
||||
maskClosable={true}
|
||||
closable={true}
|
||||
onCancel={() => { setVisibleAchieve(false) }}
|
||||
onOk={uploadAchievement}
|
||||
className="upload-modal"
|
||||
>
|
||||
<Upload
|
||||
className="commentStyle"
|
||||
load={UploadFunc}
|
||||
size={100}
|
||||
showNotification={showNotification}
|
||||
actionUrl={httpUrl}
|
||||
fileList={fileList}
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// 内容详情
|
||||
.item-content {
|
||||
padding: 10px 10px 0 30px;
|
||||
}
|
||||
.ant-descriptions-item-label {
|
||||
width: 5em;
|
||||
margin-right: 5px;
|
||||
color: rgba(0, 0, 0, 0.65);
|
||||
text-align: right;
|
||||
}
|
||||
.ant-descriptions-item-content {
|
||||
color: rgba(0, 0, 0, 1);
|
||||
}
|
||||
.file-list-item > span {
|
||||
vertical-align: top;
|
||||
}
|
||||
.file-list-box {
|
||||
width: 600px;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
p:hover {
|
||||
cursor: pointer;
|
||||
color: #0089ff;
|
||||
}
|
||||
.downP {
|
||||
color: #0089ff;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.upload-modal{
|
||||
width: 800px !important;
|
||||
.commentStyle{
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
import React, { forwardRef, useCallback, useEffect, useState } from 'react';
|
||||
import { Form, Input, Select, Button, DatePicker } from 'antd';
|
||||
import moment from 'moment';
|
||||
import Upload from '../../components/Upload';
|
||||
import { httpUrl } from '../../../fetch';
|
||||
import { getDictionary, getRequirementDetail, addRequirement, updateRequirement } from '../api';
|
||||
import './index.scss';
|
||||
|
||||
const Option = Select.Option;
|
||||
const { TextArea } = Input;
|
||||
const format = "YYYY-MM-DD HH:mm:ss";
|
||||
|
||||
export default Form.create()(forwardRef(({current_user, form, showNotification, match, history }, ref) => {
|
||||
|
||||
const [requireType, setRequireType] = useState([]);
|
||||
const [tagType, setTagType] = useState([]);
|
||||
const [fileList, setFileList] = useState(null);
|
||||
const [typeCode, setTypeCode] = useState('');
|
||||
const [typeName, setTypeName] = useState('');
|
||||
|
||||
const id = match.params.requireId;
|
||||
const { getFieldDecorator, validateFields, setFieldsValue, } = form;
|
||||
|
||||
useEffect(() => {
|
||||
id && getRequirementDetail(id).then(data => {
|
||||
const formValue = {
|
||||
title: data.title,
|
||||
attachments: data.attachments,
|
||||
// typeCode: data.typeCode, //为使用select labelInValue,在代码中初始化值
|
||||
endTime: moment(data.endTime),
|
||||
tag: data.tag,
|
||||
remark: data.remark
|
||||
};
|
||||
setFieldsValue(formValue);
|
||||
setTypeName(data.typeName);
|
||||
setTypeCode(data.typeCode)
|
||||
if (data.attachmentList.length) {
|
||||
for (const item of data.attachmentList) {
|
||||
item.name = item.fileName;
|
||||
item.size = item.fileSize;
|
||||
item.uid = "rc-upload" + item.id
|
||||
}
|
||||
setFileList(data.attachmentList);
|
||||
}
|
||||
})
|
||||
}, [id]);
|
||||
|
||||
// 加载选项数据
|
||||
useEffect(() => {
|
||||
getDictionary('requirement_type').then((res) => {
|
||||
setRequireType(res.data);
|
||||
});
|
||||
getDictionary("tag_type").then((res) => {
|
||||
setTagType(res.data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
|
||||
// 上传附件后得到的文件数组
|
||||
function UploadFunc(fileList) {
|
||||
setFileList(fileList);
|
||||
let files = [];
|
||||
for (const item of fileList) {
|
||||
files.push(item.id || item.response.data.id);
|
||||
}
|
||||
setFieldsValue({
|
||||
attachments: files.join()
|
||||
});
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, initialValue) => (
|
||||
<Form.Item label={label}>
|
||||
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
xs: { span: 12 },
|
||||
sm: { span: 4 },
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 12 },
|
||||
sm: { span: 16 },
|
||||
},
|
||||
};
|
||||
|
||||
const tailFormItemLayout = {
|
||||
wrapperCol: {
|
||||
xs: {
|
||||
span: 20,
|
||||
offset: 4,
|
||||
},
|
||||
sm: {
|
||||
span: 20,
|
||||
offset: 4,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// 修改
|
||||
function saveItem() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
let params = {
|
||||
...values,
|
||||
createUserAccount:current_user.login|| sessionStorage.getItem("SET_Account"), //用户信息
|
||||
createUserName:current_user.username|| sessionStorage.getItem("SET_NAME"), //模拟时使用莫胜吕
|
||||
typeName,
|
||||
typeCode,
|
||||
status: 0, //状态
|
||||
};
|
||||
params.tag = params.tag.join();
|
||||
params.endTime = params.endTime.format(format);
|
||||
if (id) {
|
||||
// 编辑
|
||||
params.id = id;
|
||||
updateRequirement(params).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification("需求更新成功!");
|
||||
history.go(-1);
|
||||
} else {
|
||||
showNotification(res.message);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// 新增
|
||||
addRequirement(params).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification("需求新增成功!");
|
||||
history.go(-1);
|
||||
} else {
|
||||
showNotification(res.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function changeTypeName(value) {
|
||||
setTypeCode(value.key);
|
||||
setTypeName(value.label);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox">
|
||||
<div className="center-content">
|
||||
|
||||
<div className="centerScreen">
|
||||
<div className="center-left-but">{id ? '修改' : '新增'}需求</div>
|
||||
</div>
|
||||
<Form className="achieve-form" {...formItemLayout}>
|
||||
{helper(
|
||||
"需求名称:",
|
||||
"title",
|
||||
[{ required: true, message: "请输入需求名称" }],
|
||||
<Input
|
||||
className="edit-input"
|
||||
placeholder="请输入需求名称"
|
||||
/>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"需求类型:",
|
||||
"typeCode",
|
||||
[{ required: true, message: "请选择需求类别" }],
|
||||
<Select placeholder="请选择需求类别"
|
||||
className="edit-input"
|
||||
labelInValue
|
||||
onChange={changeTypeName}
|
||||
>
|
||||
{
|
||||
requireType.map(item => {
|
||||
return <Option key={item.id + ''} value={item.id + ''}>{item.dicItemName}</Option>
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
, { key: typeCode, label: typeName })}
|
||||
|
||||
{helper(
|
||||
"结束时间:",
|
||||
"endTime",
|
||||
[{ required: true, message: "请输入结束时间" }],
|
||||
<DatePicker
|
||||
showTime
|
||||
format={format}
|
||||
placeholder="请输入结束时间"
|
||||
/>
|
||||
)}
|
||||
|
||||
<Form.Item label={"需求文件:"} required={true}>
|
||||
<Upload
|
||||
className="commentStyle"
|
||||
load={UploadFunc}
|
||||
size={100}
|
||||
showNotification={showNotification}
|
||||
actionUrl={httpUrl}
|
||||
fileList={fileList}
|
||||
/>
|
||||
|
||||
{/* 用一个隐藏的input实现上传文件的必填校验 */}
|
||||
{getFieldDecorator('attachments', {
|
||||
rules: [{ required: true, message: "请上传需求文件" }], validateFirst: true
|
||||
})(<Input style={{ display: 'none' }} />)}
|
||||
</Form.Item>
|
||||
|
||||
{helper(
|
||||
"标签:",
|
||||
"tag",
|
||||
[{ required: true, message: "请选择需求标签" }],
|
||||
<Select
|
||||
placeholder="请选择需求标签"
|
||||
className="edit-input"
|
||||
mode="tags"
|
||||
tokenSeparators={[',']}
|
||||
>
|
||||
{
|
||||
tagType.map(item => {
|
||||
return <Option key={item.dicItemName}>{item.dicItemName}</Option>
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"需求描述:",
|
||||
"remark",
|
||||
[{ required: true, message: "请输入需求描述" }],
|
||||
<TextArea
|
||||
placeholder="请输入需求描述"
|
||||
autoSize={{ minRows: 3, maxRows: 5 }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<Form.Item {...tailFormItemLayout}>
|
||||
<Button className="mr20" type={"primary"} onClick={saveItem}>保存</Button>
|
||||
<Button onClick={() => { history.go(-1) }}>取消</Button>
|
||||
</Form.Item>
|
||||
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
.achieve-form{
|
||||
padding:24px 40px 0px 40px;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Pagination, Button } from 'antd';
|
||||
import ChooseNav from '../../components/chooseNav';
|
||||
import ItemList from '../../components/itemList';
|
||||
import { getDictionary, getRequirementList } from '../api';
|
||||
|
||||
export default (props) => {
|
||||
const { current_user } = props;
|
||||
// console.log(current_user);
|
||||
|
||||
const [requirementType, setrequirementType] = useState([]); //需求类别选项数组
|
||||
const [requirementStatusArr, setrequirementStatusArr] = useState([]); //需求状态选项数组
|
||||
const [requirementTypeName, setRequirementTypeName] = useState(''); //当前需求类别
|
||||
const [requirementStatus, setRequirementStatus] = useState(''); //当前需求状态
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [requirementList, setRequirementList] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
getDictionary('requirement_type').then(res => {
|
||||
if (res && res.data) setrequirementType(res.data);
|
||||
});
|
||||
getDictionary('requirement_status').then(res => {
|
||||
if (res && res.data) setrequirementStatusArr(res.data);
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
tag: null,
|
||||
status: requirementStatus || null,
|
||||
typeName: requirementTypeName || null,
|
||||
queryType: 'all',
|
||||
curPage,
|
||||
pageSize: 10
|
||||
};
|
||||
getRequirementList(params).then(data => {
|
||||
if (data && data.rows) {
|
||||
setRequirementList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
})
|
||||
}, [requirementTypeName, requirementStatus, curPage]);
|
||||
|
||||
function changeOptionId(option, type) {
|
||||
if (type === 'requirement_type') {
|
||||
setRequirementTypeName(option.dicItemName);
|
||||
setCurPage(1);
|
||||
} else if (type === 'requirement_status') {
|
||||
setRequirementStatus(option.dicItemCode);
|
||||
setCurPage(1);
|
||||
}
|
||||
}
|
||||
|
||||
function goRequirementMine() {
|
||||
props.history.push('/requirement/requireMine');
|
||||
}
|
||||
function goAdd() {
|
||||
props.history.push("/requirement/requireAdd");
|
||||
}
|
||||
|
||||
function achiveClick(id) {
|
||||
props.history.push(`/requirement/requireDetail/${id}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="centerbox">
|
||||
<div className="nav-content">
|
||||
<ChooseNav
|
||||
key={'requirement_type'}
|
||||
type={'requirement_type'}
|
||||
title={'需求类别'}
|
||||
options={requirementType}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
|
||||
<ChooseNav
|
||||
key={'requirement_status'}
|
||||
type={'requirement_status'}
|
||||
title={'需求状态'}
|
||||
options={requirementStatusArr}
|
||||
changeOptionId={changeOptionId}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="center-content">
|
||||
<div className="centerScreen">
|
||||
<div className="center-left-but">需求大厅</div>
|
||||
{
|
||||
current_user.login &&
|
||||
<div className="center-right-but">
|
||||
<Button className="mr15 font-12" size="small" type="primary" onClick={goRequirementMine}>我的需求</Button>
|
||||
<Button className="mr20 font-12" size="small" type="primary" onClick={goAdd}><i className="iconfont icon-zaibianji font-12 mr3"></i>发布需求</Button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<ItemList
|
||||
list={requirementList}
|
||||
itemClick={achiveClick}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="edu-txt-center ">
|
||||
<Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
showTotal={total => `共 ${total} 条`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
import React, { useEffect, forwardRef, useCallback, useState } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { Form, Radio, Input, Select, Pagination, Table, Button, Modal } from 'antd';
|
||||
import DelModal from '../../components/DelModal';
|
||||
import { deleteRequirement, getRequirementList, getAllUsers, updateRequirement } from '../api';
|
||||
|
||||
const Option = Select.Option;
|
||||
const { TextArea } = Input;
|
||||
|
||||
const statusArr = ['待审核', '进行中', '成果验收中', '完成', '审核未通过', '延期', '其他', '验收未通过'];
|
||||
const chooseStatusArr = ['待审核', '进行中', '成果验收中', '完成', '审核未通过', '延期', '全部'];
|
||||
const statusColor = ['#f8c753', '#67c23a', '#67c23a', '#67c23a', '#F56C6C', '#f8c753', '#f8c753', '#F56C6C'];
|
||||
|
||||
export default Form.create()(forwardRef(({ form, showNotification, match, history }, ref) => {
|
||||
const [requirementList, setRequirementList] = useState([]);
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [status, setStatus] = useState(6);
|
||||
const [checkVisible, setCheckVisible] = useState(false);
|
||||
const [checkStatus, setCheckStatus] = useState(1);
|
||||
const [acceptVisible, setAcceptVisible] = useState(false);
|
||||
const [currentId, setCurrentId] = useState('');
|
||||
const [allUsers, setAllUsers] = useState([]);
|
||||
|
||||
|
||||
const { getFieldDecorator, validateFields, } = form;
|
||||
|
||||
useEffect(() => {
|
||||
getRequireList();
|
||||
}, [curPage, status]);
|
||||
|
||||
useEffect(() => {
|
||||
if (checkVisible) {
|
||||
getAllUsers().then(res => {
|
||||
if (res.code === '1') {
|
||||
setAllUsers(res.data);
|
||||
} else {
|
||||
showNotification(res.message);
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [checkVisible]);
|
||||
|
||||
function getRequireList() {
|
||||
let searchStaus = "";
|
||||
if (status !== 6) {
|
||||
searchStaus = status;
|
||||
}
|
||||
const params = {
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
status: searchStaus,
|
||||
tag: "",
|
||||
title: "",
|
||||
typeName: "",
|
||||
currentUser: "",
|
||||
queryType: "all" //all:所有 my:我创建的 tome:指派给我的
|
||||
};
|
||||
getRequirementList(params).then(data => {
|
||||
if (data) {
|
||||
for (const item of data.rows) {
|
||||
item.createUserName = item.createUser.nickname ? item.createUser.nickname : item.createUser.login;
|
||||
}
|
||||
setRequirementList(data.rows);
|
||||
setTotal(data.total);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function detailItem(id) {
|
||||
history.push(`/requirement/requireDetail/${id}`);
|
||||
}
|
||||
|
||||
function editItem(id) {
|
||||
history.push(`/requirement/requireEdit/${id}`);
|
||||
}
|
||||
|
||||
function deletItem(id) {
|
||||
DelModal(() => {
|
||||
deleteRequirement(id).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification("删除成功");
|
||||
getRequireList();
|
||||
} else {
|
||||
showNotification("删除失败");
|
||||
}
|
||||
})
|
||||
}, '此操作将删除该记录, 是否继续?');
|
||||
}
|
||||
|
||||
// 审核
|
||||
function checkItem() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
let params = {
|
||||
id: currentId,
|
||||
status: checkStatus, //状态
|
||||
assignedUserLogin: values.vertifyUserAccount ? values.vertifyUserAccount.key : '',
|
||||
assignedUserName: values.vertifyUserAccount ? values.vertifyUserAccount.label : '',
|
||||
vertifyUserAccount: values.vertifyUserAccount ? values.vertifyUserAccount.key : '',
|
||||
vertifyUserName: values.vertifyUserAccount ? values.vertifyUserAccount.label : '',
|
||||
vertifyComments: values.vertifyComments,
|
||||
};
|
||||
console.log(params);
|
||||
updateRequirement(params).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification("操作成功!");
|
||||
setCheckVisible(false);
|
||||
getRequireList();
|
||||
} else {
|
||||
showNotification(res.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 验收
|
||||
function acceptItem() {
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
let params = {
|
||||
status: values.status,
|
||||
id: currentId,
|
||||
checkComments: values.checkComments,
|
||||
};
|
||||
console.log(params);
|
||||
updateRequirement(params).then(res => {
|
||||
if (res.code === '1') {
|
||||
showNotification("操作成功!");
|
||||
setAcceptVisible(false);
|
||||
getRequireList();
|
||||
} else {
|
||||
showNotification(res.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '需求标题',
|
||||
dataIndex: 'title',
|
||||
key: 'title',
|
||||
width: '20%',
|
||||
},
|
||||
{
|
||||
title: '类型',
|
||||
dataIndex: 'typeName',
|
||||
key: 'typeName',
|
||||
},
|
||||
{
|
||||
title: '创建人',
|
||||
dataIndex: 'createUserName',
|
||||
key: 'createUserName',
|
||||
},
|
||||
{
|
||||
title: '指派人',
|
||||
key: 'assignedUserName',
|
||||
dataIndex: 'assignedUserName',
|
||||
},
|
||||
{
|
||||
title: '创建时间',
|
||||
key: 'createTime',
|
||||
dataIndex: 'createTime',
|
||||
},
|
||||
{
|
||||
title: '结束时间',
|
||||
key: 'endTime',
|
||||
dataIndex: 'endTime',
|
||||
},
|
||||
{
|
||||
title: '状态',
|
||||
key: 'status',
|
||||
dataIndex: 'status',
|
||||
render: (text, record) => {
|
||||
return <span style={{ color: statusColor[text] }}>{statusArr[text]}</span>
|
||||
}
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<Button className="mr5 font-12" type="primary" size="small" onClick={() => { editItem(record.id) }}><i className="iconfont icon-zaibianji font-15 mr3"></i></Button>
|
||||
<Button className="mr5 font-12" type="danger" size="small" onClick={() => { deletItem(record.id) }}><i className="iconfont icon-shanchu font-15 "></i></Button>
|
||||
<Button className="mr5 font-12" type="info" size="small" onClick={() => { detailItem(record.id) }}>详情</Button>
|
||||
{record.status === '0' && <Button className="mr5 font-12" type="primary" size="small" onClick={() => { setCurrentId(record.id); setCheckVisible(true); }}>审核</Button>}
|
||||
{record.status === '2' && <Button className="mr5 font-12" type="success" size="small" onClick={() => { setCurrentId(record.id); setAcceptVisible(true) }}>验收成果</Button>}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, initialValue) => (
|
||||
<Form.Item label={label}>
|
||||
{getFieldDecorator(name, { rules, initialValue, validateFirst: true, })(widget)}
|
||||
</Form.Item>
|
||||
), []);
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
xs: { span: 12 },
|
||||
sm: { span: 6 },
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 12 },
|
||||
sm: { span: 18 },
|
||||
},
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
|
||||
<div className="choose-status">
|
||||
{
|
||||
chooseStatusArr.map((item, i) => {
|
||||
return <Button className={classnames({ mr10: true, active: status === i })} type="dashed" key={i} onClick={() => { setStatus(i) }}> {item}</Button>
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
||||
<Table
|
||||
rowKey={(row) => row.id}
|
||||
dataSource={requirementList}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
/>
|
||||
|
||||
<div className="edu-txt-center mt10">
|
||||
<Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Modal
|
||||
title="需求审核"
|
||||
visible={checkVisible}
|
||||
onOk={checkItem}
|
||||
onCancel={() => { setCheckVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
|
||||
{checkVisible && <Form {...formItemLayout}>
|
||||
<Form.Item label="审批结果:">
|
||||
<Radio.Group value={checkStatus} onChange={(e) => { setCheckStatus(e.target.value) }}>
|
||||
<Radio className="columsRadio" value={1}>
|
||||
同意
|
||||
</Radio>
|
||||
<Radio className="columsRadio" value={4}>
|
||||
拒绝
|
||||
</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
|
||||
{helper(
|
||||
"指派用户:",
|
||||
"vertifyUserAccount",
|
||||
[{ required: checkStatus === 1, message: "请指派用户" }],
|
||||
<Select placeholder="请指派用户"
|
||||
className="edit-input"
|
||||
showSearch
|
||||
labelInValue
|
||||
disabled={checkStatus === 4}
|
||||
filterOption={(input, option) =>
|
||||
option.props && option.props.children && (option.props.children.indexOf(input) > -1 || option.props.children.toLowerCase().indexOf(input.toLowerCase()) > -1)
|
||||
}
|
||||
>
|
||||
{
|
||||
allUsers.map((item, i) => {
|
||||
return <Option key={item.id} value={item.login}>{item.nickName}</Option>
|
||||
})
|
||||
}
|
||||
</Select>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"审核意见:",
|
||||
"vertifyComments",
|
||||
[{ required: true, message: "请输入审核意见" }],
|
||||
<TextArea
|
||||
className="edit-input"
|
||||
placeholder="请输入审核意见"
|
||||
/>
|
||||
)}
|
||||
</Form>}
|
||||
</Modal>
|
||||
|
||||
|
||||
<Modal
|
||||
title="验收成果"
|
||||
visible={acceptVisible}
|
||||
onOk={acceptItem}
|
||||
onCancel={() => { setAcceptVisible(false) }}
|
||||
className="form-edit-modal"
|
||||
>
|
||||
|
||||
{acceptVisible && <Form {...formItemLayout}>
|
||||
{helper(
|
||||
"验收结果:",
|
||||
"status",
|
||||
[{ required: true, message: "请选择验收结果" }],
|
||||
<Radio.Group>
|
||||
<Radio className="columsRadio" value={3}>
|
||||
同意
|
||||
</Radio>
|
||||
<Radio className="columsRadio" value={7}>
|
||||
拒绝
|
||||
</Radio>
|
||||
</Radio.Group>
|
||||
)}
|
||||
|
||||
{helper(
|
||||
"验收意见:",
|
||||
"checkComments",
|
||||
[],
|
||||
<TextArea
|
||||
className="edit-input"
|
||||
placeholder="请输入验收意见"
|
||||
/>
|
||||
)}
|
||||
</Form>}
|
||||
|
||||
</Modal>
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
||||
)
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
import React from 'react';
|
||||
import { Tabs } from 'antd';
|
||||
import AllRequire from './allRequire';
|
||||
import MyRequire from './myRequire';
|
||||
import './index.scss';
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
export default (props) => {
|
||||
|
||||
return (
|
||||
<div className="centerbox">
|
||||
|
||||
<Tabs className="tabs-style" type="card">
|
||||
<TabPane tab="全部需求" key="1">
|
||||
<AllRequire {...props}/>
|
||||
</TabPane>
|
||||
|
||||
<TabPane tab="我的需求" key="2">
|
||||
<MyRequire {...props}/>
|
||||
</TabPane>
|
||||
</Tabs>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
// Tabs
|
||||
.tabs-style{
|
||||
background: #fff;
|
||||
border: 1px solid #dcdfe6;
|
||||
-webkit-box-shadow: 0 2px 4px 0 rgba(0,0,0,.12), 0 0 6px 0 rgba(0,0,0,.04);
|
||||
box-shadow: 0 2px 4px 0 rgba(0,0,0,.12), 0 0 6px 0 rgba(0,0,0,.04);
|
||||
padding-bottom: 1vw;
|
||||
.ant-tabs-tab{
|
||||
margin: 0 !important;
|
||||
}
|
||||
.ant-tabs-tab{
|
||||
border-top:0 !important;
|
||||
border-left:0 !important;
|
||||
border-radius:0 !important;
|
||||
}
|
||||
.ant-tabs-nav .ant-tabs-tab{
|
||||
padding:19px 0px;
|
||||
margin-right: 40px;
|
||||
}
|
||||
.ant-tabs-ink-bar{
|
||||
width:25px!important;
|
||||
bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.choose-status{
|
||||
padding: 1em;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.ant-btn-info{
|
||||
color: #fff;
|
||||
background-color: #909399;
|
||||
border-color: #909399;
|
||||
}
|
||||
|
||||
.ant-btn-success{
|
||||
color: #fff;
|
||||
background-color: #67c23a;
|
||||
border-color: #67c23a;
|
||||
}
|
||||
|
||||
.mt10{
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.form-edit-modal{
|
||||
.ant-col{
|
||||
display: inline-block;
|
||||
}
|
||||
.edit-input{
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { Pagination, Button } from 'antd';
|
||||
import ItemList from '../../components/itemList';
|
||||
import DelModal from '../../components/DelModal';
|
||||
import { deleteRequirement, getRequirementList } from '../api';
|
||||
|
||||
export default (props) => {
|
||||
const [requirementList, setRequirementList] = useState([]);
|
||||
const [curPage, setCurPage] = useState(1);
|
||||
const [total, setTotal] = useState(0);
|
||||
// const [queryType, setQueryType] = useState("my");
|
||||
const [queryType, setQueryType] = useState("all");
|
||||
|
||||
useEffect(() => {
|
||||
getRequireList();
|
||||
}, [curPage, queryType]);
|
||||
|
||||
function getRequireList() {
|
||||
const params = {
|
||||
curPage,
|
||||
pageSize: 10,
|
||||
status: "",
|
||||
tag: "",
|
||||
title: "",
|
||||
typeName: "",
|
||||
currentUser: "",
|
||||
queryType, //all:所有 my:我创建的 tome:指派给我的
|
||||
};
|
||||
getRequirementList(params).then(data => {
|
||||
setRequirementList(data.rows);
|
||||
setTotal(data.total);
|
||||
})
|
||||
}
|
||||
|
||||
function detailItem(id) {
|
||||
props.history.push(`/requirement/requireDetail/${id}`);
|
||||
}
|
||||
|
||||
function editItem(id) {
|
||||
props.history.push(`/requirement/requireEdit/${id}`);
|
||||
}
|
||||
|
||||
function deletItem(id) {
|
||||
DelModal(() => {
|
||||
deleteRequirement(id).then(res => {
|
||||
if (res.code === '1') {
|
||||
props.showNotification("删除成功");
|
||||
getRequireList();
|
||||
} else {
|
||||
props.showNotification("删除失败");
|
||||
}
|
||||
})
|
||||
}, '此操作将删除该记录, 是否继续?');
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="choose-status">
|
||||
<Button className={classnames({ mr10: true, active: queryType === "my" })} type="dashed" key="my" onClick={() => { setQueryType("my") }}>我创建的</Button>
|
||||
<Button className={classnames({ mr10: true, active: queryType === "tome" })} type="dashed" key="tome" onClick={() => { setQueryType("tome") }}> 指派给我的 </Button>
|
||||
</div>
|
||||
<ItemList
|
||||
list={requirementList}
|
||||
itemClick={detailItem}
|
||||
deletItem={queryType === "my" && deletItem}
|
||||
editItem={queryType === "my" && editItem}
|
||||
activeByStatus={queryType === "my"}
|
||||
/>
|
||||
<div className="edu-txt-center mt10">
|
||||
<Pagination
|
||||
showQuickJumper
|
||||
onChange={(page) => { setCurPage(page) }}
|
||||
current={curPage}
|
||||
total={total}
|
||||
/>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
|
@ -29,7 +29,6 @@ service.interceptors.request.use(config => {
|
|||
});
|
||||
// respone拦截器
|
||||
service.interceptors.response.use(
|
||||
|
||||
response => {
|
||||
/**
|
||||
* 下面的注释为通过response自定义code来标示请求状态,当code返回如下情况为权限有问题,登出并返回到登录页
|
||||
|
|
|
|||
Loading…
Reference in New Issue