From 53c6f3fcfd40e046e355c632c3a9bd8b941e208f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=90=A6?= Date: Sat, 8 Aug 2026 18:36:38 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=82=A3=E8=80=85=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E8=BA=AB=E4=BB=BD=E8=AF=81=E6=94=B9=E6=88=90=E9=9D=9E=E5=BF=85?= =?UTF-8?q?=E5=A1=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- request/api/request.js | 19 +- subPackages/my/myinfo-add.vue | 164 +++++++++++----- subPackages/my/myinfo-edit.vue | 184 +++++++++++++----- subPackages/my/myinfo.vue | 2 +- .../components/RegisterPatientStep.vue | 30 +++ 5 files changed, 297 insertions(+), 102 deletions(-) diff --git a/request/api/request.js b/request/api/request.js index c1e546c..a58e6e8 100644 --- a/request/api/request.js +++ b/request/api/request.js @@ -337,6 +337,14 @@ function getRes(obj, isDecode = true) { } else if (obj[key] !== null && typeof obj[key] === 'object') { obj[key] = getRes(obj[key], isDecode) } else if (arr.indexOf(key) !== -1) { + // 未填写的敏感字段保持空串,禁止加解密(避免空值被解成密文乱码) + if (obj[key] == null || obj[key] === '') { + obj[key] = '' + if (isDecode === true && (sensitiveData.indexOf(key) !== -1 || displayMaskFields.indexOf(key) !== -1)) { + obj[key + '_tm'] = '' + } + continue + } let plainValue = '' if (isDecode === true) { plainValue = customBase64Decode(obj[key]) @@ -369,17 +377,22 @@ function getRes(obj, isDecode = true) { } function customBase64Decode(data) { + // 空值直接返回空串,避免 Base64.decode(null/'' ) 失败后回退成密文原串 + if (data == null || data === '') { + return '' + } // return data try { // 第一次Base64解码 const decodedFirst = Base64.decode(data) // 截取从第30个字符开始往后的内容 const subStr = decodedFirst.slice(30) - // 第二次Base64解码 - return Base64.decode(subStr) != '' ? Base64.decode(subStr) : data + // 第二次Base64解码;解出空串说明业务上就是未填写,不要回退成密文 + const decodedSecond = Base64.decode(subStr) + return decodedSecond !== '' ? decodedSecond : '' } catch (error) { console.error(`解码Base64字符串【${data}】时发生错误`, error) - return data + return '' } } diff --git a/subPackages/my/myinfo-add.vue b/subPackages/my/myinfo-add.vue index 6aac0bd..3586313 100644 --- a/subPackages/my/myinfo-add.vue +++ b/subPackages/my/myinfo-add.vue @@ -12,14 +12,24 @@ - + 身份证号 - - + + + + 生日 + + {{ form.birthday || '请选择年月日' }} + + + + + 性别 @@ -30,7 +40,7 @@ - + 年龄 = 1 && n <= 200; }, - calcAgeFromIdCard(idCard) { + /** 身份证格式正则(与后端 cc_is_id_card 大致对齐) */ + isValidIdCard(idCard) { const reg = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; - if (!reg.test(idCard)) { + return reg.test(idCard || ''); + }, + /** 按 YYYY-MM-DD 计算周岁,非法返回 false */ + calcAgeFromBirthday(birthday) { + if (!birthday || !/^\d{4}-\d{2}-\d{2}$/.test(birthday)) { + return false; + } + const birthdays = new Date(birthday.replace(/-/g, '/')); + if (isNaN(birthdays.getTime())) { + return false; + } + const d = new Date(); + if (birthdays > d) { + return false; + } + return ( + d.getFullYear() - + birthdays.getFullYear() - + (d.getMonth() < birthdays.getMonth() || + (d.getMonth() === birthdays.getMonth() && d.getDate() < birthdays.getDate()) ? + 1 : + 0) + ); + }, + calcAgeFromIdCard(idCard) { + if (!this.isValidIdCard(idCard)) { return false; } const orgBirthday = idCard.substring(6, 14); @@ -760,16 +799,39 @@ orgBirthday.substring(4, 6) + '-' + orgBirthday.substring(6, 8); - const birthdays = new Date(birthday.replace(/-/g, '/')); - const d = new Date(); - return ( - d.getFullYear() - - birthdays.getFullYear() - - (d.getMonth() < birthdays.getMonth() || - (d.getMonth() === birthdays.getMonth() && d.getDate() < birthdays.getDate()) ? - 1 : - 0) - ); + return this.calcAgeFromBirthday(birthday); + }, + /** 选择生日后反算年龄(无证时用) */ + onBirthdayChange(e) { + const birthday = (e && e.detail && e.detail.value) || ''; + this.form.birthday = birthday; + const age = this.calcAgeFromBirthday(birthday); + if (age !== false) { + this.form.age = age; + if (age > 6) { + this.resetGuardian(); + } + } + }, + /** 提交前:身份证可空,但无证时生日必填;有证需格式正确 */ + validateIdentity() { + const idCard = (this.form.identityCardNo || '').trim(); + const birthday = (this.form.birthday || '').trim(); + if (!idCard && !birthday) { + uni.showToast({ + title: '请填写身份证或生日', + icon: 'none', + }); + return false; + } + if (idCard && !this.isValidIdCard(idCard)) { + uni.showToast({ + title: '身份证号格式不正确', + icon: 'none', + }); + return false; + } + return true; }, validatePatientAge() { if (!this.isAgeInRange(this.form.age)) { @@ -859,7 +921,7 @@ }, // 添加就诊人 async getAdduser() { - if (!this.validatePatientAge() || !this.validateGuardian()) { + if (!this.validateIdentity() || !this.validatePatientAge() || !this.validateGuardian()) { return; } try { @@ -884,7 +946,8 @@ is_default: this.checked ? '1' : '0', id: this.addid, name: this.names, - id_card: this.form.identityCardNo, + id_card: (this.form.identityCardNo || '').trim(), + birthday: (this.form.birthday || '').trim(), sex: (this.form.sex) == '女' ? '2' : (this.form.sex == '男' ? '1' : this.form.sex), age: this.form.age, mobile: this.phone, @@ -1036,43 +1099,38 @@ this.toggleHistoryTag('rSelectPresent', 'present_history', e, item) }, - // 身份证号码 + // 身份证号码:合法时自动解析并回填生日/年龄/性别(年龄按生日算) inputChange() { - const reg = - /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; - if (reg.test(this.form.identityCardNo)) { - var org_birthday = this.form.identityCardNo.substring(6, 14); - var org_gender = this.form.identityCardNo.substring(16, 17); - var sex = org_gender % 2 == 1 ? "男" : "女"; - var birthday = - org_birthday.substring(0, 4) + - "-" + - org_birthday.substring(4, 6) + - "-" + - org_birthday.substring(6, 8); - var birthdays = new Date(birthday.replace(/-/g, "/")); - - let d = new Date(); - let age = - d.getFullYear() - - birthdays.getFullYear() - - (d.getMonth() < birthdays.getMonth() || - (d.getMonth() == birthdays.getMonth() && - d.getDate() < birthdays.getDate()) ? - 1 : 0); - this.form.sex = sex; + if (!this.isValidIdCard(this.form.identityCardNo)) { + return false; + } + var org_birthday = this.form.identityCardNo.substring(6, 14); + var org_gender = this.form.identityCardNo.substring(16, 17); + var sex = org_gender % 2 == 1 ? "1" : "2"; + var birthday = + org_birthday.substring(0, 4) + + "-" + + org_birthday.substring(4, 6) + + "-" + + org_birthday.substring(6, 8); + var age = this.calcAgeFromBirthday(birthday); + // 有证必回填生日,供后续优先生日算年龄 + this.form.birthday = birthday; + this.form.sex = sex; + if (age !== false) { this.form.age = age; - this.sex = org_gender% 2 == 1 ? 1 : 2; if (age > 6) { this.resetGuardian(); } - } else { - this.form.sex = ""; - return false; } + this.sex = org_gender % 2 == 1 ? 1 : 2; }, }, mounted() { + const d = new Date(); + const m = (d.getMonth() + 1) < 10 ? '0' + (d.getMonth() + 1) : '' + (d.getMonth() + 1); + const day = d.getDate() < 10 ? '0' + d.getDate() : '' + d.getDate(); + this.todayDate = d.getFullYear() + '-' + m + '-' + day; this.getAction(); this.loadPatientList(); } @@ -1119,6 +1177,16 @@ color: #1E293B; } + .birthday-value { + display: flex; + align-items: center; + gap: 8rpx; + + .placeholder { + color: #94A3B8; + } + } + ::v-deep .u-input { width: 400rpx; } diff --git a/subPackages/my/myinfo-edit.vue b/subPackages/my/myinfo-edit.vue index 0f26529..95e0ea1 100644 --- a/subPackages/my/myinfo-edit.vue +++ b/subPackages/my/myinfo-edit.vue @@ -13,20 +13,34 @@ - + 身份证号 - - + + + + 生日 + + {{ form.birthday || '请选择年月日' }} + + + + + 性别 - + + + + - + 年龄 6) { this.resetGuardian(); } - } else { - this.form.sex = ""; - return false; } + this.sex = org_gender % 2 == 1 ? 1 : 2; }, // 就诊人关系 @@ -851,7 +869,13 @@ that.phone = that.infoList[0].mobile that.form.sex = (that.infoList[0].sex) % 2 == 0 ? '女' : '男' that.form.age = that.infoList[0].age - that.form.identityCardNo = that.infoList[0].id_card + that.form.identityCardNo = that.infoList[0].id_card || '' + // 回显生日;若有证但库里无生日,再从证号补一次 + that.form.birthday = that.infoList[0].birthday || '' + if (!that.form.birthday && that.isValidIdCard(that.form.identityCardNo)) { + const org = that.form.identityCardNo.substring(6, 14) + that.form.birthday = org.substring(0, 4) + '-' + org.substring(4, 6) + '-' + org.substring(6, 8) + } that.addid = that.infoList[0].id // 编辑页无「设为默认」开关,保存时原样回传,避免后端缺省写成 0 that.checked = Number(that.infoList[0].is_default) === 1 @@ -933,10 +957,68 @@ const n = Number(age); return age !== '' && !isNaN(n) && n >= 1 && n <= 200; }, - calcAgeFromIdCard(idCard) { + /** 身份证格式校验 */ + isValidIdCard(idCard) { const reg = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; - if (!reg.test(idCard)) { + return reg.test(idCard || ''); + }, + /** 按 YYYY-MM-DD 计算周岁,非法返回 false */ + calcAgeFromBirthday(birthday) { + if (!birthday || !/^\d{4}-\d{2}-\d{2}$/.test(birthday)) { + return false; + } + const birthdays = new Date(birthday.replace(/-/g, '/')); + if (isNaN(birthdays.getTime())) { + return false; + } + const d = new Date(); + if (birthdays > d) { + return false; + } + return ( + d.getFullYear() - + birthdays.getFullYear() - + (d.getMonth() < birthdays.getMonth() || + (d.getMonth() === birthdays.getMonth() && d.getDate() < birthdays.getDate()) ? + 1 : + 0) + ); + }, + /** 选择生日后反算年龄(无证时用) */ + onBirthdayChange(e) { + const birthday = (e && e.detail && e.detail.value) || ''; + this.form.birthday = birthday; + const age = this.calcAgeFromBirthday(birthday); + if (age !== false) { + this.form.age = age; + if (age > 6) { + this.resetGuardian(); + } + } + }, + /** 提交前:身份证可空,但无证时生日必填;有证需格式正确 */ + validateIdentity() { + const idCard = (this.form.identityCardNo || '').trim(); + const birthday = (this.form.birthday || '').trim(); + if (!idCard && !birthday) { + uni.showToast({ + title: '请填写身份证或生日', + icon: 'none', + }); + return false; + } + if (idCard && !this.isValidIdCard(idCard)) { + uni.showToast({ + title: '身份证号格式不正确', + icon: 'none', + }); + return false; + } + return true; + }, + calcAgeFromIdCard(idCard) { + if (!this.isValidIdCard(idCard)) { return false; } const orgBirthday = idCard.substring(6, 14); @@ -946,16 +1028,7 @@ orgBirthday.substring(4, 6) + '-' + orgBirthday.substring(6, 8); - const birthdays = new Date(birthday.replace(/-/g, '/')); - const d = new Date(); - return ( - d.getFullYear() - - birthdays.getFullYear() - - (d.getMonth() < birthdays.getMonth() || - (d.getMonth() === birthdays.getMonth() && d.getDate() < birthdays.getDate()) ? - 1 : - 0) - ); + return this.calcAgeFromBirthday(birthday); }, validatePatientAge() { if (!this.isAgeInRange(this.form.age)) { @@ -1044,9 +1117,9 @@ return res.data.message || res.data.msg || '保存失败'; }, - // 添加就诊人 + // 保存就诊人 async getAdduser() { - if (!this.validatePatientAge() || !this.validateGuardian()) { + if (!this.validateIdentity() || !this.validatePatientAge() || !this.validateGuardian()) { return; } try { @@ -1070,7 +1143,8 @@ store_id: uni.getStorageSync('store_id') || '11001', id: this.addid, name: this.names, - id_card: this.form.identityCardNo, + id_card: (this.form.identityCardNo || '').trim(), + birthday: (this.form.birthday || '').trim(), sex: (this.form.sex) == '女' ? '2' : '1', age: this.form.age, mobile: this.phone, @@ -1240,6 +1314,16 @@ color: #1E293B; } + .birthday-value { + display: flex; + align-items: center; + gap: 8rpx; + + .placeholder { + color: #94A3B8; + } + } + ::v-deep .u-input { width: 380rpx; } diff --git a/subPackages/my/myinfo.vue b/subPackages/my/myinfo.vue index dd761ad..dc6ead6 100644 --- a/subPackages/my/myinfo.vue +++ b/subPackages/my/myinfo.vue @@ -30,7 +30,7 @@ - {{item.id_card_tm || item.id_card}} + {{ item.id_card_tm || item.id_card || '未填写' }} {{item.mobile_tm || item.mobile}} diff --git a/subPackages/register/components/RegisterPatientStep.vue b/subPackages/register/components/RegisterPatientStep.vue index 1965fae..f68f5b1 100644 --- a/subPackages/register/components/RegisterPatientStep.vue +++ b/subPackages/register/components/RegisterPatientStep.vue @@ -376,6 +376,32 @@ export default { if (this.followUpDrugIdsForApi().length === 0) return '请至少选择一种药品'; return ''; }, + /** + * 在线复诊必须有就诊人身份证:列表接口已解密回传 id_card,空则引导去编辑页补填 + * 普通挂号不强制 + */ + ensureFollowUpPatientIdCard() { + if (this.registerType !== '2' && this.registerType !== '3') { + return true; + } + if (!this.actived) { + uni.showToast({ title: '请选择就诊人', icon: 'none' }); + return false; + } + const patient = this.infoList.find((p) => p.id === this.actived) || null; + const idCard = patient ? String(patient.id_card || '').trim() : ''; + if (!idCard) { + uni.showToast({ + title: '复诊需补充就诊人身份证', + icon: 'none', + }); + setTimeout(() => { + uni.navigateTo({ url: '/subPackages/my/myinfo-edit?id=' + this.actived }); + }, 500); + return false; + } + return true; + }, async prepareFollowUpRegisterInfo() { let params = typeof this.rInfo === 'string' ? JSON.parse(this.rInfo) : { ...(this.rInfo || {}) }; if (params.info_id) { @@ -606,6 +632,10 @@ export default { }); }, subScriptionMessage() { + // 在线复诊:先校验就诊人是否已填身份证 + if (!this.ensureFollowUpPatientIdCard()) { + return; + } if (this.showFollowUpForm) { const err = this.validateFollowUpFields(); if (err) {