Merge branch '20220802-评标室预约情况' into 'release_electronic_bid_evaluation_room'
9.1 评标室预约情况 See merge request eshop/fe_service_ebtp_frontend!273
This commit is contained in:
298
src/components/ElecBidEvaluation/BidEvalAppointment.tsx
Normal file
298
src/components/ElecBidEvaluation/BidEvalAppointment.tsx
Normal file
@ -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<BidEvalAppointmentProps> = (props) => {
|
||||
const { modalVisible, onCancel, onSubmit, reload, values, type } = props;
|
||||
const actionRef = useRef<ActionType>();
|
||||
const [form] = Form.useForm();
|
||||
//项目id
|
||||
const proId = getProId();
|
||||
//当前选择行areaId
|
||||
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
|
||||
//当前选择行数据
|
||||
const [selectedRecord, setSelectedRecord] = useState<any>();
|
||||
const columns: ProColumns<any>[] = [
|
||||
{
|
||||
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 (
|
||||
<Modal
|
||||
destroyOnClose
|
||||
title={type == "0" ? "选择评标室" : "修改预约"}
|
||||
visible={modalVisible}
|
||||
maskClosable={false}
|
||||
onCancel={() => 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 && (
|
||||
<>
|
||||
<h3 className='first-title'>{type == "0" ? "已选择评标室" : "已预约评标室"}</h3>
|
||||
<Descriptions size="middle">
|
||||
<Descriptions.Item label="评标室名称">{values?.areaName}</Descriptions.Item>
|
||||
{values?.contactName && <Descriptions.Item label="联系人">{values?.contactName}</Descriptions.Item>}
|
||||
{values?.contactTel && <Descriptions.Item label="联系电话">{values?.contactTel}</Descriptions.Item>}
|
||||
<Descriptions.Item label="可容纳人数">{values?.areaNumber ? values?.areaNumber : values?.numberInMeeting}</Descriptions.Item>
|
||||
<Descriptions.Item label="预计评标开始时间">{moment(values?.reserveStartDate).format(dateTimeFormatter)}</Descriptions.Item>
|
||||
<Descriptions.Item label="预计评标结束时间">{moment(values?.reserveEndDate).format(dateTimeFormatter)}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
<h3 className='first-title'>选择评标室</h3>
|
||||
</>
|
||||
)}
|
||||
<ProTable<any>
|
||||
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}
|
||||
/>
|
||||
<Form
|
||||
name="basic"
|
||||
form={form}
|
||||
labelCol={{ span: 8 }}
|
||||
wrapperCol={{ span: 16 }}
|
||||
preserve={false}
|
||||
validateMessages={validateMessages}
|
||||
>
|
||||
<Form.Item
|
||||
label="是否预约评标室"
|
||||
name="reserveStatus"
|
||||
initialValue={"1"}
|
||||
hidden
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="项目id"
|
||||
name="projectId"
|
||||
initialValue={proId}
|
||||
hidden
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
{selectedRowKeys.length > 0 && (
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="预计评标开始时间"
|
||||
name="reserveStartDate"
|
||||
rules={[{ required: true, message: '请选择' }]}
|
||||
extra={<span style={{ color: "#b30000" }}>预约时间范围 7:00 ~ 18:00</span>}
|
||||
>
|
||||
<DatePicker showTime={{ defaultValue: moment().hour(7) }} showNow={false} disabledDate={disabledDate} disabledTime={disabledDateTime} showMinute={false} showSecond={false} format={dateFormat} style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="预计评标结束时间"
|
||||
name="reserveEndDate"
|
||||
rules={[{ required: true, message: '请选择' }]}
|
||||
>
|
||||
<DatePicker showTime={{ defaultValue: moment().hour(7) }} showNow={false} disabledDate={disabledDate} disabledTime={disabledDateTime} showMinute={false} showSecond={false} format={dateFormat} style={{ width: '100%' }} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="预约人"
|
||||
name="reserveBy"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input maxLength={20} placeholder="预约人姓名" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label="预约人联系方式"
|
||||
name="reserveContactNumber"
|
||||
rules={[{ required: true }]}
|
||||
>
|
||||
<Input type="number" maxLength={20} placeholder="预约人手机号" />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
|
||||
export default BidEvalAppointment;
|
153
src/components/ElecBidEvaluation/ExpertPhotoUpload.tsx
Normal file
153
src/components/ElecBidEvaluation/ExpertPhotoUpload.tsx
Normal file
@ -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<string> =>
|
||||
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<ExpertPhotoUpload> = (props) => {
|
||||
const { maxSize, value, onChange, uploadProps } = { maxSize: 1024, ...props, }
|
||||
//预览弹窗
|
||||
const [previewVisible, setPreviewVisible] = useState(false);
|
||||
//预览图片的base64
|
||||
const [previewImage, setPreviewImage] = useState('');
|
||||
//objectId
|
||||
const [uploadObjectId, setUploadObjectId] = useState<string>();
|
||||
//文件列表
|
||||
const [fileList, setFileList] = useState<any[]>([]);
|
||||
|
||||
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 = (
|
||||
<div>
|
||||
<PlusOutlined />
|
||||
<div style={{ marginTop: 8 }}>上传</div>
|
||||
</div>
|
||||
);
|
||||
//获取雪花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 (
|
||||
<>
|
||||
<Upload
|
||||
action={uploadAttachmentPath}
|
||||
data={{
|
||||
appCode: 'ebtp-cloud-frontend',
|
||||
objectId: uploadObjectId,
|
||||
}}
|
||||
headers={{
|
||||
Authorization: getUserToken(),
|
||||
currentRoleCode: getSessionRoleData()?.roleCode,
|
||||
}}
|
||||
name="multipartFiles"
|
||||
listType="picture-card"
|
||||
fileList={fileList}
|
||||
onPreview={handlePreview}
|
||||
onChange={handleChange}
|
||||
beforeUpload={beforeUpload}
|
||||
accept=".jpg,.png,.jpeg"
|
||||
{...uploadProps}
|
||||
>
|
||||
{uploadProps?.disabled || fileList.length >= 1 ? null : uploadButton}
|
||||
</Upload>
|
||||
<Modal visible={previewVisible} title="查看" footer={null} onCancel={handleCancel} centered>
|
||||
<img alt="example" style={{ width: '100%' }} src={previewImage} />
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExpertPhotoUpload;
|
@ -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<MeetingReservationProps> = (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);
|
||||
|
@ -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, },
|
||||
});
|
||||
}
|
Reference in New Issue
Block a user