master
LiuJiaNan 2026-02-03 17:56:33 +08:00
parent 9092691340
commit fe2cdb82e6
13 changed files with 885 additions and 16 deletions

View File

@ -27,11 +27,14 @@
"@cqsjjb/jjb-react-admin-component": "latest",
"ahooks": "^3.9.5",
"antd": "^5.27.6",
"antd-mobile": "^5.42.3",
"antd-mobile-icons": "^0.3.0",
"dayjs": "^1.11.7",
"lodash-es": "^4.17.21",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"zy-react-library": "^1.1.41"
"react-signature-canvas": "^1.1.0-alpha.2",
"zy-react-library": "^1.1.42"
},
"devDependencies": {
"@antfu/eslint-config": "^5.4.1",

View File

@ -43,4 +43,8 @@
- `/primeport/container/stakeholder/personnelApplication/list` 人员申请
- `/primeport/container/stakeholder/vehicleApplication/list` 车辆申请
- `/primeport/container/stakeholder/personnelApplicationRecords/list` 人员申请记录
- `/primeport/container/stakeholder/vehicleApplicationRecords/list` 车辆申请记录
- `/primeport/container/stakeholder/vehicleApplicationRecords/list` 车辆申请记录
### H5端
- `/primeport/container/mobile/firstLevelDoor/personnelApplication/apply` 一级口门管理/人员申请/申请
- `/primeport/container/mobile/firstLevelDoor/personnelApplication/applyList` 一级口门管理/人员申请/申请记录

View File

@ -1,11 +1,7 @@
import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
export {};
// export const riskList = declareRequest(
// "loading",
// "Post > @/xxx",
// "dataSource: [] | res.data || [] & total: 0 | res.totalCount || 0 & pageIndex: 1 | res.pageIndex || 1 & pageSize: 10 | res.pageSize || 10",
// );
// export const riskDelete = declareRequest(
// "loading",
// "Delete > @/xxx/{id}",
// );
export const getDepartmentListTree = declareRequest(
"Post > @/basicInfo/department/listAllTreeByCorpType",
);

View File

@ -0,0 +1,161 @@
import { Image as AntdImage, Button, Popup, Toast } from "antd-mobile";
import dayjs from "dayjs";
import { useEffect, useRef, useState } from "react";
import SignatureCanvas from "react-signature-canvas";
import { base642File } from "zy-react-library/utils";
const SignatureH5 = (props) => {
const [signatureModalOpen, setSignatureModalOpen] = useState(false);
const signatureCanvas = useRef(null);
const [base64, setBase64] = useState("");
const [signatureClientHeight, setSignatureClientHeight] = useState("");
const [signatureClientWidth, setSignatureClientWidth] = useState("");
useEffect(() => {
if (signatureModalOpen) {
// setSignatureClientHeight(document.querySelector(".adm-popup-body").clientHeight - 50);
// setSignatureClientWidth(document.querySelector(".adm-popup-body").clientWidth - 100);
setSignatureClientHeight(window.innerHeight - 50);
setSignatureClientWidth(window.innerWidth - 100);
}
}, [signatureModalOpen]);
useEffect(() => {
setBase64(props.url);
}, [props.url]);
const rotateBase64Img = (src) => {
return new Promise((resolve) => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
let imgW;
let imgH;
let size;
const cutCor = { sx: 0, sy: 0, ex: 0, ey: 0 };
const image = new Image();
image.crossOrigin = "anonymous";
image.src = src;
image.onload = function () {
imgW = image.width;
imgH = image.height;
size = imgW > imgH ? imgW : imgH;
canvas.width = size * 2;
canvas.height = size * 2;
cutCor.sx = size;
cutCor.sy = size - imgW;
cutCor.ex = size + imgH;
cutCor.ey = size + imgW;
ctx.translate(size, size);
ctx.rotate((270 * Math.PI) / 180);
// ctx.scale(0.16, 0.16);
ctx.drawImage(image, 0, 0);
const imgData = ctx.getImageData(
cutCor.sx,
cutCor.sy,
cutCor.ex,
cutCor.ey,
);
canvas.width = imgH;
canvas.height = imgW;
ctx.putImageData(imgData, 0, 0);
resolve(canvas.toDataURL("image/png"));
};
});
};
const onOk = async () => {
if (signatureCanvas.current.isEmpty()) {
Toast.show({
icon: "fail",
content: "请签名",
});
return;
}
const result = signatureCanvas.current.toDataURL();
const base64 = await rotateBase64Img(result);
setBase64(base64);
props.onConfirm?.({
time: dayjs().format("YYYY-MM-DD HH:mm:ss"),
base64,
file: base642File(base64),
});
signatureCanvas.current.clear();
setSignatureModalOpen(false);
};
return (
<div>
<div>
<Button
color="primary"
onClick={() => {
setSignatureModalOpen(true);
}}
>
{base64 ? "重新签字" : "手写签字"}
</Button>
</div>
{base64 && (
<div style={{ border: "1px dashed #d9d9d9", width: "90%", height: "200px", marginTop: "16px", margin: "16px auto" }}>
<AntdImage src={base64} style={{ width: "100%", height: "200px", objectFit: "contain" }} />
</div>
)}
<Popup
position="right"
visible={signatureModalOpen}
bodyStyle={{ width: "100vw", height: "100vh" }}
>
<div style={{ backgroundColor: "#f5f5f5", width: "100%", height: "100%" }}>
<div style={{
position: "absolute",
left: "-200px",
top: "50%",
transform: "rotate(90deg)",
display: "flex",
gap: "30px",
}}
>
<Button style={{ padding: "7px 50px" }} onClick={() => signatureCanvas.current.clear()}>重签</Button>
<Button
style={{ padding: "7px 50px" }}
onClick={() => {
setSignatureModalOpen(false);
signatureCanvas.current.clear();
}}
>
取消
</Button>
<Button style={{ padding: "7px 50px" }} color="primary" onClick={onOk}>确定</Button>
</div>
<div style={{
border: "1px dashed #d9d9d9",
width: signatureClientWidth,
height: signatureClientHeight,
position: "absolute",
left: "55px",
top: "25px",
backgroundColor: "#fff",
}}
>
<SignatureCanvas
ref={signatureCanvas}
penColor="black"
canvasProps={{ width: signatureClientWidth, height: signatureClientHeight }}
/>
</div>
<div style={{
position: "absolute",
top: "50%",
right: "-18px",
transform: "rotate(90deg)",
fontSize: "18px",
}}
>
请横屏签字
</div>
</div>
</Popup>
</div>
);
};
export default SignatureH5;

View File

@ -0,0 +1,514 @@
import { Connect } from "@cqsjjb/jjb-dva-runtime";
import {
Button,
Cascader,
Checkbox,
DatePicker,
Form,
Image,
ImageUploader,
Input,
Picker,
Popup,
Toast,
} from "antd-mobile";
import dayjs from "dayjs";
import { useEffect, useRef, useState } from "react";
import useDictionary from "zy-react-library/hooks/useDictionary";
import { ID_NUMBER, LICENSE_PLATE_NUMBER, PHONE } from "zy-react-library/regular";
import { validatorEndTime } from "zy-react-library/utils";
import SignatureH5 from "~/components/SignatureH5";
import { NS_GLOBAL } from "~/enumerate/namespace";
import "../../../index.less";
function Apply(props) {
const [primeportAreaList, setPrimeportAreaList] = useState([]);
const [vehicleTypeList, setVehicleTypeList] = useState([]);
const [licensePlateTypeList, setLicensePlateTypeList] = useState([]);
const [departmentList, setDepartmentList] = useState([]);
const [noticePopupVisible, setNoticePopupVisible] = useState(false);
const [signatureUrl, setSignatureUrl] = useState("");
const checkboxRef = useRef(null);
const [form] = Form.useForm();
const accessType = Form.useWatch("accessType", form);
const doorType = Form.useWatch("doorType", form);
const { getDictionary } = useDictionary();
const transformDepartmentList = (list) => {
return list.map(item => ({
label: item.name,
value: item.id,
children: item.childrenList ? transformDepartmentList(item.childrenList) : undefined,
}));
};
const getData = async () => {
const primeportAreaData = await getDictionary({ dictValue: "primeport_area" });
setPrimeportAreaList(primeportAreaData);
const vehicleTypeData = await getDictionary({ dictValue: "VEHICLE_TYPE" });
setVehicleTypeList(vehicleTypeData);
const licensePlateTypeData = await getDictionary({ dictValue: "LICENSE_PLATE_TYPE" });
setLicensePlateTypeList(licensePlateTypeData);
const { data: departmentList } = await props["getDepartmentListTree"]({ enterpriseType: [1, 2] });
const transformedDepartmentList = transformDepartmentList(departmentList);
setDepartmentList(transformedDepartmentList);
};
useEffect(() => {
getData();
}, []);
const onFinish = (values) => {
if (!values.safetyNoticeAgreed || !values.signature) {
Toast.show({
icon: "fail",
content: "请勾选《安全进港须知》并签字",
});
return;
}
console.log(values);
props.history.push(`./success?accessType=${values.accessType}&text=${values.accessType === "1" ? values.licensePlateNumber : values.phoneNumber}`);
};
return (
<div style={{ padding: "16px" }}>
<Form
form={form}
preserve={false}
layout="horizontal"
onFinish={onFinish}
footer={(
<Button block type="submit" shape="rounded" color="primary">
提交申请
</Button>
)}
>
<Form.Item
name="accessType"
label="访问类型"
rules={[{ required: true, message: "请选择访问类型" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => value[0]}
getValueProps={value => [value]}
>
<Picker
columns={[[
{ label: "车辆", value: "1" },
{ label: "人员", value: "2" },
]]}
>
{value => value?.[0]?.label || "请选择访问类型"}
</Picker>
</Form.Item>
<Form.Item
name="doorType"
label="选择申请口门"
rules={[{ required: true, message: "请选择选择申请口门" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => value[0]}
getValueProps={value => [value]}
>
<Picker
columns={[[
{ label: "一级口门", value: "1" },
{ label: "封闭区域口门", value: "2" },
]]}
>
{value => value?.[0]?.label || "请选择选择申请口门"}
</Picker>
</Form.Item>
{
accessType === "1"
&& (
<>
<Form.Item name="driverName" label="驾驶人姓名" rules={[{ required: true }]}>
<Input placeholder="请输入驾驶人姓名" />
</Form.Item>
<BasicInfoFields />
<Form.Item
name="vehicleType"
label="车辆类型"
rules={[{ required: true, message: "请选择车辆类型" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => value[0]}
getValueProps={value => [value]}
>
<Picker
columns={[vehicleTypeList.map(item => ({ label: item.dictLabel, value: item.dictValue }))]}
>
{value => value?.[0]?.label || "请选择车辆类型"}
</Picker>
</Form.Item>
<Form.Item
name="licensePlateType"
label="车牌类型"
rules={[{ required: true, message: "请选择车牌类型" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => value[0]}
getValueProps={value => [value]}
>
<Picker
columns={[licensePlateTypeList.map(item => ({ label: item.dictLabel, value: item.dictValue }))]}
>
{value => value?.[0]?.label || "请选择车牌类型"}
</Picker>
</Form.Item>
<Form.Item name="licensePlateNumber" label="车牌号" rules={[{ required: true }, { pattern: LICENSE_PLATE_NUMBER, message: "请输入正确的车牌号" }]}>
<Input placeholder="请输入车牌号" />
</Form.Item>
<VisitTime form={form} />
<LocationFields primeportAreaList={primeportAreaList} doorType={doorType} />
<Form.Item name="vehicleLicensePhoto" label="行驶证照片" rules={[{ required: true, message: "请上传行驶证照片" }]}>
<ImageUploader
upload={file => ({ url: URL.createObjectURL(file), file })}
maxCount={2}
/>
</Form.Item>
<Form.Item name="vehiclePhoto" label="车辆照片" rules={[{ required: true, message: "请上传车辆照片" }]}>
<ImageUploader
upload={file => ({ url: URL.createObjectURL(file), file })}
maxCount={4}
/>
</Form.Item>
<Approval departmentList={departmentList} />
<SafetyNoticeAndSignature
checkboxRef={checkboxRef}
signatureUrl={signatureUrl}
setNoticePopupVisible={setNoticePopupVisible}
/>
</>
)
}
{
accessType === "2"
&& (
<>
<Form.Item name="visitorName" label="访问人姓名" rules={[{ required: true }]}>
<Input placeholder="请输入访问人姓名" />
</Form.Item>
<BasicInfoFields />
<VisitTime form={form} />
<LocationFields primeportAreaList={primeportAreaList} doorType={doorType} />
<Form.Item name="facePhoto" label="人脸照片" rules={[{ required: true, message: "请上传人脸照片" }]}>
<ImageUploader
upload={file => ({ url: URL.createObjectURL(file), file })}
maxCount={1}
/>
</Form.Item>
<Approval departmentList={departmentList} />
<SafetyNoticeAndSignature
checkboxRef={checkboxRef}
signatureUrl={signatureUrl}
setNoticePopupVisible={setNoticePopupVisible}
/>
</>
)
}
</Form>
<Popup
position="right"
visible={noticePopupVisible}
showCloseButton
onClose={() => {
setNoticePopupVisible(false);
}}
>
<div style={{ padding: "40px 20px", overflowY: "auto", height: "100vh" }}>
<p style={{ textAlign: "justify", textIndent: "2rem" }}>欢迎您到访秦皇岛港为保障您的人身安全及港口生产作业秩序请注意港口属于重点安全监管区域存在大型机械作业货物装卸车辆往来等生产场景可能面临机械伤害物体打击车辆碰撞等安全风险请您认真阅读以下须知内容确认遵守后签字</p>
<p style={{ textAlign: "justify", textIndent: "2rem" }}>1. 入港时请主动出示有效身份证件配合安保人员进行身份核验与信息登记凭港口核发的临时访客证入港自觉接受出港查验不转借冒用访客凭证不将无关人员带入港口</p>
<p style={{ textAlign: "justify", textIndent: "2rem" }}>2. 入港后请严格在指定区域活动未经陪同人员及港口负责人许可绝不擅自进入标有"禁止入内""危险区域"等标识的场所不靠近起重机械输送设备危险品存储点等高危部位不跨越安全护栏警戒线不在作业区域逗留围观</p>
<p style={{ textAlign: "justify", textIndent: "2rem" }}>3. 遵守港口生产秩序不干扰装卸运输检修等正常工作不随意触摸操作生产设备仪器仪表及安全设施不移动遮挡安全警示标识如需拍摄港口场景须提前征得港口方同意不拍摄涉及安全商业秘密的内容</p>
<p style={{ textAlign: "justify", textIndent: "2rem" }}>4. 严格遵守消防安全规定不在港口内吸烟不携带火种易燃易爆物品管制器具等违禁物品入港发现火灾设备故障等隐患或突发情况第一时间告知陪同人员或港口工作人员配合应急处置不擅自行动引发次生风险</p>
<p style={{ textAlign: "justify", textIndent: "2rem" }}>5. 注意自身安全防护行走时主动避让作业车辆与机械不擅自横穿作业通道雨天雾天等恶劣天气下听从陪同人员安排加强安全防范</p>
<p style={{ textAlign: "justify", textIndent: "2rem" }}>6. 已知晓港口所去区域应急逃生路线遇紧急情况按港口指引有序疏散</p>
<p>本人确认已完整阅读并理解以上须知承诺严格遵守如因违反本须知及港口安全规定导致自身人身伤害或港口他人财产损失自愿承担全部责任</p>
<SignatureH5
onConfirm={(value) => {
setSignatureUrl(value.base64);
form.setFieldValue("signature", value.file);
}}
url={signatureUrl}
/>
<div style={{ marginTop: "20px" }}>
<Button
block
shape="rounded"
color="primary"
onClick={() => {
if (!signatureUrl) {
Toast.show({
icon: "fail",
content: "请签名",
});
return;
}
setNoticePopupVisible(false);
checkboxRef.current.check();
}}
>
完成
</Button>
</div>
</div>
</Popup>
</div>
);
}
// 公共基础信息字段组件
const BasicInfoFields = () => (
<>
<Form.Item name="phoneNumber" label="手机号" rules={[{ required: true }, { pattern: PHONE, message: "请输入正确的手机号" }]}>
<Input placeholder="请输入手机号" />
</Form.Item>
<Form.Item name="idNumber" label="身份证号" rules={[{ required: true }, { pattern: ID_NUMBER, message: "请输入正确的身份证号" }]}>
<Input placeholder="请输入身份证号" />
</Form.Item>
</>
);
// 公共访问时间组件
const VisitTime = ({ form }) => (
<>
<Form.Item
name="visitStartTime"
label="访问起始时间"
rules={[{ required: true, message: "请选择访问起始时间" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => dayjs(value).format("YYYY-MM-DD")}
getValueProps={value => dayjs(value)}
>
<DatePicker>
{value => value ? dayjs(value).format("YYYY-MM-DD") : "请选择访问起始时间"}
</DatePicker>
</Form.Item>
<Form.Item
name="visitEndTime"
label="访问结束时间"
rules={[{ required: true, message: "请选择访问结束时间" }, (() => validatorEndTime(form.getFieldValue("visitStartTime")))()]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => dayjs(value).format("YYYY-MM-DD")}
getValueProps={value => dayjs(value)}
>
<DatePicker>
{value => value ? dayjs(value).format("YYYY-MM-DD") : "请选择访问结束时间"}
</DatePicker>
</Form.Item>
</>
);
// 公共地点字段组件
const LocationFields = ({ primeportAreaList, doorType }) => (
<>
<Form.Item
name="portArea"
label="港区"
rules={[{ required: true, message: "请选择港区" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => value[0]}
getValueProps={value => [value]}
>
<Picker
columns={[primeportAreaList.map(item => ({ label: item.dictLabel, value: item.dictValue }))]}
>
{value => value?.[0]?.label || "请选择港区"}
</Picker>
</Form.Item>
<Form.Item
name="firstLevelDoor"
label="一级口门"
rules={[{ required: true, message: "请选择一级口门" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => value[0]}
getValueProps={value => [value]}
>
<Picker
columns={[[
{ label: "一级口门1", value: "1" },
{ label: "一级口门2", value: "2" },
]]}
>
{value => value?.[0]?.label || "请选择一级口门"}
</Picker>
</Form.Item>
{doorType === "2" && <EnclosedAreaFields />}
</>
);
// 封闭区域相关字段组件
const EnclosedAreaFields = () => (
<>
<Form.Item
name="areaCompany"
label="区域所属公司"
rules={[{ required: true, message: "请选择区域所属公司" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => value[0]}
getValueProps={value => [value]}
>
<Picker
columns={[[
{ label: "区域所属公司1", value: "1" },
{ label: "区域所属公司2", value: "2" },
]]}
>
{value => value?.[0]?.label || "请选择区域所属公司"}
</Picker>
</Form.Item>
<Form.Item
name="enclosedArea"
label="封闭区域"
rules={[{ required: true, message: "请选择封闭区域" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => value[0]}
getValueProps={value => [value]}
>
<Picker
columns={[[
{ label: "封闭区域1", value: "1" },
{ label: "封闭区域2", value: "2" },
]]}
>
{value => value?.[0]?.label || "请选择封闭区域"}
</Picker>
</Form.Item>
<Form.Item
name="enclosedAreaDoor"
label="口门"
rules={[{ required: true, message: "请选择口门" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => value[0]}
getValueProps={value => [value]}
>
<Picker
columns={[[
{ label: "口门1", value: "1" },
{ label: "口门2", value: "2" },
]]}
>
{value => value?.[0]?.label || "请选择口门"}
</Picker>
</Form.Item>
</>
);
// 公共审批字段组件
const Approval = ({ departmentList }) => (
<>
<Form.Item
name="approvalEnterprise"
label="审批企业"
rules={[{ required: true, message: "请选择审批企业" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
>
<Cascader options={departmentList}>
{value => value.length > 0 ? value.map(item => item?.label).filter(Boolean).join("-") : "请选择审批企业"}
</Cascader>
</Form.Item>
<Form.Item
name="approvalPerson"
label="审批人"
rules={[{ required: true, message: "请选择审批人" }]}
trigger="onConfirm"
onClick={(_, pickerRef) => {
pickerRef.current?.open();
}}
getValueFromEvent={value => value[0]}
getValueProps={value => [value]}
>
<Picker
columns={[[
{ label: "审批人1", value: "1" },
{ label: "审批人2", value: "2" },
]]}
>
{value => value?.[0]?.label || "请选择审批人"}
</Picker>
</Form.Item>
</>
);
// 安全须知和签名组件
const SafetyNoticeAndSignature = ({ checkboxRef, signatureUrl, setNoticePopupVisible }) => (
<>
<Form.Item
name="safetyNoticeAgreed"
required={false}
label=""
rules={[{ required: true, message: "请勾选" }]}
>
<Checkbox style={{ "--icon-size": "18px", "--font-size": "14px", "--gap": "6px" }} ref={checkboxRef}>
<div style={{ fontSize: "14px" }}>
<span>我已阅读并同意</span>
<span
style={{ color: "#1677ff" }}
onClick={() => {
checkboxRef.current.check();
setNoticePopupVisible(true);
}}
>
安全进港须知
</span>
</div>
</Checkbox>
</Form.Item>
<Form.Item name="signature" noStyle>
<input type="hidden" />
</Form.Item>
<Form.Item noStyle>
{signatureUrl && (
<div style={{
border: "1px dashed #d9d9d9",
width: "90%",
height: "200px",
marginTop: "16px",
margin: "16px auto",
}}
>
<Image src={signatureUrl} style={{ width: "100%", height: "200px", objectFit: "contain" }} />
</div>
)}
</Form.Item>
</>
);
export default Connect([NS_GLOBAL], true)(Apply);

View File

@ -0,0 +1,127 @@
import { DotLoading, InfiniteScroll } from "antd-mobile";
import { useState } from "react";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
function ApplyList() {
const query = useGetUrlQuery();
const [data, setData] = useState([]);
const [hasMore, setHasMore] = useState(true);
const loadMore = async () => {
const data = [
{ name: "张三", phone: "12345678901", area: "A区", doorTypeName: "1号门", startTime: "2021-01-01 00:00:00", endTime: "2021-01-01 01:00:00", status: "通过", reason: "" },
];
setData(val => [...val, ...data]);
setHasMore(data.length > 0);
};
return (
<div>
<div style={{ backgroundColor: "#f9f9f9", padding: "10px" }}>
{data.map((item, index) => (
<div key={index} style={{ backgroundColor: "#fff", padding: "10px", marginBottom: "10px", borderRadius: "5px" }}>
{
query.accessType === "2" && (
<div>
<div style={{ fontSize: "16px", fontWeight: "bold" }}>临时访客申请</div>
<div>
申请人
{item.name}
</div>
<div>
手机号
{item.phone}
</div>
<div>
申请区域
{item.area}
</div>
<div>
申请口门
{item.doorTypeName}
</div>
<div>
时间范围
{item.startTime}
{item.endTime}
</div>
<div>
审核状态
{item.status}
</div>
<div>
驳回原因
{item.reason}
</div>
</div>
)
}
{
query.accessType === "1" && (
<div>
<div style={{ fontSize: "16px", fontWeight: "bold" }}>临时访客车辆申请</div>
<div>
申请人
{item.name}
</div>
<div>
手机号
{item.phone}
</div>
<div>
申请区域
{item.area}
</div>
<div>
申请口门
{item.doorTypeName}
</div>
<div>
时间范围
{item.startTime}
{item.endTime}
</div>
<div>
车辆类型
{item.carType}
</div>
<div>
车牌号
{item.carNo}
</div>
<div>
审核状态
{item.status}
</div>
<div>
驳回原因
{item.reason}
</div>
</div>
)
}
</div>
))}
</div>
<InfiniteScroll loadMore={loadMore} hasMore={hasMore}>
{
hasMore
? (
<>
<span>Loading</span>
<DotLoading />
</>
)
: (
<span>--- 我是有底线的 ---</span>
)
}
</InfiniteScroll>
</div>
);
}
export default ApplyList;

View File

@ -0,0 +1,23 @@
import { QRCode } from "antd";
import { CheckCircleFill } from "antd-mobile-icons";
import useGetUrlQuery from "zy-react-library/hooks/useGetUrlQuery";
function Success() {
const query = useGetUrlQuery();
return (
<div style={{ padding: "20px" }}>
<div style={{ textAlign: "center", paddingTop: "30px" }}>
<CheckCircleFill fontSize={48} color="var(--adm-color-primary)" />
<div style={{ paddingTop: "10px" }}>信息提交成功</div>
</div>
<div style={{ textAlign: "center", marginTop: "50px" }}>
<QRCode value={`${window.location.origin}/primeport/container/mobile/firstLevelDoor/personnelApplication/applyList?accessType=${query.accessType}&text=${query.text}`} style={{ margin: "0 auto", marginBottom: 10 }} />
<div style={{ paddingTop: "20px" }}>扫描识别二维码获取审批进度</div>
<div style={{ color: "red", fontSize: 12, paddingTop: "10px" }}>请长按或截屏保存二维码关闭页面后将无法再获取二维码</div>
</div>
</div>
);
}
export default Success;

View File

@ -0,0 +1,5 @@
function PersonnelApplication(props) {
return props.children;
}
export default PersonnelApplication;

View File

@ -0,0 +1,5 @@
function firstLevelDoor(props) {
return props.children;
}
export default firstLevelDoor;

View File

@ -0,0 +1,5 @@
function Mobile(props) {
return props.children;
}
export default Mobile;

View File

@ -0,0 +1,11 @@
.adm-list, .adm-input {
--font-size: var(--adm-font-size-6);
}
.adm-button {
font-size: var(--adm-font-size-6);
}
.adm-list-item-content-prefix {
width: 130px;
}

View File

@ -14,6 +14,8 @@ function Add(props) {
const [addPersonnelModalVisible, setAddPersonnelModalVisible] = useState(false);
const [needToKnowModalVisible, setNeedToKnowModalVisible] = useState(false);
const signatureUrl = useRef("");
const [form] = Form.useForm();
const onSubmit = async (values) => {
@ -137,12 +139,13 @@ function Add(props) {
{
needToKnowModalVisible && (
<NeedToKnowModal
signatureUrl={form.getFieldValue("todo8")}
signatureUrl={signatureUrl.current}
onCancel={() => {
setNeedToKnowModalVisible(false);
}}
onOk={(values) => {
form.setFieldValue("todo8", values);
signatureUrl.current = values.base64;
setNeedToKnowModalVisible(false);
}}
/>
@ -198,6 +201,7 @@ const AddPersonnelModalComponent = (props) => {
const NeedToKnowModal = (props) => {
const signatureUrl = useRef("");
const signatureFile = useRef({});
return (
<Modal
@ -211,7 +215,10 @@ const NeedToKnowModal = (props) => {
message.warning("请签名");
return;
}
props.onOk(signatureUrl.current);
props.onOk({
base64: signatureUrl.current,
file: signatureFile.current,
});
}}
>
<div>
@ -227,6 +234,7 @@ const NeedToKnowModal = (props) => {
<Signature
onConfirm={(value) => {
signatureUrl.current = value.base64;
signatureFile.current = value.file;
}}
url={props.signatureUrl}
/>

View File

@ -14,6 +14,7 @@ import { NS_VEHICLE_APPLICATION } from "~/enumerate/namespace";
function Add(props) {
const [needToKnowModalVisible, setNeedToKnowModalVisible] = useState(false);
const signatureUrl = useRef("");
const [form] = Form.useForm();
const todo7 = Form.useWatch("todo7", form);
@ -83,12 +84,13 @@ function Add(props) {
{
needToKnowModalVisible && (
<NeedToKnowModal
signatureUrl={form.getFieldValue("todo8")}
signatureUrl={signatureUrl.current}
onCancel={() => {
setNeedToKnowModalVisible(false);
}}
onOk={(values) => {
form.setFieldValue("todo8", values);
form.setFieldValue("todo8", values.file);
signatureUrl.current = values.base64;
setNeedToKnowModalVisible(false);
}}
/>
@ -100,6 +102,7 @@ function Add(props) {
const NeedToKnowModal = (props) => {
const signatureUrl = useRef("");
const signatureFile = useRef({});
return (
<Modal
@ -113,7 +116,10 @@ const NeedToKnowModal = (props) => {
message.warning("请签名");
return;
}
props.onOk(signatureUrl.current);
props.onOk({
base64: signatureUrl.current,
file: signatureFile.current,
});
}}
>
<div>
@ -129,6 +135,7 @@ const NeedToKnowModal = (props) => {
<Signature
onConfirm={(value) => {
signatureUrl.current = value.base64;
signatureFile.current = value.file;
}}
url={props.signatureUrl}
/>