diff --git a/src/assets/zjl_style.less b/src/assets/zjl_style.less index 8a4a611..61fc6f7 100644 --- a/src/assets/zjl_style.less +++ b/src/assets/zjl_style.less @@ -2,10 +2,12 @@ .common { padding: 0px 24px; } + //操作栏颜色 .operation { // margin-right: 8px; } + // .card-title-button .ant-card-head-title { // padding: 10px 0px; // } @@ -17,15 +19,18 @@ color: #b30000; // margin-right: 8px; } + .revenue .ant-tabs-content-holder { margin-top: 0px; } -.revenue .ant-tabs-top > .ant-tabs-nav, -.ant-tabs-bottom > .ant-tabs-nav, -.ant-tabs-top > div > .ant-tabs-nav, -.ant-tabs-bottom > div > .ant-tabs-nav { + +.revenue .ant-tabs-top>.ant-tabs-nav, +.ant-tabs-bottom>.ant-tabs-nav, +.ant-tabs-top>div>.ant-tabs-nav, +.ant-tabs-bottom>div>.ant-tabs-nav { margin: 0; } + // .ant-pro-card-body { // padding: 0; // } @@ -33,17 +38,21 @@ .confirm .ant-pro-table .ant-pro-table-search { padding: 16px 0px 0px 0px; } + .notice .ant-pro-table-list-toolbar-container { padding: 0px 0px 16px; } + .erf-title-flex { display: flex; justify-content: space-between; } + .erf-title-left { height: 32px; line-height: 32px; } + .erf-delete { color: #1890ff !important; background: rgba(0, 0, 0, 0) !important; @@ -55,6 +64,7 @@ font-weight: 600; line-height: 56px; } + .CM_span { text-indent: 2em; // line-height: 24px; @@ -79,10 +89,12 @@ float: left; line-height: 44px; } + //日历组件专用样式 .calendar-dashboard .ant-picker-calendar .ant-picker-panel .ant-picker-body { padding: 0px; } + .calendar-dashboard .ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date { margin: 0 0 1px 1px; padding: 0px 8px 0px; @@ -93,6 +105,7 @@ border-right: 1px solid #f0f0f0; border-radius: 0px } + .calendar-dashboard .ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-content { position: static; width: auto; @@ -102,34 +115,42 @@ color: rgba(0, 0, 0, 0.85); line-height: 1.5715; text-align: center; -} +} + .calendar-dashboard .ant-picker-calendar-full .ant-picker-panel .ant-picker-cell-selected .ant-picker-calendar-date, .calendar-dashboard .ant-picker-calendar-full .ant-picker-panel .ant-picker-cell-selected:hover .ant-picker-calendar-date, .calendar-dashboard .ant-picker-calendar-full .ant-picker-panel .ant-picker-cell-selected .ant-picker-calendar-date-today, .calendar-dashboard .ant-picker-calendar-full .ant-picker-panel .ant-picker-cell-selected:hover .ant-picker-calendar-date-today { background: #fff1f0; } + .calendar-dashboard .ant-picker-calendar-full .ant-picker-panel .ant-picker-calendar-date-today { border-color: #b30000; } + .calendar-dashboard .ant-picker-calendar-full .ant-picker-panel .ant-picker-body th { padding: 0 0px 5px 0; text-align: center; } + .calendar-dashboard .ant-picker-calendar-full .ant-picker-panel .ant-picker-body td { text-align: center; } + .calendar-dashboard .ant-tag { margin-right: 0px; line-height: 19px; } + .calendar-dashboard .ant-picker-cell { cursor: default; } + .notice-detail-html p { margin: 0; padding: 0; } + .notice-detail-file { font-size: 17px; color: #7c7c7c; @@ -138,26 +159,38 @@ top: 5px; vertical-align: top; } + .notice-detail-noticefile { margin-top: 20px; + .ant-spin-nested-loading { display: inline-block; } } + .baseinf-top { background-color: #ffffff; padding: 20px; overflow: auto; } + .baseinf-bottom-btn { margin-top: 40px; text-align: center; } + .calibration-panel { .ant-collapse-content-box { padding: 0px 16px; } } + .question-form .ant-space { min-width: 50%; +} + +.table-no-alert { + .ant-pro-table-alert { + display: none; + } } \ No newline at end of file diff --git a/src/components/ElecBidEvaluation/BidEvalAppointment.tsx b/src/components/ElecBidEvaluation/BidEvalAppointment.tsx new file mode 100644 index 0000000..ec5d0ae --- /dev/null +++ b/src/components/ElecBidEvaluation/BidEvalAppointment.tsx @@ -0,0 +1,298 @@ +import React, { useEffect, useRef, useState } from 'react'; +import { Col, DatePicker, Descriptions, Form, Input, message, Modal, Row } from 'antd'; +import ProTable, { ActionType, ProColumns } from '@ant-design/pro-table'; +import { getBidEvalRoom, saveAppointmentEdit } from './service'; +import { dateFormat, disabledDate, disabledDateTime, validateMessages } from './MeetingReservation'; +import moment from 'moment'; +import { dateTimeFormatter } from '@/utils/DateUtils'; +import { getProId } from '@/utils/session'; + +interface BidEvalAppointmentProps { + modalVisible: boolean; + onCancel: () => void; + onSubmit: (value: any) => void; + reload: () => void; + values: any; + type: string; //0-选择评标室 1-修改预约 +} + +export const proviceEnum = { + "0011": "北京", + "0012": "天津", + "0013": "河北", + "0014": "山西", + "0015": "内蒙古", + "0021": "辽宁", + "0022": "吉林", + "0023": "黑龙江", + "0031": "上海", + "0032": "江苏", + "0033": "浙江", + "0034": "安徽", + "0035": "福建", + "0036": "江西", + "0037": "山东", + "0041": "河南", + "0042": "湖北", + "0043": "湖南", + "0044": "广东", + "0045": "广西", + "0046": "海南", + "0050": "重庆", + "0051": "四川", + "0052": "贵州", + "0053": "云南", + "0054": "西藏", + "0061": "陕西", + "0062": "甘肃", + "0063": "青海", + "0064": "宁夏", + "0065": "新疆", + "001000": "集团" +} + +const modalHeight = window.innerHeight * 96 / 100; + +const BidEvalAppointment: React.FC = (props) => { + const { modalVisible, onCancel, onSubmit, reload, values, type } = props; + const actionRef = useRef(); + const [form] = Form.useForm(); + //项目id + const proId = getProId(); + //当前选择行areaId + const [selectedRowKeys, setSelectedRowKeys] = useState([]); + //当前选择行数据 + const [selectedRecord, setSelectedRecord] = useState(); + const columns: ProColumns[] = [ + { + valueType: 'index', + width: 48, + }, + { + title: '评标室名称', + dataIndex: 'areaName', + ellipsis: true, + }, + { + title: '服务省分', + dataIndex: 'provinceDictId', + ellipsis: true, + valueEnum: proviceEnum, + hideInSearch: true, + }, + { + title: '详细地址', + dataIndex: 'areaAddress', + ellipsis: true, + hideInSearch: true, + }, + { + title: '可容纳人数', + dataIndex: 'areaNumber', + ellipsis: true, + hideInSearch: true, + }, + { + title: '联系人', + dataIndex: 'contactName', + ellipsis: true, + hideInSearch: true, + }, { + title: '联系电话', + dataIndex: 'contactTel', + ellipsis: true, + hideInSearch: true, + }, + ]; + + const onOk = () => { + if (selectedRowKeys.length == 0) { + message.info("请选择评标室"); + return; + } + form.validateFields().then(value => { + if (moment(value.reserveStartDate).format(dateTimeFormatter) < moment().format(dateTimeFormatter)) { + message.info("开始时间需晚于当前时间"); + return; + } + if (moment(value.reserveEndDate).format(dateTimeFormatter) <= moment(value.reserveStartDate).format(dateTimeFormatter)) { + message.info("结束时间需晚于开始时间"); + return; + } + if (type == "0") {//选择评标室 + value["areaId"] = selectedRecord.id; + value["placeId"] = selectedRecord.placeId; + value["areaAddress"] = selectedRecord.areaAddress; + value["areaName"] = selectedRecord.areaName; + value["contactName"] = selectedRecord.contactName; + value["contactTel"] = selectedRecord.contactTel; + value["areaNumber"] = selectedRecord.areaNumber; + onSubmit(value); + } else {//修改预约 + const params = { + ...values, + areaId: selectedRecord.id, + placeId: selectedRecord.placeId, + reserveStartDate: moment(value.reserveStartDate).format(dateTimeFormatter), + reserveEndDate: moment(value.reserveEndDate).format(dateTimeFormatter), + reserveBy: value.reserveBy, + reserveContactNumber: value.reserveContactNumber, + } + saveAppointmentEdit(params).then(res => { + if (res?.code == 200) { + message.success("预约成功"); + onCancel(); + reload(); + } + }) + } + }) + } + + useEffect(() => { + setSelectedRowKeys([]); + setSelectedRecord(null); + }, [values]) + + return ( + onCancel()} + onOk={() => onOk()} + okText={type == "0" ? "确认" : "保存"} + width={"70%"} + style={{ maxHeight: modalHeight }} + bodyStyle={{ maxHeight: modalHeight - 107, overflowY: 'auto', }} + className="confirm table-no-alert" + centered + > + {values?.areaId && ( + <> +

