Merge branch 'master-单一公告时间验证小于3天填说明' into 'release_20220826'

8.26 单一公告时间验证小于3天填说明

See merge request eshop/fe_service_ebtp_frontend!257
This commit is contained in:
周建龙
2022-08-26 21:27:26 +08:00
5 changed files with 342 additions and 7 deletions

View File

@ -13,6 +13,7 @@ import {
Radio,
Row,
Spin, Tabs,
Typography,
Upload
} from "antd"
import '@/assets/ld_style.less'
@ -25,7 +26,7 @@ import {
creatNotice,
getChooseRoom,
getPackageAndSupplierList,
chooseSupplier, deleteSupplier, updateSupplierUser, checkConflict
chooseSupplier, deleteSupplier, updateSupplierUser, saveAnno
} from '../service'
import moment from "moment";
import TabPane from "@ant-design/pro-card/lib/components/TabPane";
@ -46,6 +47,8 @@ import BraftText from "@/components/richText/wang"
import RiskPrevention from "@/utils/RiskPrevention"
import Dating from '@/images/招标公告/dating.jpg';
import './style.less';
import TextArea from "antd/lib/input/TextArea"
import RiskPreventionSoft from "@/utils/RiskPreventionSoft"
interface BiddingInvitation {
type: string;
@ -104,6 +107,11 @@ const BiddingInvitation: React.FC<BiddingInvitation> = (props) => {
const [riskVisible, setRiskVisible] = useState<boolean>(false);//风控弹窗 2021.9.7 zhoujianlong
const [riskData, setRiskData] = useState<any[]>([]);//风控数据 2021.9.7 zhoujianlong
const WebofficeRef = useRef<Weboffice>(null);
const [memoVisible, setMemoVisible] = useState<boolean>(false);//说明弹窗
/*weboffic end*/
const [UploadMemoID, setUploadMemoID] = useState<any>("empty"); //upload 业务id
const { Text } = Typography;
const onRef = (ref) => {
/* this.child= ref;*/
}
@ -182,6 +190,7 @@ const BiddingInvitation: React.FC<BiddingInvitation> = (props) => {
setDocSaveBtn("compact");
setDocBtnName("新建");
setSping(false);
setUploadMemoID("");
}
});
} else if (type == "edit") {//==========================================================编辑
@ -211,6 +220,7 @@ const BiddingInvitation: React.FC<BiddingInvitation> = (props) => {
"openhallId": data.openhallId,
"annoTitle": data.annoTitle,
"sectionIds": defPak,
"reasonMemo": data.reasonMemo,
});
echoSet(data.contentWithStyle);
setUploadID(data.attDatasetId);
@ -220,6 +230,7 @@ const BiddingInvitation: React.FC<BiddingInvitation> = (props) => {
setDocReadOnly("false");
setDocSaveBtn("compact");
setDocBtnName("编辑");
setUploadMemoID(data.reasonMemoAttrId);
}
});
@ -256,6 +267,7 @@ const BiddingInvitation: React.FC<BiddingInvitation> = (props) => {
setDocReadOnly("ture");
setDocSaveBtn("none");
setDocBtnName("查看");
setUploadMemoID(data.reasonMemoAttrId);
}
});
}
@ -318,7 +330,15 @@ const BiddingInvitation: React.FC<BiddingInvitation> = (props) => {
} else if (TpPackageName == "谈判") {
if (form.getFieldValue("docStartTime") < moment().startOf('day')) {
message.warn('采购文件获取开始时间需晚于当前时间');
} else if (moment(form.getFieldValue("docEndTime")).startOf('day').diff(moment(form.getFieldValue("docStartTime")).startOf('day'), "days") < 3) {
} else if (proDict == "procurement_mode_6" && moment(form.getFieldValue("docEndTime")).startOf('day').diff(moment(form.getFieldValue("docStartTime")).startOf('day'), "days") < 1) {
message.warn('采购文件获取截止时间需与采购文件获取开始时间间隔不少于1天');
} else if (proDict == "procurement_mode_6" && moment(form.getFieldValue("docEndTime")).startOf('day').diff(moment(form.getFieldValue("docStartTime")).startOf('day'), "days") < 3) {
if(form.getFieldValue("reasonMemo") !== null && form.getFieldValue("reasonMemo") !== undefined){
msg = "true"
}else{
setMemoVisible(true);
}
} else if (moment(form.getFieldValue("docEndTime")).startOf('day').diff(moment(form.getFieldValue("docStartTime")).startOf('day'), "days") < 3) {
message.warn('采购文件获取截止时间需与采购文件获取开始时间间隔不少于3天');
} else if (form.getFieldValue("replyEndTime").format('YYYY-MM-DD HH:mm:ss') < form.getFieldValue("docEndTime").format('YYYY-MM-DD HH:mm:ss')) {
message.warn('应答截止时间需晚于或等于采购文件获取截止时间');
@ -442,12 +462,16 @@ const BiddingInvitation: React.FC<BiddingInvitation> = (props) => {
// "contentHtmlId": WebofficeRef.current!.HTMLfileCode,//html id
"sections": packageMsg,
"medias": "9",
"roomType": "2"
"roomType": "2",
"reasonMemoAttrId": form.getFieldValue("reasonMemoAttrId"),
"reasonMemo": form.getFieldValue("reasonMemo")
}
creatNotice(type, fromData).then(res => {
if (res?.code == 4004 && res?.success == false) { //2021.9.7 zhoujianlong 新增和修改邀请函增加风控
const data = res?.data?.result == undefined ? [] : res?.data?.result
setRiskData(data)
const data = res?.data== undefined ? [] : res?.data
let thisData = [];
thisData.push(data);
setRiskData(thisData)
setRiskVisible(true)
}
if (res.code == 200) {
@ -458,6 +482,48 @@ const BiddingInvitation: React.FC<BiddingInvitation> = (props) => {
setTimeout(() => setSping(false), 1000)
});
}
const saveAfterRisk = () => {
const packageMsg = [];
for (const item of TpPackageId) {//包数据
for (const item1 of form.getFieldValue("sectionIds")) {
if (item.value == item1) {
packageMsg.push({ "bsId": item.value, "bsName": item.label })
}
}
}
setSping(true);
const fromData = {
"id": pkId,
"annoNature": 101,//邀请函
"tpId": tpId,
"csAnnoId": pkId,
"attDatasetId": form.getFieldValue("attDatasetId"),
"openhallTitle": form.getFieldValue("openhallIdTime"),//开标大厅 时间段
"source": 21,//来源1预审公告2预审公示11资审公告12资审公示21邀请函
"annoTitle": form.getFieldValue("annoTitle"),
"contentWithStyle": braftRef.current.getHtml().replace(/<table border="0"/, '<table border="1"'),//富文本正文
"docStartTime": form.getFieldValue("docStartTime").format("yyyy-MM-DD HH:mm:ss"),
"replyEndTime": form.getFieldValue("replyEndTime").format("yyyy-MM-DD HH:mm:ss"),
"openingTime": form.getFieldValue("openingTime").format("yyyy-MM-DD HH:mm:ss"),
"docEndTime": form.getFieldValue("docEndTime").format("yyyy-MM-DD HH:mm:ss"),
"openhallId": form.getFieldValue("openhallId"),
// "contentFileId": WebofficeRef.current!.DocfileCode,//office id
// "contentHtmlId": WebofficeRef.current!.HTMLfileCode,//html id
"sections": packageMsg,
"medias": "9",
"roomType": "2",
"reasonMemoAttrId": form.getFieldValue("reasonMemoAttrId"),
"reasonMemo": form.getFieldValue("reasonMemo")
}
saveAnno(fromData).then(res => {
if (res.code == 200) {
setAnnoId(res?.data);
message.success("成功");
setTabsKeys("2");
}
setTimeout(() => setSping(false), 1000)
});
}
const columns1: ProColumns<{}>[] = [
@ -828,6 +894,45 @@ const BiddingInvitation: React.FC<BiddingInvitation> = (props) => {
</div>
</Card> */}
<BraftText braftRef={braftRef} echo={echo} disabled={editInformation} />
<Modal
destroyOnClose
title="原因说明"
visible={memoVisible}
width={'40%'}
onCancel={() => {
setMemoVisible(false)
}}
onOk={() => {setMemoVisible(false);onFinshInvitation();}}
footer={[
<Button key="back" onClick={() => setMemoVisible(false)}>
</Button>,
<Button key="save" type="primary" onClick={() => {setMemoVisible(false);onFinshInvitation();}}>
</Button>,
]}
centered
>
<Text style={{ color: '#b30000' }}>3</Text>
<Form.Item
label="原因说明"
name="reasonMemo"
rules={[
{ required: true },
{ max: 500, message: '原因说明不能超过500字' },
]}
>
<TextArea rows={4} style={{ resize: 'vertical'}} />
</Form.Item>
<Form.Item
label="附件文件"
name="reasonMemoAttrId"
extra="单个附件最大30MB"
>
{UploadMemoID != "empty" ? <ExtendUpload uploadProps={UploadProps} maxCount={1} bid={UploadMemoID} /> : null}
</Form.Item>
</Modal>
</Form>
{editInformation ? null :
<div style={{ textAlign: "right", marginTop: " 26px" }}>
@ -885,14 +990,16 @@ const BiddingInvitation: React.FC<BiddingInvitation> = (props) => {
</TabPane>
</Tabs>
{/**风控组件 */}
{riskVisible && <RiskPrevention
{riskVisible && <RiskPreventionSoft
modalVisible={riskVisible}
onCancel={() => {
setRiskVisible(false)
setRiskData([])
}}
data={riskData}
onSubmit={() => saveAfterRisk()}
/>}
</Spin>
)

View File

@ -20,6 +20,7 @@ import { btnAuthority } from '@/utils/authority';
import { getApprProcessList } from '@/utils/SeleApprovalProcess/service';
import SeleApprovalProcess from '@/utils/SeleApprovalProcess';
import { checkObjectId } from '@/utils/DownloadUtils';
import ReasonMemo from './ReasonMemo';
/*
* 招标公告开始
@ -50,6 +51,7 @@ const BiddingInvitationList: React.FC<{}> = (props) => {
const [approvalVisible, setApprovalVisible] = useState<boolean>(false);//选择流程弹窗控制参数
const [approvalData, setApprovalData] = useState<any[]>([]);//选择流程数据存储
const [memoVisible, setMemoVisible] = useState<boolean>(false);//说明弹窗
let proName = ''; //名称
let pktittle = '';
let proDict = getProMethod();
@ -129,6 +131,13 @@ const BiddingInvitationList: React.FC<{}> = (props) => {
onClick={() => toEdit(record)}
>
</Button>
<Button
hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])|| record.reasonMemo== null ||record.reasonMemo==undefined}
type="text"
onClick={() => toEditReasonMemo(record,"edit")}
>
</Button>
<Button
hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])}
@ -158,6 +167,13 @@ const BiddingInvitationList: React.FC<{}> = (props) => {
<Button type="text" onClick={() => toRead(record)}>
</Button>
<Button
hidden={ record.reasonMemo== null ||record.reasonMemo==undefined}
type="text"
onClick={() => toEditReasonMemo(record,"read")}
>
</Button>
<Button type="text" key="9" hidden={!record.approvalInstanceId || !checkObjectId(record.id)} onClick={() => toApprovalFor(record)}>
</Button>
@ -176,6 +192,13 @@ const BiddingInvitationList: React.FC<{}> = (props) => {
<Button type="text" onClick={() => toRead(record)}>
</Button>
<Button
hidden={record.reasonMemo== null ||record.reasonMemo==undefined}
type="text"
onClick={() => toEditReasonMemo(record,"read")}
>
</Button>
<Button type="text" key="9" hidden={!record.approvalInstanceId || !checkObjectId(record.id)} onClick={() => toApprovalFor(record)}>
</Button>
@ -190,6 +213,13 @@ const BiddingInvitationList: React.FC<{}> = (props) => {
>
</Button>
<Button
hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])|| record.reasonMemo== null ||record.reasonMemo==undefined}
type="text"
onClick={() => toEditReasonMemo(record,"edit")}
>
</Button>
<Button
hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])}
type="text"
@ -221,6 +251,13 @@ const BiddingInvitationList: React.FC<{}> = (props) => {
<Button type="text" onClick={() => toRead(record)}>
</Button>
<Button
hidden={record.reasonMemo== null ||record.reasonMemo==undefined}
type="text"
onClick={() => toEditReasonMemo(record,"read")}
>
</Button>
<Button type="text" key="9" hidden={!record.approvalInstanceId || !checkObjectId(record.id)} onClick={() => toApprovalFor(record)}>
</Button>
@ -239,6 +276,13 @@ const BiddingInvitationList: React.FC<{}> = (props) => {
<Button type="text" onClick={() => toRead(record)}>
</Button>
<Button
hidden={record.reasonMemo== null ||record.reasonMemo==undefined}
type="text"
onClick={() => toEditReasonMemo(record,"read")}
>
</Button>
<Button type="text" key="9" hidden={!record.approvalInstanceId || !checkObjectId(record.id)} onClick={() => toApprovalFor(record)}>
</Button>
@ -434,7 +478,15 @@ const BiddingInvitationList: React.FC<{}> = (props) => {
}
});
};
/*编辑原因说明*/
const toEditReasonMemo = (props: any,type: any) => {
setPkId(props.id);
setType(type);
setMemoVisible(true);
};
const Proref = useRef<ActionType>();
return (
<div style={{ height: '100%', position: 'relative' }}>
<Spin spinning={spin}>
@ -511,6 +563,16 @@ const BiddingInvitationList: React.FC<{}> = (props) => {
setRefresh(Math.random() + 1)
}} data={approvalData} annoId={recordData?.id} />
) : null}
{memoVisible ? (
<ReasonMemo
modalVisible={memoVisible}
id={pkId}
type={type}
onCancel={() => {
setMemoVisible(false)
}}
/>
) : null}
</div>
);
};

View File

@ -0,0 +1,129 @@
import { Button, Form, message, Modal, Typography, Spin } from 'antd';
import TextArea from 'antd/lib/input/TextArea';
import React, { useEffect, useState } from 'react';
import { GetNoticeMsg, updateMemo } from '../service';
import { UploadProps } from "antd/lib/upload/interface";
import ExtendUpload from '@/utils/ExtendUpload';
/*说明原因 组件*/
type Props = {
id: string;
type: string;
onCancel: () => void;
modalVisible: boolean; //弹窗visible
}
const Index: React.FC<Props> = (props) => {
const { type, id ,modalVisible,onCancel} = props;
const [spinning, setSping] = useState<boolean>(false);//加载遮罩
const [UploadMemoID, setUploadMemoID] = useState<any>("empty"); //upload 业务id
const [disableStatus, setDisableStatus] = useState<boolean>(false);//是否只读
const [form] = Form.useForm();
const { Text } = Typography;
useEffect(() => {
Int();
form.resetFields();//清除form中数据
}, [id, type]);
const UploadProps: UploadProps = {
name: "file",
disabled: disableStatus
}
const layout = {
labelCol: { span: 7 },
wrapperCol: { span: 10 },
};
const Int = async () => {
setSping(true);
await GetNoticeMsg(id).then(res => {
if (res.code == 200) {
const data = res.data;
let defPak = [];
for (const item of data.sections) {
defPak.push(item.bsId);
}
form.setFieldsValue({
"reasonMemo": data.reasonMemo,
"reasonMemoAttrId": data.reasonMemoAttrId,
});
setUploadMemoID(data.reasonMemoAttrId);
}
});
if (type == "read") {//==========================================================查看
setDisableStatus(true);//不可编辑
}
setSping(false);
};
const submit = () => {
setSping(true);
const fromData = {
"id": id,
"reasonMemoAttrId": form.getFieldValue("reasonMemoAttrId"),
"reasonMemo": form.getFieldValue("reasonMemo")
}
updateMemo(fromData).then(res => {
if (res.code == 200) {
message.success("成功");
onCancel();
setSping(false);
} else {
message.success("失败");
}
});
}
return (
<>
<Spin spinning={spinning}>
<Modal
destroyOnClose
visible={modalVisible}
title="原因说明"
width={'40%'}
onCancel={() => {
onCancel();
}}
onOk={() => { submit();}}
footer={[
disableStatus ? null : <Button key="back" onClick={() => onCancel()}>
</Button>,
disableStatus ? null : <Button key="save" type="primary" onClick={() => { submit(); }}>
</Button>,
]}
centered
>
<Text style={{ color: '#b30000' }}>3</Text>
<Form
{...layout}
name="basic"
form={form}
component={false}
>
<Form.Item
label="原因说明"
name="reasonMemo"
rules={[
{ required: true },
{ max: 500, message: '原因说明不能超过500字' },
]}
>
<TextArea rows={4} style={{ resize: 'vertical' }} disabled={disableStatus} />
</Form.Item>
<Form.Item
label="附件文件"
name="reasonMemoAttrId"
extra="单个附件最大30MB"
>
{UploadMemoID != "empty" ? <ExtendUpload uploadProps={UploadProps} maxCount={1} bid={UploadMemoID} /> : null}
</Form.Item>
</Form>
</Modal>
</Spin>
</>
)
}
export default Index;

View File

@ -222,4 +222,22 @@ export async function savePublicData(params: any) {
method: "POST",
data: params
});
}
/*修改说明*/
export async function updateMemo(params?: any) {
return request("/api/biz-service-ebtp-bid/v1/anno/updateMemo", {
method: "post",
data: {
...params
},
})
}
/*风控后的保存公告*/
export async function saveAnno(params?: any) {
return request("/api/biz-service-ebtp-bid/v1/anno/saveAnno", {
method: "post",
data: {
...params
},
})
}

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect, useState } from 'react';
import { Modal, Tag } from 'antd';
import { ExclamationCircleOutlined } from '@ant-design/icons';
import type { ProColumns } from '@ant-design/pro-table';
@ -21,6 +21,7 @@ const modalHeight = window.innerHeight * 96 / 100;
*/
const RiskPreventionSoft: React.FC<RiskPreventionSoftProps> = (props) => {
const { modalVisible, onCancel, onSubmit, data } = props;
const [confirmButtonVisible, setConfirmButtonVisible] = useState<boolean>(true);//是否显示确定按钮
const columns: ProColumns<any[]>[] = [
{
@ -53,6 +54,23 @@ const RiskPreventionSoft: React.FC<RiskPreventionSoftProps> = (props) => {
title: '规则相应内容',
},
];
useEffect(()=>{
setConfirmButtonVisible(getButtonVisible());
},[])
const getButtonVisible = () => {
console.log(data);
for (const risk of data) {
for (const result of risk.result) {
for (const regulationData of result.regulationData) {
if(regulationData.regulationStrategy=="hard"){
return true;
}
}
}
}
return false;
}
return (
<Modal
@ -64,6 +82,7 @@ const RiskPreventionSoft: React.FC<RiskPreventionSoftProps> = (props) => {
bodyStyle={{ maxHeight: modalHeight - 107, overflowY: 'auto', padding: '8px 24px 16px' }}
centered
onCancel={() => onCancel()}
okButtonProps={{hidden: confirmButtonVisible}}
onOk={() => {
onSubmit();
onCancel();