Merge branch '20230705-专家评审组照片维护功能,当选择电子评标室的标段,维护照片时为必选项。' into 'release_20230714'

7.14 专家评审组照片维护功能,当选择电子评标室的标段,维护照片时为必选项。

See merge request eshop/fe_service_ebtp_frontend!303
This commit is contained in:
jl-zhoujl2
2023-07-14 03:14:30 +00:00
6 changed files with 136 additions and 73 deletions

View File

@ -148,7 +148,7 @@ const ExpertPhotoUpload: React.FC<ExpertPhotoUpload> = (props) => {
>
{uploadProps?.disabled || fileList.length >= 1 ? null : uploadButton}
</Upload>
<Modal visible={previewVisible} title="查看" footer={null} onCancel={handleCancel} centered>
<Modal visible={previewVisible} title="查看" width={'461px'} footer={null} onCancel={handleCancel} centered>
<img alt="example" style={{ width: '100%' }} src={previewImage} />
</Modal>
</>

View File

@ -7,6 +7,7 @@ import React, { useEffect, useState } from "react";
import './judgList.less';
import '@/assets/xsy_style.less';
import { saveAssistPeople } from "./service";
import { isEmpty } from "@/utils/CommonUtils";
interface OutsourcingManageProps {
modalVisible: boolean,
@ -124,6 +125,17 @@ const OutsourcingManage: React.FC<OutsourcingManageProps> = (props) => {
// }}
onOk={() => {
if (Number(assistNumber) == dataSource.length) {
let count = 0
for (let i = 0, length = dataSource.length; i < length; i++) {
const item = dataSource[i];
if (isEmpty(item.faceId)) {
count += 1;
}
}
if (count > 0) {
message.error(`请上传专家照片`);
return;
}
const params = {
juryId,
assistList: [...dataSource],
@ -252,18 +264,19 @@ const OutsourcingManage: React.FC<OutsourcingManageProps> = (props) => {
>
<Input style={{ width: "60%" }} />
</Form.Item></Col></Row>
<Form.Item label="照片" style={{ marginBottom: 0 }}>
<Form.Item label="照片" required style={{ marginBottom: 0 }} tooltip="若预约了电子评标室,请提前维护外协人员照片,避免无法进入电子评标室。">
<Form.Item
name="faceId"
style={{ display: 'inline-block', width: '60%' }}
extra={<span style={{ color: '#b30000' }}></span>}
style={{ display: 'inline-block', width: '80%' }}
rules={[{ required: true, message: "请上传照片" }]}
extra={<span style={{ color: '#b30000' }}>2psJPG格式400k以下</span>}
>
<ExpertPhotoUpload maxSize={200} />
<ExpertPhotoUpload maxSize={400} uploadProps={{ accept: ".jpg,.jpeg" }} />
</Form.Item>
<Form.Item
{/* <Form.Item
style={{ display: 'inline-block', width: '40%', position: "relative", right: '24%' }}
>
</Form.Item>
</Form.Item> */}
</Form.Item>
<Row><Col span={24}><Form.Item {...tailLayoutDrawer}>
<Button type="primary" loading={loading} hidden={btnAuthority(['ebtp-agency-project-manager', 'ebtp-purchase'])} onClick={async () => {

View File

@ -4,7 +4,7 @@ import ProTable, { ActionType, ProColumns } from '@ant-design/pro-table';
import { getList, getSecs, saveGroup, delOne, saveMember, changeEx, queryVoList, changeMember, applyFor, roomStatus, juryTem, rePassWord, getUserPhoto, unlockAccount } from './service';
import moment from 'moment';
import { getDefId, getProId, getProMethod, getSessionProjectData, getSessionUserData } from '@/utils/session';
import { getURLInformation } from '@/utils/CommonUtils';
import { getURLInformation, isEmpty } from '@/utils/CommonUtils';
import './judgList.less';
import '@/assets/xsy_style.less';
import FileDown from '@/utils/Download';
@ -59,6 +59,7 @@ const JudgingPanel: React.FC<{}> = () => {
const [isReserve, setIsReserve] = useState<string>("0");//电子评标室-是否预约电子评标室 2022.9.23 zhoujianlong 0-不预约 1-预约
const userData = getSessionUserData();//当前登录人用户信息
const [assistVisible, setAssistVisible] = useState<boolean>(false);//协办管理visible 2022.10.10 zhoujianlong
const [reserveStatus, setReserveStatus] = useState<boolean>(false);//成员管理-当前行是否预约了评标室 true-预约了 false-没预约
function getShouName() {
const method = getProMethod();
@ -167,6 +168,7 @@ const JudgingPanel: React.FC<{}> = () => {
await queryOpenStatus(record.id);
categorySet(record.juryCategoryVOList);
juryIdSet(record.id);
setReserveStatus(record.reserveStatus === 1);
memberCountSet(memberCount + 1);
setMemberVis(true);
}}></Button>
@ -1204,6 +1206,7 @@ const JudgingPanel: React.FC<{}> = () => {
checkBoxsSet([]);
changeMemberIdSet('');
setCheckedList([]);
setReserveStatus(false);
form.resetFields();
}
const columnsMember: ProColumns<any>[] = [//成员管理页面表格
@ -1616,19 +1619,20 @@ const JudgingPanel: React.FC<{}> = () => {
>
<Input style={{ width: "60%" }} onChange={onCertificateChange} />
</FormItem></Col></Row>
<Form.Item label="照片" style={{ marginBottom: 0 }}>
<Form.Item label="照片" required={reserveStatus} style={{ marginBottom: 0 }} tooltip="评审专家照片为专家进入电子评标室报道及人脸识别认证使用,若预约了电子评标室,请维护专家照片。">
<Form.Item
name="faceId"
style={{ display: 'inline-block', width: '60%' }}
extra={<span style={{ color: '#b30000' }}>使</span>}
style={{ display: 'inline-block', width: '80%' }}
rules={[{ required: reserveStatus, message: "请上传照片" }]}
extra={<span style={{ color: '#b30000' }}>2psJPG格式400k以下</span>}
>
<ExpertPhotoUpload maxSize={200} />
</Form.Item>
<Form.Item
style={{ display: 'inline-block', width: '40%', position: "relative", right: '24%' }}
>
{/* <Button type='primary' onClick={() => getExpertPhoto()}>获取照片</Button> */}
<ExpertPhotoUpload maxSize={400} uploadProps={{ accept: ".jpg,.jpeg" }} />
</Form.Item>
{/* <Form.Item
style={{ display: 'inline-block', width: '20%', position: "relative", right: '24%' }}
> */}
{/* <Button type='primary' onClick={() => getExpertPhoto()}>获取照片</Button> */}
{/* </Form.Item> */}
</Form.Item>
{/* <Row><Col span={24}><FormItem
name="type"
@ -1820,6 +1824,18 @@ const JudgingPanel: React.FC<{}> = () => {
// qita != undefined && qita.extractNumber==qita.juryMemberList.length ? params.push(...qita.juryMemberList) : null;
if (chackNum) {
let count = 0
for (let i = 0, length = params.length; i < length; i++) {
const item = params[i];
if (isEmpty(item.faceId)) {
count += 1;
}
}
if (count > 0) {
message.error(`请上传专家照片`);
loadingSet(false);
return;
}
const success = await saveMember({ juryMemberDTOList: params }).then((res) => {
return res.success
});
@ -1889,7 +1905,7 @@ const JudgingPanel: React.FC<{}> = () => {
centered
destroyOnClose
title="评审小组成员管理"
bodyStyle={{ maxHeight: modalHeight - 140, overflow: 'auto', minHeight: '300px', padding: '16px 0px 0px 0px' }}
bodyStyle={{ maxHeight: modalHeight - 140, overflow: 'auto', minHeight: '350px', padding: '16px 0px 0px 0px' }}
footer={returnFooterMem()}
onCancel={() => {
setMemberVis(false);

View File

@ -17,6 +17,7 @@ import { getUserPhoto, unlockAccount } from '@/pages/Tender/ProjectManager/Judgi
import BidEvalAppointment from '@/components/ElecBidEvaluation/BidEvalAppointment';
import OutsourcingManage from '@/pages/Tender/ProjectManager/JudgingPanel/List/OutsourcingManage';
import { dateTimeFormatter } from '@/utils/DateUtils';
import { isEmpty } from '@/utils/CommonUtils';
const JudgingPanel: React.FC<{}> = (props: any) => {
const modalHeight = window.innerHeight * 96 / 100;
@ -56,6 +57,7 @@ const JudgingPanel: React.FC<{}> = (props: any) => {
const [isReserve, setIsReserve] = useState<string>("0");//电子评标室-是否预约电子评标室 2022.9.23 zhoujianlong 0-不预约 1-预约
const userData = getSessionUserData();//当前登录人用户信息
const [assistVisible, setAssistVisible] = useState<boolean>(false);//协办管理visible 2022.10.10 zhoujianlong
const [reserveStatus, setReserveStatus] = useState<boolean>(false);//成员管理-当前行是否预约了评标室 true-预约了 false-没预约
//外协管理
const [assistList, setAssistList] = useState<any>([]);//外协人员数据 assistList
const [assistNumber, setAssistNumber] = useState<string>("");//外协人员数量 assistNumber
@ -155,6 +157,7 @@ const JudgingPanel: React.FC<{}> = (props: any) => {
await queryOpenStatus(record.id);
categorySet(record.juryCategoryVOList);
juryIdSet(record.id);
setReserveStatus(record.reserveStatus === 1);
memberCountSet(memberCount + 1);
setMemberVis(true);
}}></Button>
@ -1072,6 +1075,7 @@ const JudgingPanel: React.FC<{}> = (props: any) => {
updateKeyMemSet(-1);
checkBoxsSet([]);
changeMemberIdSet('');
setReserveStatus(false);
form.resetFields();
}
const columnsMember: ProColumns<any>[] = [//成员管理页面表格
@ -1484,19 +1488,20 @@ const JudgingPanel: React.FC<{}> = (props: any) => {
>
<Input style={{ width: "60%" }} onChange={onCertificateChange} />
</FormItem></Col></Row>
<Form.Item label="照片" style={{ marginBottom: 0 }}>
<Form.Item label="照片" required={reserveStatus} style={{ marginBottom: 0 }} tooltip="评审专家照片为专家进入电子评标室报道及人脸识别认证使用,若预约了电子评标室,请维护专家照片。">
<Form.Item
name="faceId"
style={{ display: 'inline-block', width: '60%' }}
extra={<span style={{ color: '#b30000' }}>使</span>}
style={{ display: 'inline-block', width: '80%' }}
rules={[{ required: reserveStatus, message: "请上传照片" }]}
extra={<span style={{ color: '#b30000' }}>2psJPG格式400k以下</span>}
>
<ExpertPhotoUpload maxSize={200} />
</Form.Item>
<Form.Item
style={{ display: 'inline-block', width: '40%', position: "relative", right: '24%' }}
>
{/* <Button type='primary' onClick={() => getExpertPhoto()}>获取照片</Button> */}
<ExpertPhotoUpload maxSize={400} uploadProps={{ accept: ".jpg,.jpeg" }} />
</Form.Item>
{/* <Form.Item
style={{ display: 'inline-block', width: '20%', position: "relative", right: '24%' }}
> */}
{/* <Button type='primary' onClick={() => getExpertPhoto()}>获取照片</Button> */}
{/* </Form.Item> */}
</Form.Item>
{/* <Row><Col span={24}><FormItem
name="type"
@ -1688,6 +1693,18 @@ const JudgingPanel: React.FC<{}> = (props: any) => {
// qita != undefined && qita.extractNumber==qita.juryMemberList.length ? params.push(...qita.juryMemberList) : null;
if (chackNum) {
let count = 0
for (let i = 0, length = params.length; i < length; i++) {
const item = params[i];
if (isEmpty(item.faceId)) {
count += 1;
}
}
if (count > 0) {
message.error(`请上传专家照片`);
loadingSet(false);
return;
}
const success = await saveMember({ juryMemberDTOList: params, roomId: roomId }).then((res) => {
return res.success
});
@ -1757,7 +1774,7 @@ const JudgingPanel: React.FC<{}> = (props: any) => {
centered
destroyOnClose
title="评审小组成员管理"
bodyStyle={{ maxHeight: modalHeight - 140, overflow: 'auto', minHeight: '300px', padding: '16px 0px 0px 0px' }}
bodyStyle={{ maxHeight: modalHeight - 140, overflow: 'auto', minHeight: '350px', padding: '16px 0px 0px 0px' }}
footer={returnFooterMem()}
onCancel={() => {
setMemberVis(false);

View File

@ -2,7 +2,7 @@ import React, { useEffect, useState, useRef } from 'react';
import { Form, Button, Input, Row, Col, Modal, Spin, message, Tabs } from 'antd';
import { UserOutlined, LockOutlined, SafetyCertificateOutlined } from '@ant-design/icons';
import './style.less';
import { changePass } from './service';
import { changePass, showFaceTab } from './service';
import logo from '@/images/login/logoPic.png';
import { refreshTokenApi, ZjfakeAccountLogin, ZjfakeFaceLogin } from '@/services/login';
import { history } from 'umi';
@ -40,6 +40,7 @@ const Index: React.FC<{}> = () => {
const { TabPane } = Tabs;
const [submitLoading, setSubmitLoading] = useState<boolean>(false);
const [faceLoginDisable, setFaceLoginDisable] = useState<boolean>(false);
const [faceLoginShow, setFaceLoginShow] = useState<boolean>(false);
const lv = useRef<LivingNotIE>();
const [timerShow, setTimeShow] = useState<boolean>(false);
const [itemShow, setItemShow] = useState<boolean>(false);
@ -496,6 +497,11 @@ const Index: React.FC<{}> = () => {
}
return false;
}
//是否显示人脸登录
const showFaceLogin = async () => {
const res = await showFaceTab();
setFaceLoginShow(res?.data === 1);
}
useEffect(() => {
@ -505,6 +511,7 @@ const Index: React.FC<{}> = () => {
if (!allowedToFaceLogin()) {
setFaceLoginDisable(true);
}
showFaceLogin();
}, []);
useEffect(() => {
@ -592,49 +599,51 @@ const Index: React.FC<{}> = () => {
</Form.Item>
</Form>
</TabPane>
{/* <TabPane tab="人脸识别登录" key="2" disabled={faceLoginDisable}>
<Form
name="basic2"
className="form-box"
initialValues={{ remember: true }}
form={form2}
// onFinish={hanleFaceSubmit.bind(this, null)}
onFinish={!whetherIE.current?liveDetectStart:hanleFaceSubmit.bind(this, null)}
// onFinishFailed={onFinishFailed}
>
<Form.Item
label=""
name="userName"
rules={[{ required: true, message: '请输入用户名!' }]}
{faceLoginShow && <>
<TabPane tab="人脸识别登录" key="2" disabled={faceLoginDisable}>
<Form
name="basic2"
className="form-box"
initialValues={{ remember: true }}
form={form2}
// onFinish={hanleFaceSubmit.bind(this, null)}
onFinish={!whetherIE.current ? liveDetectStart : hanleFaceSubmit.bind(this, null)}
// onFinishFailed={onFinishFailed}
>
<Input
prefix={
<UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
}
placeholder="请输入用户名"
/>
</Form.Item>
<Form.Item>
{!whetherIE.current ? (<video ref={video} width="382" height="200"></video>) : (<FrameFaceLogin faceCompareEvent2={IELiveDetectFinish2} faceCompareEvent={IELiveDetectFinish} faceDetectStatusEvent = {UpdateDetectStatus}/>)}
</Form.Item>
<Form.Item>
<Button type="primary" className="w100" loading={submitLoading} htmlType="submit">
{submitLoading ? actionText(action, Math.round(timer/1000)) : '登 录'}
</Button>
</Form.Item>
</Form>
</TabPane> */}
{/* 加载摄像头 */}
{/* <Form.Item hidden={!itemShow}>
<div>
<span style={{color:classColor(action)}}>{actionText(action)}</span>
<span hidden={!timerShow}>{Math.round(timer/1000)}</span>
</div>
</Form.Item> */}
{/* <video ref={video} width="382" height="200"></video> */}
{/* onClick={() => {hanleFaceSubmit(null, null);}} */}
<Form.Item
label=""
name="userName"
rules={[{ required: true, message: '请输入用户名!' }]}
>
<Input
prefix={
<UserOutlined style={{ fontSize: '18px' }} className="site-form-item-icon" />
}
placeholder="请输入用户名"
/>
</Form.Item>
<Form.Item>
{!whetherIE.current ? (<video ref={video} width="382" height="200"></video>) : (<FrameFaceLogin faceCompareEvent2={IELiveDetectFinish2} faceCompareEvent={IELiveDetectFinish} faceDetectStatusEvent={UpdateDetectStatus} />)}
</Form.Item>
<Form.Item>
<Button type="primary" className="w100" loading={submitLoading} htmlType="submit">
{submitLoading ? actionText(action, Math.round(timer / 1000)) : '登 录'}
</Button>
</Form.Item>
</Form>
</TabPane>
{/* 加载摄像头 */}
<Form.Item hidden={!itemShow}>
<div>
<span style={{ color: classColor(action) }}>{actionText(action)}</span>
<span hidden={!timerShow}>{Math.round(timer / 1000)}</span>
</div>
</Form.Item>
<video ref={video} width="382" height="200"></video>
{/* onClick={() => {hanleFaceSubmit(null, null);}} */}
</>}
</Tabs>
</div>
</div>

View File

@ -17,11 +17,19 @@ export async function changePass(params: any) {
*/
export async function rgbToBase64(params: any) {
const _body = JSON.stringify({//post请求参数
type: 'pixel',
type: 'pixel',
rgb: params.image
});
return request('/api/core-service-ebtp-userinfo/outer/v1/ebtp/face/rgbArray2Base64', {
method: 'post',
body:_body,
body: _body,
});
}
/**
* 是否显示人脸识别tab
* @param params
*/
export async function showFaceTab() {
return request('/api/biz-service-ebtp-extend//v1/BizFuncSwitchConfig/bizfuncswitchconfig/getFaceRecognitionFlag');
}