{type == "0" ? "已选择评标室" : "已预约评标室"}

+ + {values?.areaName} + {values?.contactName && {values?.contactName}} + {values?.contactTel && {values?.contactTel}} + {values?.areaNumber ? values?.areaNumber : values?.numberInMeeting} + {moment(values?.reserveStartDate).format(dateTimeFormatter)} + {moment(values?.reserveEndDate).format(dateTimeFormatter)} + +

选择评标室

+ + )} + + columns={columns} + actionRef={actionRef} + bordered={false} + request={async (params: any) => { + return await getBidEvalRoom(params).then(res => { + if (res?.code == 200) { + return { + data: res?.data.records, + success: res?.success, + total: res?.data.total, + } + } else { + return { + data: [], + success: false, + total: 0, + } + } + }) + }} + rowKey="id" + search={{ + labelWidth: 'auto', + }} + options={false} + pagination={{ + size: "small", + defaultPageSize: 10, + showSizeChanger: true, + }} + rowSelection={{ + type: "radio", + selectedRowKeys, + onChange: (selectedRowKeys, selectedRows) => { + setSelectedRowKeys(selectedRowKeys); + setSelectedRecord(selectedRows[0]); + }, + }} + dateFormatter="string" + toolBarRender={false} + /> +
+ + + {selectedRowKeys.length > 0 && ( + + + 预约时间范围 7:00 ~ 18:00} + > + + + + + + + + + + + + + + + + + + + + )} +
+
+ ); +}; + +export default BidEvalAppointment; diff --git a/src/components/ElecBidEvaluation/ExpertPhotoUpload.tsx b/src/components/ElecBidEvaluation/ExpertPhotoUpload.tsx new file mode 100644 index 0000000..df2b7ac --- /dev/null +++ b/src/components/ElecBidEvaluation/ExpertPhotoUpload.tsx @@ -0,0 +1,153 @@ +import { createNewFileBid, removeFileByOid } from '@/services/download_'; +import { downloadPath, uploadAttachmentPath } from '@/utils/DownloadUtils'; +import { getSessionRoleData, getUserToken } from '@/utils/session'; +import { PlusOutlined } from '@ant-design/icons'; +import { message, Modal, Spin, Upload } from 'antd'; +import type { RcFile, UploadProps } from 'antd/es/upload'; +import type { UploadFile } from 'antd/es/upload/interface'; +import React, { useEffect, useState } from 'react'; + +const getBase64 = (file: RcFile): Promise => + new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result as string); + reader.onerror = error => reject(error); + }); + +interface ExpertPhotoUpload { + maxSize?: number | undefined; //文件大小KB 默认1024KB + value?: string | null; //文档中心fileId + onChange?: (fileId: string | null) => void; //回调 + uploadProps?: UploadProps; +} +/** + * 图片上传 仅用fileId objectId随机生成 + * @param props + * @returns + */ +const ExpertPhotoUpload: React.FC = (props) => { + const { maxSize, value, onChange, uploadProps } = { maxSize: 1024, ...props, } + //预览弹窗 + const [previewVisible, setPreviewVisible] = useState(false); + //预览图片的base64 + const [previewImage, setPreviewImage] = useState(''); + //objectId + const [uploadObjectId, setUploadObjectId] = useState(); + //文件列表 + const [fileList, setFileList] = useState([]); + + const handleCancel = () => setPreviewVisible(false); + + const handlePreview = async (file: UploadFile) => { + if (!file.url && !file.preview) { + file.preview = await getBase64(file.originFileObj as RcFile); + } + + setPreviewImage(file.url || (file.preview as string)); + setPreviewVisible(true); + }; + + const handleChange: UploadProps['onChange'] = ({ file, fileList: newFileList }) => { + if (file.status === 'uploading') { + setFileList(newFileList); + } else if (file.status === 'removed') { + //删除文件 + removeFileByOid(file.uid).then(res => { + if (res.success) { + onChange && onChange(null); + message.success("删除成功"); + } + }) + } else if (file.status === 'done') { + onChange && onChange(file?.response.data[0].sysStorageVO.fileId); + message.success("上传成功"); + } else if (file.status === 'error') { + message.error("上传失败,请重新上传"); + } + }; + //上传前校验 + const beforeUpload = (file: RcFile) => { + const fileType = file.type === 'image/png' || file.type === 'image/jpg' || file.type === 'image/jpeg'; + const fileSize = file.size / 1024;//精确到KB + console.log("fileSize", fileSize) + const fileListLength = fileList.length; + if (!fileType) { + message.error(`上传失败,${file.name}类型不正确,请选择png、jpg、jpeg类型的图片`); + return Upload.LIST_IGNORE; + } + if (fileSize >= maxSize) { + message.error(`上传失败,${file.name}大小为${fileSize.toFixed(2)}KB,超过允许的大小${maxSize}KB`); + return Upload.LIST_IGNORE; + } + if (fileListLength >= 1) { + message.error(`上传失败,${file.name}数量为${fileListLength}个,超过允许的数量 1 个`); + return Upload.LIST_IGNORE; + } + return true; + } + + const uploadButton = ( +
+ +
上传
+
+ ); + //获取雪花id,上传用 + const getObjectId = () => { + createNewFileBid().then(res => { + setUploadObjectId(res.id); + }) + } + //回显文件列表 + const getFileList = (fileId: string | null | undefined) => { + if (fileId) { + return [{ + uid: fileId, + name: 'image.png', + status: 'done', + url: downloadPath + "?fileId=" + fileId, + }] + } + return []; + } + + useEffect(() => { + !uploadProps?.disabled && getObjectId(); + }, []) + + useEffect(() => { + setFileList(() => getFileList(value)); + }, [value]) + + return ( + <> + + {uploadProps?.disabled || fileList.length >= 1 ? null : uploadButton} + + + example + + + ); +}; + +export default ExpertPhotoUpload; \ No newline at end of file diff --git a/src/components/ElecBidEvaluation/MeetingReservation.tsx b/src/components/ElecBidEvaluation/MeetingReservation.tsx index a4f6e8b..b18bfd0 100644 --- a/src/components/ElecBidEvaluation/MeetingReservation.tsx +++ b/src/components/ElecBidEvaluation/MeetingReservation.tsx @@ -18,16 +18,26 @@ const layout = { labelCol: { span: 7 }, wrapperCol: { span: 14 }, }; -const validateMessages = { +export const validateMessages = { required: '请填写此项', }; -const range = (start: number, end: number) => { +export const range = (start: number, end: number) => { const result = []; for (let i = start; i < end; i++) { result.push(i); } return result; }; +//不可选天 +export function disabledDate(current: any) { + return current && current < moment().startOf('day'); +} +//不可选小时 +export const disabledDateTime = () => ({ + disabledHours: () => [...range(0, 7), ...range(19, 24)], +}); +//时间选择框日期格式化 +export const dateFormat: DatePickerProps['format'] = value => value?.startOf('hour').format('YYYY-MM-DD HH:mm:ss'); /** * 评标室预约管理-会议室预约弹窗 * @param props @@ -67,16 +77,7 @@ const MeetingReservation: React.FC = (props) => { setLoading(false); }) }; - //不可选天 - function disabledDate(current: any) { - return current && current < moment().startOf('day'); - } - //不可选小时 - const disabledDateTime = () => ({ - disabledHours: () => [...range(0, 7), ...range(19, 24)], - }); - //时间选择框日期格式化 - const dateFormat: DatePickerProps['format'] = value => value?.startOf('hour').format('YYYY-MM-DD HH:mm:ss'); + //获取预约信息 const getMeetData = () => { setSkeleing(true); diff --git a/src/components/ElecBidEvaluation/service.ts b/src/components/ElecBidEvaluation/service.ts index 944ba2b..91472cd 100644 --- a/src/components/ElecBidEvaluation/service.ts +++ b/src/components/ElecBidEvaluation/service.ts @@ -26,4 +26,29 @@ export async function cancelMeeting(id: any) { return request('/api/biz-service-ebtp-evaluation/v1/eval/room/reserve/cancel/' + id, { method: 'GET', }); +} + +/** + * 评标室预约-查询评标室 + * @params data + */ +export async function getBidEvalRoom(data: any) { + return request('/api/biz-service-ebtp-evaluation/v1/elec/eval/area/page/list', { + method: 'POST', + data: { + ...data, + pageNo: data.current, + }, + }); +} + +/** + * 评标室预约-预约修改保存 + * @params data + */ +export async function saveAppointmentEdit(data: any) { + return request('/api/biz-service-ebtp-evaluation/v1/eval/room/reserve/updateSubmit', { + method: 'POST', + data: { ...data, }, + }); } \ No newline at end of file diff --git a/src/pages/Project/ProjectManage/ProjectManager/HomePageSectionList/components/AddEvaluationItems.tsx b/src/pages/Project/ProjectManage/ProjectManager/HomePageSectionList/components/AddEvaluationItems.tsx index fbb894e..05bb3e4 100644 --- a/src/pages/Project/ProjectManage/ProjectManager/HomePageSectionList/components/AddEvaluationItems.tsx +++ b/src/pages/Project/ProjectManage/ProjectManager/HomePageSectionList/components/AddEvaluationItems.tsx @@ -1,10 +1,11 @@ import { echoDateTimeFormatter, saveDateTimeFormatter } from '@/utils/DateUtils'; import ExtendUpload from '@/utils/ExtendUpload'; import { getProMethod } from '@/utils/session'; -import { DatePicker, Form, Input, message, Modal, Radio, Spin } from 'antd'; +import { Button, DatePicker, Form, Input, message, Modal, Radio, Spin } from 'antd'; import React, { useEffect, useState } from 'react'; import moment from 'moment'; import { isEmpty } from '@/utils/CommonUtils'; +import BidEvalAppointment from '@/components/ElecBidEvaluation/BidEvalAppointment'; interface AddEvaluationItemsProps { title?: string; modalVisible?: boolean; @@ -46,6 +47,12 @@ const AddEvaluationItems: React.FC = (props) => { const [sectionType, setSectionType] = useState('评审'); //loading const [saveLoading, setSaveLoading] = useState(false); + //电子评标室-评标室预约选择 2022.8.26 zhoujianlong + const [selectEvalVisible, setSelectEvalVisible] = useState(false); + //电子评标室-评标室预约选择不可选状态控制 true-不可填写 false-可填写 2022.8.26 zhoujianlong + const [selectEvalDisabled, setSelectEvalDisabled] = useState(true); + //电子评标室-评标室预约选择-数据 2022.8.26 zhoujianlong + const [selectEvalData, setSelectEvalData] = useState(); useEffect(() => { //名称确定 if (MethodDict == 'procurement_mode_1' || MethodDict == 'procurement_mode_2') { @@ -101,99 +108,144 @@ const AddEvaluationItems: React.FC = (props) => { form.submit(); }; + //评标室预约回调 + const returnEvalData = (value: any) => { + console.log('value', value) + setSelectEvalVisible(false); + setSelectEvalDisabled(false); + setSelectEvalData(value); + form.setFieldsValue({ + evaluationStartTime: value.reserveStartDate, + evaluationEndTime: value.reserveEndDate, + evaluationPlace: value.areaAddress, + reserveBy: value.reserveBy, + reserveContactNumber: value.reserveContactNumber, + }) + } + + //评标室预约-选择评标室 + const selectEvalClick = () => { + setSelectEvalVisible(true); + } + return ( - onSubmit()} - onCancel={() => { - // setFileListData([]); - onCancel(); - }} - width={'60%'} - style={{ maxHeight: modalHeight }} - bodyStyle={{ maxHeight: modalHeight - 107, overflowY: 'auto' }} - centered - okText="保存" - cancelText="返回" - confirmLoading={saveLoading} - > - -
- - - - -