517 lines
16 KiB
Vue
517 lines
16 KiB
Vue
<template>
|
|
<!-- 人员身份证信息表单 -->
|
|
<view style="height: 100%">
|
|
<up-form
|
|
labelWidth="120"
|
|
labelPosition="left"
|
|
:model="idCardModel"
|
|
:rules="idCardRules"
|
|
ref="idCardFormRef"
|
|
class="id-card-form"
|
|
>
|
|
<up-cell style="padding: 0 13px">
|
|
<template #icon>
|
|
<text class="blue-text"> 身份证人面像信息 </text>
|
|
</template>
|
|
|
|
<template #right-icon>
|
|
<up-button
|
|
icon="photo"
|
|
:plain="true"
|
|
size="small"
|
|
type="primary"
|
|
text="识别身份证(人像)"
|
|
@tap="onHandleRecognizeIdCard(1)"
|
|
/>
|
|
</template>
|
|
</up-cell>
|
|
<up-form-item label="姓名" prop="name" :borderBottom="true">
|
|
<up-input
|
|
clearable
|
|
border="none"
|
|
placeholder="请输入姓名"
|
|
v-model="idCardModel.name"
|
|
/>
|
|
</up-form-item>
|
|
<up-form-item label="身份证号" prop="idNumber" :borderBottom="true">
|
|
<up-input
|
|
clearable
|
|
border="none"
|
|
@blur="onBlurIdNumber"
|
|
placeholder="请输入18位身份证号"
|
|
v-model="idCardModel.idNumber"
|
|
/>
|
|
</up-form-item>
|
|
<up-form-item label="性别" prop="sex" :borderBottom="true">
|
|
<up-radio-group v-model="idCardModel.sex" placement="row" disabled>
|
|
<up-radio label="男" name="男" shape="circle" />
|
|
<up-radio label="女" name="女" shape="circle" />
|
|
</up-radio-group>
|
|
</up-form-item>
|
|
<up-form-item label="出生日期" prop="birthday" :borderBottom="true">
|
|
<up-cell
|
|
isLink
|
|
disabled
|
|
:border="false"
|
|
style="width: 100%"
|
|
@tap="onOpenPikerDate(1)"
|
|
>
|
|
<template #icon>
|
|
<text :class="{ 'color-text': idCardModel.birthday }" class="time-text">
|
|
{{ idCardModel.birthday || '出生日期' }}
|
|
</text>
|
|
</template>
|
|
</up-cell>
|
|
</up-form-item>
|
|
<up-form-item label="民族" prop="nation" :borderBottom="true">
|
|
<up-input
|
|
clearable
|
|
border="none"
|
|
placeholder="请输入民族"
|
|
v-model="idCardModel.nation"
|
|
/>
|
|
</up-form-item>
|
|
<up-form-item label="住址" prop="address" :borderBottom="true">
|
|
<up-textarea
|
|
count
|
|
autoHeight
|
|
maxlength="50"
|
|
placeholder="请输入住址"
|
|
v-model="idCardModel.address"
|
|
/>
|
|
</up-form-item>
|
|
|
|
<up-cell style="padding: 0 13px">
|
|
<template #icon>
|
|
<text class="blue-text"> 身份证国徽面信息 </text>
|
|
</template>
|
|
|
|
<template #right-icon>
|
|
<up-button
|
|
icon="photo"
|
|
:plain="true"
|
|
size="small"
|
|
type="primary"
|
|
text="识别身份证(国徽)"
|
|
@tap="onHandleRecognizeIdCard(2)"
|
|
/>
|
|
</template>
|
|
</up-cell>
|
|
|
|
<up-form-item label="生效日期" prop="startTime" :borderBottom="true">
|
|
<up-cell
|
|
isLink
|
|
size="large"
|
|
style="width: 100%"
|
|
@tap="onOpenPikerDate(2)"
|
|
:border="false"
|
|
>
|
|
<template #icon>
|
|
<text :class="{ 'color-text': idCardModel.startTime }" class="time-text">
|
|
{{ idCardModel.startTime || '请选择生效日期' }}
|
|
</text>
|
|
</template>
|
|
</up-cell>
|
|
</up-form-item>
|
|
|
|
<up-form-item label="失效日期" prop="birthday" :borderBottom="true">
|
|
<up-cell
|
|
isLink
|
|
size="large"
|
|
style="width: 100%"
|
|
@tap="onOpenPikerDate(3)"
|
|
:border="false"
|
|
>
|
|
<template #icon>
|
|
<text :class="{ 'color-text': idCardModel.endTime }" class="time-text">
|
|
{{ idCardModel.endTime || '请选择失效日期' }}
|
|
</text>
|
|
</template>
|
|
</up-cell>
|
|
</up-form-item>
|
|
|
|
<up-form-item label="签发机关" prop="issuingAuthority" :borderBottom="true">
|
|
<up-input
|
|
clearable
|
|
border="none"
|
|
placeholder="请输入签发机关"
|
|
v-model="idCardModel.issuingAuthority"
|
|
/>
|
|
</up-form-item>
|
|
</up-form>
|
|
|
|
<up-datetime-picker
|
|
mode="date"
|
|
ref="pikerBirthdayRef"
|
|
:minDate="0"
|
|
:show="showPikerBirthday"
|
|
@cancel="onCancelBirthday"
|
|
@confirm="onConfirmBirthday"
|
|
v-model="pikerBirthdayValue"
|
|
/>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup name="personIdCardForm">
|
|
import { ref, watch } from 'vue'
|
|
import { pathToBase64 } from 'image-tools'
|
|
import { useMemberStore } from '@/stores'
|
|
import dayjs from 'dayjs'
|
|
|
|
const memberStore = useMemberStore()
|
|
const idCardFormRef = ref(null) // 身份证表单ref
|
|
const idCardModel = ref({
|
|
age: '',
|
|
sex: '', // 性别
|
|
name: '', // 姓名
|
|
nation: '', // 民族
|
|
startTime: '', // 生效日期
|
|
endTime: '', // 失效日期
|
|
address: '', // 身份证住址
|
|
idNumber: '', // 身份证号
|
|
birthday: '', // 出生日期
|
|
issuingAuthority: '', // 签发机关
|
|
}) // 身份证表单数据
|
|
const idCardRules = ref({
|
|
name: [
|
|
{
|
|
type: 'string',
|
|
required: true,
|
|
message: '请输入姓名',
|
|
},
|
|
{
|
|
max: 20,
|
|
message: '姓名长度不能超过20个字符',
|
|
},
|
|
],
|
|
idNumber: [
|
|
{
|
|
type: 'string',
|
|
required: true,
|
|
message: '请输入身份证号',
|
|
},
|
|
{
|
|
pattern: /^[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[0-1])\d{3}[0-9Xx]$/,
|
|
message: '请输入正确的身份证号',
|
|
},
|
|
],
|
|
sex: [
|
|
{
|
|
type: 'string',
|
|
required: true,
|
|
message: '请选择性别',
|
|
},
|
|
],
|
|
birthday: [
|
|
{
|
|
type: 'string',
|
|
required: true,
|
|
message: '请选择出生日期',
|
|
},
|
|
],
|
|
nation: [
|
|
{
|
|
type: 'string',
|
|
required: true,
|
|
message: '请输入民族',
|
|
},
|
|
{
|
|
max: 20,
|
|
message: '民族长度不能超过20个字符',
|
|
},
|
|
],
|
|
address: [
|
|
{
|
|
type: 'string',
|
|
required: true,
|
|
message: '请输入住址',
|
|
},
|
|
|
|
{
|
|
max: 50,
|
|
message: '住址长度不能超过50个字符',
|
|
},
|
|
],
|
|
startTime: [
|
|
{
|
|
type: 'string',
|
|
required: true,
|
|
message: '请选择生效日期',
|
|
},
|
|
],
|
|
endTime: [
|
|
{
|
|
type: 'string',
|
|
required: true,
|
|
message: '请选择失效日期',
|
|
},
|
|
],
|
|
issuingAuthority: [
|
|
{
|
|
type: 'string',
|
|
required: true,
|
|
message: '请输入签发机关',
|
|
},
|
|
{
|
|
max: 20,
|
|
message: '签发机关长度不能超过20个字符',
|
|
},
|
|
],
|
|
}) // 身份证表单规则
|
|
|
|
const showPikerBirthday = ref(false) // 出生日期选择器
|
|
const pikerBirthdayRef = ref(null) // 出生日期选择器ref
|
|
const pikerBirthdayValue = ref(Date.now()) // 出生日期选择器值
|
|
const pikerDateType = ref(1) // 日期选择器类型 1出生日期 2生效日期 3失效日期
|
|
|
|
const emit = defineEmits(['onInitIdCardForm'])
|
|
|
|
// 身份证号输入
|
|
const onBlurIdNumber = (val) => {
|
|
if (!val) {
|
|
idCardModel.value.birthday = ''
|
|
idCardModel.value.sex = ''
|
|
return
|
|
}
|
|
const birthday = idCardModel.value.idNumber.slice(6, 14)
|
|
const sex = idCardModel.value.idNumber.slice(16, 17)
|
|
idCardModel.value.birthday =
|
|
birthday?.slice(0, 4) + '-' + birthday.slice(4, 6) + '-' + birthday.slice(6, 8)
|
|
idCardModel.value.sex = sex % 2 === 0 ? '女' : '男'
|
|
}
|
|
|
|
// 日期格式化
|
|
const formatDateFun = (timestamp) => {
|
|
// 将时间戳转换为Date对象
|
|
const date = new Date(timestamp)
|
|
// 格式化日期为"YYYY年MM月DD日"格式
|
|
const year = date.getFullYear()
|
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
|
const day = String(date.getDate()).padStart(2, '0')
|
|
const formattedValue = `${year}-${month}-${day}`
|
|
return formattedValue
|
|
}
|
|
|
|
// 打开日期选择器
|
|
const onOpenPikerDate = (type) => {
|
|
pikerDateType.value = type
|
|
showPikerBirthday.value = true
|
|
}
|
|
|
|
// 日期确认
|
|
const onConfirmBirthday = (value) => {
|
|
if (value.value) {
|
|
const formattedValue = formatDateFun(value.value)
|
|
if (pikerDateType.value === 2) {
|
|
if (idCardModel.value.endTime && formattedValue > idCardModel.value.endTime) {
|
|
uni.$u.toast('生效日期不能大于失效日期')
|
|
return
|
|
}
|
|
idCardModel.value.startTime = formattedValue
|
|
} else if (pikerDateType.value === 3) {
|
|
if (idCardModel.value.startTime && formattedValue < idCardModel.value.startTime) {
|
|
uni.$u.toast('失效日期不能小于生效日期')
|
|
return
|
|
}
|
|
idCardModel.value.endTime = formattedValue
|
|
} else {
|
|
idCardModel.value.birthday = formattedValue
|
|
}
|
|
showPikerBirthday.value = false
|
|
}
|
|
}
|
|
|
|
// 日期取消
|
|
const onCancelBirthday = () => {
|
|
pikerBirthdayValue.value = Date.now()
|
|
idCardModel.value.birthday = ''
|
|
showPikerBirthday.value = false
|
|
}
|
|
|
|
const imgToBase64Fun = async (path) => {
|
|
return new Promise((resolve, reject) => {
|
|
pathToBase64(path)
|
|
.then((base64) => {
|
|
resolve(base64)
|
|
})
|
|
.catch((error) => {
|
|
console.error(error)
|
|
reject(error)
|
|
})
|
|
})
|
|
}
|
|
|
|
// 识别身份证(人像面和国徽面)
|
|
const onHandleRecognizeIdCard = (type) => {
|
|
// 1人像面 2国徽面
|
|
// console.log('识别身份证(人像面)')
|
|
|
|
// uni.$u.toast('功能正在开发中,敬请期待...')
|
|
|
|
// return
|
|
|
|
uni.chooseImage({
|
|
count: 1, // 最多选择1张图片
|
|
sizeType: ['original', 'compressed'],
|
|
sourceType: ['camera'], // 选择图片的来源
|
|
success: async (res) => {
|
|
const base64 = await imgToBase64Fun(res.tempFilePaths[0])
|
|
let params = {
|
|
recognitionFrontData: '',
|
|
recognitionBackData: '',
|
|
type: 1,
|
|
}
|
|
if (type === 1) {
|
|
params.recognitionFrontData = base64.split(',')[1]
|
|
} else {
|
|
params.recognitionBackData = base64.split(',')[1]
|
|
}
|
|
|
|
// 上传后台接口
|
|
uni.request({
|
|
url: 'http://192.168.0.14:18975/recognition',
|
|
method: 'POST',
|
|
data: params,
|
|
isUploadFile: true,
|
|
header: {
|
|
// 'Content-Type': 'application/Json',
|
|
Authorization: memberStore?.token, // token
|
|
},
|
|
success: (res) => {
|
|
const data = JSON.parse(res.data)
|
|
console.log(data, '识别身份证结果')
|
|
|
|
if (data.code === 20001) {
|
|
uni.$u.toast('识别身份证成功')
|
|
|
|
if (type === 1) {
|
|
const { name, gender, ethnicity, dateOfBirth, address, idNumber } =
|
|
data.data
|
|
|
|
const match = dateOfBirth.match(/(\d+)年(\d+)月(\d+)日/)
|
|
let birthday = ''
|
|
|
|
if (match) {
|
|
const year = match[1]
|
|
// 月和日补零处理
|
|
const month = String(match[2]).padStart(2, '0')
|
|
const day = String(match[3]).padStart(2, '0')
|
|
birthday = `${year}-${month}-${day}`
|
|
}
|
|
|
|
idCardModel.value.name = name
|
|
idCardModel.value.sex = gender
|
|
idCardModel.value.nation = ethnicity
|
|
idCardModel.value.birthday = birthday
|
|
idCardModel.value.address = address
|
|
idCardModel.value.idNumber = idNumber
|
|
} else {
|
|
const { issuingAuthority, validTime } = data.data
|
|
const validTimeArr = validTime.split('-')
|
|
idCardModel.value.issuingAuthority = issuingAuthority
|
|
idCardModel.value.startTime = validTimeArr[0].replace(/\./g, '-')
|
|
idCardModel.value.endTime = validTimeArr[1].replace(/\./g, '-')
|
|
}
|
|
} else {
|
|
uni.$u.toast('识别失败,请重新识别')
|
|
}
|
|
// const { data: result } = res
|
|
// if (result.code === 200) {
|
|
// uni.$u.toast('识别身份证成功')
|
|
// } else {
|
|
// uni.$u.toast('识别身份证失败,请重新识别')
|
|
// }
|
|
},
|
|
fail: (err) => {
|
|
// console.log(err, '----识别身份证失败')
|
|
uni.$u.toast('识别失败,请重新识别')
|
|
},
|
|
})
|
|
},
|
|
fail: (err) => {
|
|
// uni.$u.toast({
|
|
// title: '选择图片失败',
|
|
// icon: 'none',
|
|
// })
|
|
},
|
|
})
|
|
}
|
|
|
|
// 表单校验
|
|
const validateIdCardForm = async () => {
|
|
return new Promise((resolve, reject) => {
|
|
idCardFormRef.value
|
|
.validate()
|
|
.then((valid) => {
|
|
if (valid) {
|
|
// 计算年龄
|
|
const age = new Date().getFullYear() - idCardModel.value.birthday.slice(0, 4)
|
|
idCardModel.value.age = age + 1
|
|
resolve({
|
|
isValid: true,
|
|
data: idCardModel.value,
|
|
})
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
reject(false)
|
|
})
|
|
})
|
|
}
|
|
|
|
const updateIdCardInfo = () => {
|
|
Object.assign(idCardModel.value, props.idCardInfo)
|
|
}
|
|
|
|
// 向父组件暴露方法
|
|
defineExpose({
|
|
validateIdCardForm,
|
|
updateIdCardInfo,
|
|
})
|
|
|
|
const props = defineProps({
|
|
idCardInfo: {
|
|
type: Object,
|
|
default: () => {},
|
|
},
|
|
})
|
|
|
|
// 增加监听
|
|
watch(
|
|
props.idCardInfo,
|
|
(newVal) => {
|
|
if (Object.keys(newVal).length > 0) {
|
|
Object.assign(idCardModel.value, newVal)
|
|
}
|
|
},
|
|
{
|
|
immediate: true,
|
|
},
|
|
)
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
@import '@/uni.scss';
|
|
|
|
.blue-text {
|
|
font-size: 14px;
|
|
color: $uni-color-primary;
|
|
}
|
|
|
|
.u-form-item {
|
|
padding: 0 15px;
|
|
}
|
|
|
|
::v-deep .u-cell__body {
|
|
padding: 13px 0;
|
|
}
|
|
|
|
.color-text {
|
|
color: rgb(48, 49, 51) !important;
|
|
}
|
|
|
|
.time-text {
|
|
color: rgb(192, 196, 204);
|
|
}
|
|
</style>
|