改bug
parent
73dfb213a0
commit
fe9f1ccee9
|
|
@ -10,7 +10,7 @@ export const temporaryPersonnelList = declareRequest(
|
||||||
);
|
);
|
||||||
export const temporaryPersonnelAdd = declareRequest(
|
export const temporaryPersonnelAdd = declareRequest(
|
||||||
"temporaryPersonnelLoading",
|
"temporaryPersonnelLoading",
|
||||||
`Post > @/primeport/vehicleApply/saveTemporaryVisitors`,
|
`Post > @/primeport/personApply/xgfPersonSave`,
|
||||||
);
|
);
|
||||||
export const temporaryPersonnelInfo = declareRequest(
|
export const temporaryPersonnelInfo = declareRequest(
|
||||||
"temporaryPersonnelLoading",
|
"temporaryPersonnelLoading",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { declareRequest } from "@cqsjjb/jjb-dva-runtime";
|
||||||
|
|
||||||
export const temporaryVehicleAdd = declareRequest(
|
export const temporaryVehicleAdd = declareRequest(
|
||||||
"temporaryVehicleLoading",
|
"temporaryVehicleLoading",
|
||||||
`Post > @/primeport/vehicleApply/saveTemporaryVisitors`,
|
`Post > @/primeport/vehicleApply/save`,
|
||||||
);
|
);
|
||||||
export const temporaryVehicleReviewList = declareRequest(
|
export const temporaryVehicleReviewList = declareRequest(
|
||||||
"temporaryVehicleLoading",
|
"temporaryVehicleLoading",
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,9 @@ function AddModalComponent(props) {
|
||||||
if (data?.available) {
|
if (data?.available) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
if(!data.available){
|
||||||
|
form.setFieldValue("userId", undefined);
|
||||||
|
}
|
||||||
throw new Error(data?.availableMessage || "该审批人已录入,不可重复添加");
|
throw new Error(data?.availableMessage || "该审批人已录入,不可重复添加");
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,7 @@ function RelatedVehicles(props) {
|
||||||
<ReviewModal
|
<ReviewModal
|
||||||
id={currentId}
|
id={currentId}
|
||||||
vehicleApplyId={currentVehicleApplyId}
|
vehicleApplyId={currentVehicleApplyId}
|
||||||
|
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
setReviewModalVisible(false);
|
setReviewModalVisible(false);
|
||||||
setCurrentId("");
|
setCurrentId("");
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import { ID_NUMBER, PHONE } from "zy-react-library/regular";
|
||||||
import { getLabelName, validatorEndTime, validatorTimeGECurrentDay } from "zy-react-library/utils";
|
import { getLabelName, validatorEndTime, validatorTimeGECurrentDay } from "zy-react-library/utils";
|
||||||
import { NS_APPROVER_USER, NS_FIRST_LEVEL_DOOR_INFO, NS_TEMPORARY_PERSONNEL } from "~/enumerate/namespace";
|
import { NS_APPROVER_USER, NS_FIRST_LEVEL_DOOR_INFO, NS_TEMPORARY_PERSONNEL } from "~/enumerate/namespace";
|
||||||
|
|
||||||
|
|
||||||
function Add(props) {
|
function Add(props) {
|
||||||
const [form] = FormBuilder.useForm();
|
const [form] = FormBuilder.useForm();
|
||||||
const gateLevelAuthArea = FormBuilder.useWatch("gateLevelAuthArea", form);
|
const gateLevelAuthArea = FormBuilder.useWatch("gateLevelAuthArea", form);
|
||||||
|
|
@ -45,14 +46,15 @@ function Add(props) {
|
||||||
files: values.userFace,
|
files: values.userFace,
|
||||||
params: { type: UPLOAD_FILE_TYPE_ENUM[608] },
|
params: { type: UPLOAD_FILE_TYPE_ENUM[608] },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { success } = await props["temporaryPersonnelAdd"]({
|
const { success } = await props["temporaryPersonnelAdd"]({
|
||||||
...values,
|
...values,
|
||||||
personBelongType: 4,
|
personBelongType: 4,
|
||||||
personApplyList: [
|
personApplyList: [
|
||||||
{ userFaceUrl },
|
{ userFaceUrl,
|
||||||
{ employeePersonUserName: values.employeePersonUserName },
|
employeePersonUserName: values.employeePersonUserName ,
|
||||||
{ userPhone: values.userPhone },
|
userPhone: values.userPhone ,
|
||||||
{ userCard: btoa(values.userCard) },
|
userCard: btoa(values.userCard) },
|
||||||
],
|
],
|
||||||
gateLevelAuthArea: JSON.stringify({ area: values.area }),
|
gateLevelAuthArea: JSON.stringify({ area: values.area }),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import useGetFile from "zy-react-library/hooks/useGetFile";
|
||||||
import useTable from "zy-react-library/hooks/useTable";
|
import useTable from "zy-react-library/hooks/useTable";
|
||||||
import { getLabelName } from "zy-react-library/utils";
|
import { getLabelName } from "zy-react-library/utils";
|
||||||
import { NS_FIRST_LEVEL_DOOR_INFO, NS_TEMPORARY_PERSONNEL } from "~/enumerate/namespace";
|
import { NS_FIRST_LEVEL_DOOR_INFO, NS_TEMPORARY_PERSONNEL } from "~/enumerate/namespace";
|
||||||
|
import { UseDecodeIdCard } from "~/utils";
|
||||||
const STATUS_ENUM = [
|
const STATUS_ENUM = [
|
||||||
{ bianma: "1", name: "审核中" },
|
{ bianma: "1", name: "审核中" },
|
||||||
{ bianma: "2", name: "通过" },
|
{ bianma: "2", name: "通过" },
|
||||||
|
|
@ -99,7 +99,7 @@ function List(props) {
|
||||||
{
|
{
|
||||||
title: "身份证号",
|
title: "身份证号",
|
||||||
dataIndex: "userCard",
|
dataIndex: "userCard",
|
||||||
render: (_, record) => record.userCard ? atob(record.userCard) : "",
|
render: (_, record) => UseDecodeIdCard(record.userCard),
|
||||||
},
|
},
|
||||||
{ title: "来访事由", dataIndex: "reasonVisit" },
|
{ title: "来访事由", dataIndex: "reasonVisit" },
|
||||||
{ title: "访问开始时间", dataIndex: "visitStartTime" },
|
{ title: "访问开始时间", dataIndex: "visitStartTime" },
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import {
|
||||||
NS_TEMPORARY_VEHICLE,
|
NS_TEMPORARY_VEHICLE,
|
||||||
NS_VEHICLE_APPLY,
|
NS_VEHICLE_APPLY,
|
||||||
} from "~/enumerate/namespace";
|
} from "~/enumerate/namespace";
|
||||||
|
import {VEHICLE_TYPE_ENUM} from "~/enumerate/constant";
|
||||||
|
|
||||||
function Add(props) {
|
function Add(props) {
|
||||||
const [form] = FormBuilder.useForm();
|
const [form] = FormBuilder.useForm();
|
||||||
|
|
@ -60,10 +61,12 @@ function Add(props) {
|
||||||
files: values.attachmentFile,
|
files: values.attachmentFile,
|
||||||
params: { type: UPLOAD_FILE_TYPE_ENUM[602], foreignKey: "" },
|
params: { type: UPLOAD_FILE_TYPE_ENUM[602], foreignKey: "" },
|
||||||
});
|
});
|
||||||
|
|
||||||
const { success } = await props["temporaryVehicleAdd"]({
|
const { success } = await props["temporaryVehicleAdd"]({
|
||||||
...values,
|
...values,
|
||||||
drivingLicenseId,
|
drivingLicenseId,
|
||||||
attachmentId,
|
attachmentId,
|
||||||
|
lsUserIdcard: btoa(values.lsUserIdcard),
|
||||||
gateLevelAuthArea: JSON.stringify({ area: values.area }),
|
gateLevelAuthArea: JSON.stringify({ area: values.area }),
|
||||||
});
|
});
|
||||||
if (success) {
|
if (success) {
|
||||||
|
|
@ -139,6 +142,13 @@ function Add(props) {
|
||||||
render: FORM_ITEM_RENDER_ENUM.DATE,
|
render: FORM_ITEM_RENDER_ENUM.DATE,
|
||||||
rules: [validatorEndTime({ startTime: visitStartTime })],
|
rules: [validatorEndTime({ startTime: visitStartTime })],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "vehicleBelongType",
|
||||||
|
label: "车辆所属类型",
|
||||||
|
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||||
|
items:VEHICLE_TYPE_ENUM
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "gateLevelAuthArea",
|
name: "gateLevelAuthArea",
|
||||||
label: "访问港区",
|
label: "访问港区",
|
||||||
|
|
@ -174,14 +184,14 @@ function Add(props) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{ name: "mkmjName", label: "访问口门名称", onlyForLabel: true },
|
{ name: "mkmjName", label: "访问口门名称", onlyForLabel: true },
|
||||||
{ name: "reasonVisit", label: "来访事由", span: 24, render: FORM_ITEM_RENDER_ENUM.TEXTAREA },
|
{ name: "remarks", label: "来访事由", span: 24, render: FORM_ITEM_RENDER_ENUM.TEXTAREA },
|
||||||
{
|
{
|
||||||
name: "drivingLicenseFile",
|
name: "drivingLicenseFile",
|
||||||
label: "行驶证照片",
|
label: "行驶证照片",
|
||||||
span: 24,
|
span: 24,
|
||||||
render: (
|
render: (
|
||||||
<Upload
|
<Upload
|
||||||
maxCount={1}
|
maxCount={2}
|
||||||
size={5}
|
size={5}
|
||||||
tipContent={(
|
tipContent={(
|
||||||
<div style={{ color: "red", fontSize: 12 }}>
|
<div style={{ color: "red", fontSize: 12 }}>
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import useTable from "zy-react-library/hooks/useTable";
|
||||||
import { getLabelName } from "zy-react-library/utils";
|
import { getLabelName } from "zy-react-library/utils";
|
||||||
import { VEHICLE_AUDIT_STATUS_ENUM } from "~/enumerate/constant";
|
import { VEHICLE_AUDIT_STATUS_ENUM } from "~/enumerate/constant";
|
||||||
import { NS_FIRST_LEVEL_DOOR_INFO, NS_TEMPORARY_VEHICLE, NS_VEHICLE_APPLY, NS_VEHICLE_AUDIT } from "~/enumerate/namespace";
|
import { NS_FIRST_LEVEL_DOOR_INFO, NS_TEMPORARY_VEHICLE, NS_VEHICLE_APPLY, NS_VEHICLE_AUDIT } from "~/enumerate/namespace";
|
||||||
|
import {UseDecodeIdCard} from "~/utils";
|
||||||
|
|
||||||
function List(props) {
|
function List(props) {
|
||||||
const [qrCodeModalVisible, setQrCodeModalVisible] = useState(false);
|
const [qrCodeModalVisible, setQrCodeModalVisible] = useState(false);
|
||||||
|
|
@ -28,7 +29,7 @@ function List(props) {
|
||||||
const [form] = Search.useForm();
|
const [form] = Search.useForm();
|
||||||
const { tableProps, getData } = useTable(props["vehicleAuditList"], {
|
const { tableProps, getData } = useTable(props["vehicleAuditList"], {
|
||||||
form,
|
form,
|
||||||
params: { vehicleBelongTypeArr: "6", processOrRecord: !props.isRecords ? 1 : 2 },
|
params: { processOrRecord: !props.isRecords ? 1 : 2 },
|
||||||
});
|
});
|
||||||
|
|
||||||
const getFirstLevelDoorInfoListAll = async () => {
|
const getFirstLevelDoorInfoListAll = async () => {
|
||||||
|
|
@ -49,9 +50,9 @@ function List(props) {
|
||||||
{ name: "licenceNo", label: "车牌号" },
|
{ name: "licenceNo", label: "车牌号" },
|
||||||
{ name: "visitStartTime", label: "访问开始时间", render: FORM_ITEM_RENDER_ENUM.DATE },
|
{ name: "visitStartTime", label: "访问开始时间", render: FORM_ITEM_RENDER_ENUM.DATE },
|
||||||
{ name: "visitEndTime", label: "访问结束时间", render: FORM_ITEM_RENDER_ENUM.DATE },
|
{ name: "visitEndTime", label: "访问结束时间", render: FORM_ITEM_RENDER_ENUM.DATE },
|
||||||
{ name: "auditStatus", label: "审批状态", render: FORM_ITEM_RENDER_ENUM.SELECT, items: VEHICLE_AUDIT_STATUS_ENUM },
|
{ name: "processOrRecord", label: "审批状态", render: FORM_ITEM_RENDER_ENUM.SELECT, items: VEHICLE_AUDIT_STATUS_ENUM },
|
||||||
{
|
{
|
||||||
name: "todo6",
|
name: "gateLevelAuthAreaId",
|
||||||
label: "访问口门名称",
|
label: "访问口门名称",
|
||||||
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
render: FORM_ITEM_RENDER_ENUM.SELECT,
|
||||||
items: firstLevelDoorInfoListAll,
|
items: firstLevelDoorInfoListAll,
|
||||||
|
|
@ -90,7 +91,7 @@ function List(props) {
|
||||||
columns={[
|
columns={[
|
||||||
{ title: "访问人姓名", dataIndex: "employeeVehicleUserName" },
|
{ title: "访问人姓名", dataIndex: "employeeVehicleUserName" },
|
||||||
{ title: "手机号", dataIndex: "lsUserPhone" },
|
{ title: "手机号", dataIndex: "lsUserPhone" },
|
||||||
{ title: "身份证号", dataIndex: "lsUserIdcard" },
|
{ title: "身份证号", dataIndex: "lsUserIdcard",render: (_, record) => UseDecodeIdCard(record.lsUserIdcard), },
|
||||||
{ title: "车牌号", dataIndex: "licenceNo" },
|
{ title: "车牌号", dataIndex: "licenceNo" },
|
||||||
{ title: "车牌类型", dataIndex: "licenceTypeName" },
|
{ title: "车牌类型", dataIndex: "licenceTypeName" },
|
||||||
{ title: "车辆类型", dataIndex: "vehicleTypeName" },
|
{ title: "车辆类型", dataIndex: "vehicleTypeName" },
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,11 @@ function View(props) {
|
||||||
eqForeignKey: data.drivingLicenseId,
|
eqForeignKey: data.drivingLicenseId,
|
||||||
});
|
});
|
||||||
const attachmentFile = await getFile({ eqType: UPLOAD_FILE_TYPE_ENUM[602], eqForeignKey: data.attachmentId });
|
const attachmentFile = await getFile({ eqType: UPLOAD_FILE_TYPE_ENUM[602], eqForeignKey: data.attachmentId });
|
||||||
const informSignFile = await getFile({ eqType: UPLOAD_FILE_TYPE_ENUM[606], eqForeignKey: data.informSignId });
|
let informSignFile = []
|
||||||
|
if(data.informSignId){
|
||||||
|
informSignFile = await getFile({ eqType: UPLOAD_FILE_TYPE_ENUM[606], eqForeignKey: data.informSignId })
|
||||||
|
}
|
||||||
|
console.log(informSignFile);
|
||||||
setInfo({
|
setInfo({
|
||||||
...data,
|
...data,
|
||||||
drivingLicenseFile,
|
drivingLicenseFile,
|
||||||
|
|
@ -54,10 +58,10 @@ function View(props) {
|
||||||
{ label: "访问结束时间", children: info.visitEndTime },
|
{ label: "访问结束时间", children: info.visitEndTime },
|
||||||
{ label: "访问港区", children: info.gateLevelAuthArea && JSON.parse(info.gateLevelAuthArea).area.map(item => item.value).join("、") },
|
{ label: "访问港区", children: info.gateLevelAuthArea && JSON.parse(info.gateLevelAuthArea).area.map(item => item.value).join("、") },
|
||||||
{ label: "访问口门名称", children: info.mkmjName },
|
{ label: "访问口门名称", children: info.mkmjName },
|
||||||
{ label: "来访事由", children: info.reasonVisit, span: 2 },
|
{ label: "来访事由", children: info.remarks, span: 2 },
|
||||||
{ label: "行驶证照片", children: (<PreviewImg files={info.drivingLicenseFile} />), span: 2 },
|
{ label: "行驶证照片", children: (<PreviewImg files={info.drivingLicenseFile} />), span: 2 },
|
||||||
{ label: "车辆图片", children: (<PreviewImg files={info.attachmentFile} />), span: 2 },
|
{ label: "车辆图片", children: (<PreviewImg files={info.attachmentFile} />), span: 2 },
|
||||||
{ label: "申请人安全告知签字", children: (<PreviewImg files={info.informSignFile} />), span: 2 },
|
...( info.informSignFile && info.informSignFile.length ===0 ? [] : [{ label: "申请人安全告知签字", children: (<PreviewImg files={info.informSignFile} />), span: 2 }]),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<Divider orientation="left">审批信息</Divider>
|
<Divider orientation="left">审批信息</Divider>
|
||||||
|
|
@ -73,7 +77,8 @@ function View(props) {
|
||||||
{ label: "审批部门", children: item.auditDeptName },
|
{ label: "审批部门", children: item.auditDeptName },
|
||||||
{ label: "审批人", children: item.auditUserName },
|
{ label: "审批人", children: item.auditUserName },
|
||||||
{ label: "审批状态", children: getLabelName({ list: VEHICLE_AUDIT_STATUS_ENUM, status: `${item.auditStatus}` }) },
|
{ label: "审批状态", children: getLabelName({ list: VEHICLE_AUDIT_STATUS_ENUM, status: `${item.auditStatus}` }) },
|
||||||
...(item.auditStatus === 0 ? [] : [{ label: "审批时间", children: item.auditTime }, { label: "驳回原因", children: item.remarks }]),
|
...(item.auditStatus === 1 ? [] : [{ label: "审批时间", children: item.auditTime }]),
|
||||||
|
...(item.auditStatus === 3 ? [ { label: "驳回原因", children: item.remarks }] :[]),
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,272 @@
|
||||||
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验中国大陆18位身份证号
|
||||||
|
* 包含地址码、年份(18/19/20开头)、月份、日期、顺序码和校验位
|
||||||
|
* @param {string} idCard
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
export function isValidChineseIdCard(idCard) {
|
||||||
|
if (!idCard || typeof idCard !== "string") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = idCard.trim();
|
||||||
|
if (!isValidChineseIdCardFormat(value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
|
||||||
|
const checkCodeMap = ["1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"];
|
||||||
|
const sum = value
|
||||||
|
.substring(0, 17)
|
||||||
|
.split("")
|
||||||
|
.reduce((total, num, index) => total + Number(num) * weights[index], 0);
|
||||||
|
|
||||||
|
return checkCodeMap[sum % 11] === value[17].toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isValidChineseIdCardFormat(idCard) {
|
||||||
|
if (!idCard || typeof idCard !== "string") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = idCard.trim();
|
||||||
|
const pattern = /^[1-9][0-9]{5}(18|19|20)[0-9]{2}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])[0-9]{3}[0-9Xx]$/;
|
||||||
|
|
||||||
|
if (!pattern.test(value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const year = Number.parseInt(value.substring(6, 10), 10);
|
||||||
|
const month = Number.parseInt(value.substring(10, 12), 10);
|
||||||
|
const day = Number.parseInt(value.substring(12, 14), 10);
|
||||||
|
const date = new Date(year, month - 1, day);
|
||||||
|
|
||||||
|
return (
|
||||||
|
date.getFullYear() === year
|
||||||
|
&& date.getMonth() === month - 1
|
||||||
|
&& date.getDate() === day
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getChineseIdCardInputErrorMessage(idCard) {
|
||||||
|
if (!idCard || typeof idCard !== "string") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = idCard.trim();
|
||||||
|
|
||||||
|
if (!/^[0-9Xx]*$/.test(value)) {
|
||||||
|
return "身份证号只能输入数字或X";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.length > 18) {
|
||||||
|
return "身份证号长度不能超过18位";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.length < 18) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isValidChineseIdCardFormat(value)) {
|
||||||
|
return "请输入正确的18位身份证号";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getChineseIdCardFullErrorMessage(idCard) {
|
||||||
|
const inputErrorMessage = getChineseIdCardInputErrorMessage(idCard);
|
||||||
|
if (inputErrorMessage) {
|
||||||
|
return inputErrorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!idCard || typeof idCard !== "string") {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = idCard.trim();
|
||||||
|
if (value.length < 18) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isValidChineseIdCard(value)) {
|
||||||
|
return "身份证校验位不正确";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据身份证号计算年龄
|
||||||
|
* @param {string} idCard - 18位身份证号码
|
||||||
|
* @returns {number | null} 年龄(整数),无效身份证返回 null
|
||||||
|
*/
|
||||||
|
export function getAgeByIdCard(idCard) {
|
||||||
|
// 非空 & 类型校验
|
||||||
|
if (!idCard || typeof idCard !== "string") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 只处理18位身份证
|
||||||
|
const id = idCard.trim();
|
||||||
|
if (id.length !== 18) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取出生年月日:第7~14位(索引6~13)
|
||||||
|
const birthStr = id.substring(6, 14); // 如 "19900101"
|
||||||
|
const year = Number.parseInt(birthStr.substring(0, 4), 10);
|
||||||
|
const month = Number.parseInt(birthStr.substring(4, 6), 10);
|
||||||
|
const day = Number.parseInt(birthStr.substring(6, 8), 10);
|
||||||
|
|
||||||
|
// 简单校验日期合法性(可选增强)
|
||||||
|
if (
|
||||||
|
year < 1900
|
||||||
|
|| year > new Date().getFullYear()
|
||||||
|
|| month < 1
|
||||||
|
|| month > 12
|
||||||
|
|| day < 1
|
||||||
|
|| day > 31
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造出生日期
|
||||||
|
const birthDate = new Date(year, month - 1, day); // 月份从0开始
|
||||||
|
const today = new Date();
|
||||||
|
|
||||||
|
// 计算年龄
|
||||||
|
let age = today.getFullYear() - birthDate.getFullYear();
|
||||||
|
const monthDiff = today.getMonth() - birthDate.getMonth();
|
||||||
|
const dayDiff = today.getDate() - birthDate.getDate();
|
||||||
|
|
||||||
|
// 如果还没过生日,减1岁
|
||||||
|
if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) {
|
||||||
|
age -= 1;
|
||||||
|
}
|
||||||
|
return age >= 0 ? age : null; // 年龄不能为负
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 从18位身份证号中提取出生年月日
|
||||||
|
* @param {string} idCard - 身份证号码
|
||||||
|
* @returns {{ year: number; month: number; day: number } | null} 出生年月日对象,无效则返回 null
|
||||||
|
*/
|
||||||
|
export function getBirthDateFromIdCard(idCard) {
|
||||||
|
if (!idCard || typeof idCard !== "string") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const id = idCard.trim();
|
||||||
|
if (id.length !== 18) {
|
||||||
|
return null; // 仅支持18位身份证
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提取第7~14位:YYYYMMDD
|
||||||
|
const birthStr = id.substring(6, 14); // 如 "19900307"
|
||||||
|
|
||||||
|
const year = Number.parseInt(birthStr.substring(0, 4), 10);
|
||||||
|
const month = Number.parseInt(birthStr.substring(4, 6), 10);
|
||||||
|
const day = Number.parseInt(birthStr.substring(6, 8), 10);
|
||||||
|
|
||||||
|
// 简单合法性校验
|
||||||
|
const currentYear = new Date().getFullYear();
|
||||||
|
if (
|
||||||
|
year < 1900
|
||||||
|
|| year > currentYear + 1 // 允许未来1年(录入误差)
|
||||||
|
|| month < 1
|
||||||
|
|| month > 12
|
||||||
|
|| day < 1
|
||||||
|
|| day > 31
|
||||||
|
) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return `${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`;
|
||||||
|
}
|
||||||
|
export function useDebounce(value, delay = 500) {
|
||||||
|
const [debouncedValue, setDebouncedValue] = useState(value);
|
||||||
|
const timerRef = useRef(null);
|
||||||
|
useEffect(() => {
|
||||||
|
// 清除上一次的定时器
|
||||||
|
if (timerRef.current) {
|
||||||
|
clearTimeout(timerRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置新的定时器
|
||||||
|
timerRef.current = setTimeout(() => {
|
||||||
|
setDebouncedValue(value);
|
||||||
|
}, delay);
|
||||||
|
|
||||||
|
// 组件卸载或 delay/value 变化时清理
|
||||||
|
return () => {
|
||||||
|
if (timerRef.current) {
|
||||||
|
clearTimeout(timerRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [value, delay]);
|
||||||
|
return debouncedValue;
|
||||||
|
}
|
||||||
|
// 手机号脱敏
|
||||||
|
export function maskPhone(phone) {
|
||||||
|
if (!phone)
|
||||||
|
return "";
|
||||||
|
const str = String(phone).replace(/\s+/g, ""); // 去除空格
|
||||||
|
if (!/^1[3-9]\d{9}$/.test(str)) {
|
||||||
|
return phone; // 非标准手机号,原样返回
|
||||||
|
}
|
||||||
|
return `${str.substring(0, 3)}****${str.substring(7)}`;
|
||||||
|
}
|
||||||
|
// 身份证号脱敏
|
||||||
|
export function maskIdCard(idCard) {
|
||||||
|
if (!idCard)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
// 转为字符串并去除空格
|
||||||
|
const str = String(idCard).replace(/\s+/g, "");
|
||||||
|
|
||||||
|
// 判断是否为 18 位身份证(支持末尾 X/x)
|
||||||
|
if (!/^\d{17}[\dX]$/i.test(str)) {
|
||||||
|
return idCard; // 非标准身份证,原样返回
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${str.substring(0, 6)}********${str.substring(14)}`;
|
||||||
|
}
|
||||||
|
// 属地
|
||||||
|
export const getAreaNamePath = (item) => {
|
||||||
|
const names = [
|
||||||
|
item.provinceName,
|
||||||
|
item.cityName,
|
||||||
|
item.countryName,
|
||||||
|
item.streetName,
|
||||||
|
item.villageName,
|
||||||
|
|
||||||
|
].filter(name => name != null && name !== "");
|
||||||
|
return names.join("/");
|
||||||
|
};
|
||||||
|
// 行业类型
|
||||||
|
export const getCorpTypeNamePath = (item) => {
|
||||||
|
const names = [
|
||||||
|
item.corpTypeName,
|
||||||
|
item.corpType2Name,
|
||||||
|
item.corpType3Name,
|
||||||
|
item.corpType4Name,
|
||||||
|
].filter(name => name != null && name !== "");
|
||||||
|
return names.join("/");
|
||||||
|
};
|
||||||
|
// 身份证解码
|
||||||
|
export const UseDecodeIdCard = (userIdCard) => {
|
||||||
|
if (!userIdCard)
|
||||||
|
return userIdCard;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const decoded = atob(userIdCard);
|
||||||
|
if (/^\d{17}[\dX]$/.test(decoded)) {
|
||||||
|
return decoded;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
console.warn("Not a valid Base64 string, keep as is:", userIdCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
return userIdCard; // fallback
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue