feat(证件类型): 添加证件类型选择功能并优化证件号码验证
- 在搜索和添加参观者页面增加证件类型选择器 - 根据证件类型动态调整证件号码输入长度限制 - 优化证件号码验证逻辑,支持不同类型证件 - 重构二维码查询组件,支持按证件类型查询
Showing
3 changed files
with
104 additions
and
60 deletions
| ... | @@ -35,34 +35,22 @@ | ... | @@ -35,34 +35,22 @@ |
| 35 | </template> | 35 | </template> |
| 36 | 36 | ||
| 37 | <script setup> | 37 | <script setup> |
| 38 | -import { ref } from 'vue' | ||
| 39 | -import { useRoute, useRouter } from 'vue-router' | ||
| 40 | -import { Cookies, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js' | ||
| 41 | -//import { } from '@/utils/generateModules.js' | ||
| 42 | -//import { } from '@/utils/generateIcons.js' | ||
| 43 | -//import { } from '@/composables' | ||
| 44 | import { formatDatetime } from '@/utils/tools'; | 38 | import { formatDatetime } from '@/utils/tools'; |
| 45 | -import { qrcodeListAPI, qrcodeStatusAPI, billPersonAPI, queryQrCodeAPI } from '@/api/index' | 39 | +import { qrcodeStatusAPI, queryQrCodeAPI } from '@/api/index' |
| 46 | -const $route = useRoute(); | ||
| 47 | -const $router = useRouter(); | ||
| 48 | -useTitle($route.meta.title); | ||
| 49 | 40 | ||
| 50 | const props = defineProps({ | 41 | const props = defineProps({ |
| 51 | id: { | 42 | id: { |
| 52 | type: String, | 43 | type: String, |
| 53 | default: '' | 44 | default: '' |
| 54 | }, | 45 | }, |
| 46 | + id_type: { | ||
| 47 | + type: Number, | ||
| 48 | + default: 1, | ||
| 49 | + } | ||
| 55 | }); | 50 | }); |
| 56 | 51 | ||
| 57 | const userinfo = ref({}); | 52 | const userinfo = ref({}); |
| 58 | 53 | ||
| 59 | -watch( | ||
| 60 | - () => props.id, | ||
| 61 | - async (id) => { | ||
| 62 | - console.warn(id); | ||
| 63 | - } | ||
| 64 | -) | ||
| 65 | - | ||
| 66 | /** | 54 | /** |
| 67 | * 生成15位身份证号中间8位替换为*号 | 55 | * 生成15位身份证号中间8位替换为*号 |
| 68 | * @param {*} inputString | 56 | * @param {*} inputString |
| ... | @@ -101,44 +89,54 @@ const STATUS_CODE = { | ... | @@ -101,44 +89,54 @@ const STATUS_CODE = { |
| 101 | USED: '7', | 89 | USED: '7', |
| 102 | }; | 90 | }; |
| 103 | 91 | ||
| 104 | -const formatStatus = (status) => { | 92 | +const resetState = () => { |
| 105 | - switch (status) { | 93 | + userinfo.value = {} |
| 106 | - case 'success': | 94 | + useStatus.value = '0' |
| 107 | - return { | 95 | +} |
| 108 | - key: 'success', | 96 | + |
| 109 | - value: '预约成功' | 97 | +const loadQrCodeInfo = async () => { |
| 110 | - } | 98 | + const id_number = String(props.id || '').trim() |
| 111 | - case 'cancel': | 99 | + if (!id_number) { |
| 112 | - return { | 100 | + resetState() |
| 113 | - key: 'cancel', | 101 | + return |
| 114 | - value: '已取消' | ||
| 115 | } | 102 | } |
| 116 | - case 'used': | 103 | + |
| 117 | - return { | 104 | + const params = { id_number } |
| 118 | - key: 'used', | 105 | + if (props.id_type) params.id_type = props.id_type |
| 119 | - value: '已使用' | 106 | + |
| 107 | + const { code, data } = await queryQrCodeAPI(params); | ||
| 108 | + if (!code || !data) { | ||
| 109 | + resetState() | ||
| 110 | + return | ||
| 120 | } | 111 | } |
| 112 | + | ||
| 113 | + const raw = Array.isArray(data) ? data?.[0] : data | ||
| 114 | + if (!raw?.qr_code) { | ||
| 115 | + resetState() | ||
| 116 | + return | ||
| 121 | } | 117 | } |
| 122 | -} | ||
| 123 | 118 | ||
| 124 | -onMounted(async () => { | ||
| 125 | - if (props.id) { | ||
| 126 | - const { code, data } = await queryQrCodeAPI({ id_number: props.id }); | ||
| 127 | - if (code) { | ||
| 128 | userinfo.value = { | 119 | userinfo.value = { |
| 129 | - id: formatId(props.id), | 120 | + id: formatId(id_number), |
| 130 | - name: data?.name, | 121 | + name: raw?.name, |
| 131 | - datetime: formatDatetime({ begin_time: data?.begin_time, end_time: data?.end_time }), | 122 | + datetime: formatDatetime({ begin_time: raw?.begin_time, end_time: raw?.end_time }), |
| 132 | - qr_code: data?.qr_code, | 123 | + qr_code: raw?.qr_code, |
| 133 | - qr_code_url: '/admin?m=srv&a=get_qrcode&key=' + data?.qr_code, | 124 | + qr_code_url: '/admin?m=srv&a=get_qrcode&key=' + encodeURIComponent(String(raw?.qr_code)), |
| 134 | } | 125 | } |
| 135 | - const { code: status_code, data: status_data } = await qrcodeStatusAPI({ qr_code: data?.qr_code }); | 126 | + |
| 127 | + const { code: status_code, data: status_data } = await qrcodeStatusAPI({ qr_code: raw?.qr_code }); | ||
| 136 | if (status_code) { | 128 | if (status_code) { |
| 137 | - useStatus.value = status_data.status; | 129 | + useStatus.value = String(status_data.status); |
| 138 | } | 130 | } |
| 139 | - } | 131 | +} |
| 140 | - } | 132 | + |
| 141 | -}); | 133 | +watch( |
| 134 | + () => [props.id, props.id_type], | ||
| 135 | + () => { | ||
| 136 | + loadQrCodeInfo() | ||
| 137 | + }, | ||
| 138 | + { immediate: true } | ||
| 139 | +) | ||
| 142 | 140 | ||
| 143 | // 定义轮询函数 | 141 | // 定义轮询函数 |
| 144 | const poll = async () => { | 142 | const poll = async () => { | ... | ... |
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2024-01-15 17:39:29 | 2 | * @Date: 2024-01-15 17:39:29 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2024-01-30 15:21:50 | 4 | + * @LastEditTime: 2026-01-22 11:39:55 |
| 5 | - * @FilePath: /xysBooking/src/views/addVisitor.vue | 5 | + * @FilePath: /git/xysBooking/src/views/addVisitor.vue |
| 6 | * @Description: 添加参观者页面 | 6 | * @Description: 添加参观者页面 |
| 7 | --> | 7 | --> |
| 8 | <template> | 8 | <template> |
| ... | @@ -15,17 +15,14 @@ | ... | @@ -15,17 +15,14 @@ |
| 15 | </div> | 15 | </div> |
| 16 | <div class="input-item"> | 16 | <div class="input-item"> |
| 17 | <div>证件类型</div> | 17 | <div>证件类型</div> |
| 18 | - <!-- <div @click="idTypeChange"> | 18 | + <div @click="idTypeChange"> |
| 19 | {{ fieldValue }} <van-icon name="arrow-down" /> | 19 | {{ fieldValue }} <van-icon name="arrow-down" /> |
| 20 | - </div> --> | ||
| 21 | - <div> | ||
| 22 | - {{ fieldValue }} | ||
| 23 | </div> | 20 | </div> |
| 24 | </div> | 21 | </div> |
| 25 | <div class="input-item"> | 22 | <div class="input-item"> |
| 26 | <div>证件号码</div> | 23 | <div>证件号码</div> |
| 27 | <div> | 24 | <div> |
| 28 | - <input type="text" v-model="idCode" placeholder="请输入证件号码" @blur="checkIdCode" maxlength="18" style="width: 100%;"> | 25 | + <input type="text" v-model="idCode" placeholder="请输入证件号码" @blur="checkIdCode" :maxlength="id_type === 1 ? 18 : 30" style="width: 100%;"> |
| 29 | </div> | 26 | </div> |
| 30 | </div> | 27 | </div> |
| 31 | <div style="color:#A67939; font-size: 0.85rem;"> | 28 | <div style="color:#A67939; font-size: 0.85rem;"> |
| ... | @@ -87,6 +84,13 @@ const checkUsername = () => { // 检查用户名是否为空 | ... | @@ -87,6 +84,13 @@ const checkUsername = () => { // 检查用户名是否为空 |
| 87 | 84 | ||
| 88 | const checkIdCode = () => { // 检查身份证号是否为空 | 85 | const checkIdCode = () => { // 检查身份证号是否为空 |
| 89 | let flag = true; | 86 | let flag = true; |
| 87 | + if (!idCode.value) { | ||
| 88 | + show_error.value = true; | ||
| 89 | + error_message.value = '请输入证件号码'; | ||
| 90 | + flag = false; | ||
| 91 | + return flag; | ||
| 92 | + } | ||
| 93 | + if (id_type.value !== 1) return true; | ||
| 90 | if (idCode.value.length === 15) { // 15位身份证号码不校验 | 94 | if (idCode.value.length === 15) { // 15位身份证号码不校验 |
| 91 | flag = true; | 95 | flag = true; |
| 92 | } else { | 96 | } else { |
| ... | @@ -102,9 +106,12 @@ const checkIdCode = () => { // 检查身份证号是否为空 | ... | @@ -102,9 +106,12 @@ const checkIdCode = () => { // 检查身份证号是否为空 |
| 102 | const addVisitor = async () => { | 106 | const addVisitor = async () => { |
| 103 | // 保存用户信息 | 107 | // 保存用户信息 |
| 104 | if (checkUsername() && checkIdCode()) { | 108 | if (checkUsername() && checkIdCode()) { |
| 105 | - const { code, data } = await addPersonAPI({ name: username.value, id_type: id_type.value, id_number: idCode.value }); | 109 | + const { code, msg } = await addPersonAPI({ name: username.value, id_type: id_type.value, id_number: idCode.value }); |
| 106 | if (code) { | 110 | if (code) { |
| 107 | $router.go(-1); | 111 | $router.go(-1); |
| 112 | + } else { | ||
| 113 | + show_error.value = true; | ||
| 114 | + error_message.value = msg || '添加失败'; | ||
| 108 | } | 115 | } |
| 109 | } | 116 | } |
| 110 | } | 117 | } |
| ... | @@ -114,12 +121,12 @@ const idTypeChange = () => { | ... | @@ -114,12 +121,12 @@ const idTypeChange = () => { |
| 114 | showPicker.value = !showPicker.value; | 121 | showPicker.value = !showPicker.value; |
| 115 | } | 122 | } |
| 116 | const columns = [ | 123 | const columns = [ |
| 117 | - { text: '身份证', value: '1' }, | 124 | + { text: '身份证', value: 1 }, |
| 118 | - { text: '其他证件', value: '3' }, | 125 | + { text: '其他', value: 3 }, |
| 119 | ]; | 126 | ]; |
| 120 | 127 | ||
| 121 | const fieldValue = ref('身份证'); | 128 | const fieldValue = ref('身份证'); |
| 122 | -const id_type = ref('1'); | 129 | +const id_type = ref(1); |
| 123 | 130 | ||
| 124 | const onConfirm = ({ selectedOptions }) => { // 切换类型回调 | 131 | const onConfirm = ({ selectedOptions }) => { // 切换类型回调 |
| 125 | showPicker.value = false; | 132 | showPicker.value = false; | ... | ... |
| ... | @@ -9,10 +9,16 @@ | ... | @@ -9,10 +9,16 @@ |
| 9 | <div class="search-page"> | 9 | <div class="search-page"> |
| 10 | <div> | 10 | <div> |
| 11 | <div v-if="!is_search"> | 11 | <div v-if="!is_search"> |
| 12 | + <div class="input-item" @click="idTypeChange"> | ||
| 13 | + <div>证件类型</div> | ||
| 14 | + <div> | ||
| 15 | + {{ fieldValue }} <van-icon name="arrow-down" /> | ||
| 16 | + </div> | ||
| 17 | + </div> | ||
| 12 | <div class="input-item"> | 18 | <div class="input-item"> |
| 13 | <div>证件号码</div> | 19 | <div>证件号码</div> |
| 14 | <div> | 20 | <div> |
| 15 | - <input type="text" v-model="idCode" placeholder="请输入证件号码" @blur="checkIdCode" maxlength="18" style="width: 100%;"> | 21 | + <input type="text" v-model="idCode" placeholder="请输入证件号码" @blur="checkIdCode" :maxlength="id_type === 1 ? 18 : 30" style="width: 100%;"> |
| 16 | </div> | 22 | </div> |
| 17 | </div> | 23 | </div> |
| 18 | <div style="color:#A67939; font-size: 0.95rem; text-align: center;"> | 24 | <div style="color:#A67939; font-size: 0.95rem; text-align: center;"> |
| ... | @@ -23,7 +29,7 @@ | ... | @@ -23,7 +29,7 @@ |
| 23 | </div> | 29 | </div> |
| 24 | </div> | 30 | </div> |
| 25 | <div v-else> | 31 | <div v-else> |
| 26 | - <qrCodeSearch :id="id_number" /> | 32 | + <qrCodeSearch :id="id_number" :id_type="id_type" /> |
| 27 | </div> | 33 | </div> |
| 28 | <div v-if="!is_search" class="save-wrapper"> | 34 | <div v-if="!is_search" class="save-wrapper"> |
| 29 | <div class="save-btn" @click="searchBtn">查询</div> | 35 | <div class="save-btn" @click="searchBtn">查询</div> |
| ... | @@ -35,6 +41,14 @@ | ... | @@ -35,6 +41,14 @@ |
| 35 | </div> | 41 | </div> |
| 36 | <div class="logo"></div> | 42 | <div class="logo"></div> |
| 37 | 43 | ||
| 44 | + <van-popup v-model:show="showPicker" position="bottom"> | ||
| 45 | + <van-picker | ||
| 46 | + :columns="columns" | ||
| 47 | + @cancel="showPicker = false" | ||
| 48 | + @confirm="onConfirm" | ||
| 49 | + /> | ||
| 50 | + </van-popup> | ||
| 51 | + | ||
| 38 | <van-toast v-model:show="show_error" style=""> | 52 | <van-toast v-model:show="show_error" style=""> |
| 39 | <template #message> | 53 | <template #message> |
| 40 | {{ error_message }} | 54 | {{ error_message }} |
| ... | @@ -70,6 +84,13 @@ const error_message = ref(''); | ... | @@ -70,6 +84,13 @@ const error_message = ref(''); |
| 70 | 84 | ||
| 71 | const checkIdCode = () => { // 检查身份证号是否为空 | 85 | const checkIdCode = () => { // 检查身份证号是否为空 |
| 72 | let flag = true; | 86 | let flag = true; |
| 87 | + if (!idCode.value) { | ||
| 88 | + show_error.value = true; | ||
| 89 | + error_message.value = '请输入证件号码'; | ||
| 90 | + flag = false; | ||
| 91 | + return flag; | ||
| 92 | + } | ||
| 93 | + if (id_type.value !== 1) return true; | ||
| 73 | if (idCode.value.length === 15) { // 15位身份证号码不校验 | 94 | if (idCode.value.length === 15) { // 15位身份证号码不校验 |
| 74 | flag = true; | 95 | flag = true; |
| 75 | } else { | 96 | } else { |
| ... | @@ -96,6 +117,24 @@ const goBack = () => { | ... | @@ -96,6 +117,24 @@ const goBack = () => { |
| 96 | const goToHome = () => { | 117 | const goToHome = () => { |
| 97 | go('/') | 118 | go('/') |
| 98 | } | 119 | } |
| 120 | + | ||
| 121 | +const showPicker = ref(false); | ||
| 122 | +const idTypeChange = () => { | ||
| 123 | + showPicker.value = !showPicker.value; | ||
| 124 | +} | ||
| 125 | +const columns = [ | ||
| 126 | + { text: '身份证', value: 1 }, | ||
| 127 | + { text: '其他', value: 3 }, | ||
| 128 | +]; | ||
| 129 | + | ||
| 130 | +const fieldValue = ref('身份证'); | ||
| 131 | +const id_type = ref(1); | ||
| 132 | + | ||
| 133 | +const onConfirm = ({ selectedOptions }) => { // 切换类型回调 | ||
| 134 | + showPicker.value = false; | ||
| 135 | + fieldValue.value = selectedOptions[0].text; | ||
| 136 | + id_type.value = selectedOptions[0].value; | ||
| 137 | +}; | ||
| 99 | </script> | 138 | </script> |
| 100 | 139 | ||
| 101 | <style lang="less" scoped> | 140 | <style lang="less" scoped> | ... | ... |
-
Please register or login to post a comment