diff --git a/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.json b/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.json new file mode 100644 index 0000000..ac28323 --- /dev/null +++ b/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.json @@ -0,0 +1,4 @@ +{ + "component": true, + "usingComponents": {} +} diff --git a/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.less b/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.less new file mode 100644 index 0000000..53f8f43 --- /dev/null +++ b/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.less @@ -0,0 +1,139 @@ +.confirm-modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; +} + +.modal-mask { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.5); + opacity: 0; + transition: opacity 0.3s ease; + + &.anim-visible { + opacity: 1; + } +} + +.modal-content { + position: relative; + width: 660rpx; + background-color: #ffffff; + border-radius: 24rpx; + overflow: hidden; + transform: scale(0.9); + opacity: 0; + transition: all 0.3s ease; + + &.anim-visible { + transform: scale(1); + opacity: 1; + } +} + +.modal-header { + padding-top: 50rpx; + width: 100%; + margin-bottom: 30rpx; + + .modal-title { + width: 100%; + height: 36rpx; + font-weight: bolder; + font-size: 36rpx; + color: #252535; + line-height: 36rpx; + text-align: center; + margin-bottom: 24rpx; + } + + .modal-sub-title { + width: 100%; + height: 32rpx; + font-weight: 400; + font-size: 32rpx; + color: #1385FA; + line-height: 32rpx; + text-align: center; + } +} + +.modal-body { + width: 100%; + box-sizing: border-box; + padding: 0 30rpx; + margin-bottom: 30rpx; + + .modal-body-box { + width: 100%; + padding: 0 30rpx; + box-sizing: border-box; + border-radius: 16rpx; + background-color: #F6F6F6; + + .info-row { + width: 100%; + height: 80rpx; + display: flex; + padding: 10rpx 0; + align-items: center; + justify-content: space-between; + box-sizing: border-box; + border-bottom: 1px solid #EAECF1; + + .info-label { + color: #77849E; + height: 80rpx; + font-size: 28rpx; + line-height: 80rpx; + } + + .info-value { + color: #252535; + height: 80rpx; + font-weight: 500; + font-size: 28rpx; + line-height: 80rpx; + } + + &:last-of-type { + border-bottom: none; + } + } + } +} + +.modal-footer { + width: 100%; + height: 110rpx; + display: flex; + border-top: 1rpx solid #EAECF1; + + .modal-btn { + flex: 1; + height: 110rpx; + line-height: 110rpx; + font-size: 36rpx; + text-align: center; + } + + .modal-btn-cancel { + color: #77849E; + border-right: 1rpx solid #EAECF1; + } + + .modal-btn-confirm { + color: #1385FA; + font-weight: 500; + } +} diff --git a/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.ts b/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.ts new file mode 100644 index 0000000..850a43e --- /dev/null +++ b/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.ts @@ -0,0 +1,63 @@ +/** + * 用户信息确认弹框组件 + * Properties: show(控制显示), userInfo(用户信息) + * Events: confirm(确认), cancel(取消) + */ +Component({ + properties: { + /** 是否显示弹框 */ + show: { + type: Boolean, + value: false + }, + /** 用户信息数据 */ + userInfo: { + type: Object, + value: {} + } + }, + + data: { + /** 控制 wx:if,DOM 是否存在 */ + innerShow: false, + /** 控制 --visible 类,触发 CSS transition */ + animVisible: false + }, + + observers: { + /** + * 监听外部 show 变化: + * 打开时先展示弹框再执行动画;关闭时移除动画类后移除 DOM + */ + show(val: boolean) { + if (val) { + this.setData({ innerShow: true }) + setTimeout(() => { + this.setData({ animVisible: true }) + }, 20) + } else { + this.setData({ animVisible: false }) + setTimeout(() => { + this.setData({ innerShow: false }) + }, 300) + } + } + }, + + methods: { + /** 点击遮罩关闭 */ + onTapMask() { + this.triggerEvent('cancel') + }, + + /** 点击取消按钮 */ + onTapCancel() { + this.triggerEvent('cancel') + }, + + /** 点击确认按钮 */ + onTapConfirm() { + this.triggerEvent('confirm') + } + } +}) diff --git a/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.wxml b/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.wxml new file mode 100644 index 0000000..b24c0fa --- /dev/null +++ b/miniprogram/components/userInfoConfirmModal/userInfoConfirmModal.wxml @@ -0,0 +1,45 @@ + + + + + + + + + 当前身份证号已存在 + 是否直接复用信息? + + + + + + + 姓名: + {{ userInfo.realname }} + + + 身份证号: + {{ userInfo.idCard }} + + + 性别: + {{ userInfo.sex_dictText }} + + + 身高: + {{ userInfo.height }}cm + + + 体重: + {{ userInfo.weight }}kg + + + + + + + 取消 + 确认 + + + diff --git a/miniprogram/pages/addMember/addMember.json b/miniprogram/pages/addMember/addMember.json index a5b5e26..b1ea48e 100644 --- a/miniprogram/pages/addMember/addMember.json +++ b/miniprogram/pages/addMember/addMember.json @@ -1,6 +1,7 @@ { "navigationBarTitleText": "添加成员", "usingComponents": { - "select-member-drawer": "/components/selectMemberDrawer/selectMemberDrawer" + "select-member-drawer": "/components/selectMemberDrawer/selectMemberDrawer", + "user-info-confirm-modal": "/components/userInfoConfirmModal/userInfoConfirmModal" } } diff --git a/miniprogram/pages/addMember/addMember.ts b/miniprogram/pages/addMember/addMember.ts index ffc8b35..f49c133 100644 --- a/miniprogram/pages/addMember/addMember.ts +++ b/miniprogram/pages/addMember/addMember.ts @@ -106,6 +106,10 @@ Page({ hasQueried: false, /** 接口返回的用户信息,姓名 + 身份证联动校正性别年龄 */ serverResult: null as UserInfoFromServer | null, + /** 表单只读状态(code=101 时置为 true) */ + readonly: false, + /** 是否显示确认弹框 */ + showConfirmModal: false, }, onLoad(options: Record) { @@ -133,29 +137,30 @@ Page({ onNameInput(e: WechatMiniprogram.Input) { const name = e.detail.value - this.setData({ 'form.name': name }) - if (!name.trim()) { - this.setData({ serverResult: null, hasQueried: false }) - return - } - if (this.isIdCardValid(this.data.form.idCard)) { + this.setData({ + 'form.name': name, + 'form.gender': '', + 'form.age': '', + serverResult: null, + hasQueried: false, + readonly: false + }) + if (name.trim() && this.isIdCardValid(this.data.form.idCard)) { this.fetchUserInfoByIdCard(name.trim(), this.data.form.idCard) } }, onIdCardInput(e: WechatMiniprogram.Input) { const idCard = (e.detail.value || '').trim().toUpperCase() - const parsed = this.parseIdCard(idCard) this.setData({ 'form.idCard': idCard, - 'form.gender': parsed.gender, - 'form.age': parsed.age + 'form.gender': '', + 'form.age': '', + serverResult: null, + hasQueried: false, + readonly: false }) - if (!parsed.gender) { - this.setData({ serverResult: null, hasQueried: false }) - return - } - if (this.data.form.name.trim()) { + if (this.data.form.name.trim() && this.isIdCardValid(idCard)) { this.fetchUserInfoByIdCard(this.data.form.name.trim(), idCard) } }, @@ -204,12 +209,14 @@ Page({ /** * 调用服务端接口校验身份证与姓名,成功后用接口返回的身份证重新计算性别年龄 * result 为 null 视为「查无此人」,标记 hasQueried 允许新增提交 + * result.code 101 视为「信息已存在」,弹框提示并锁定表单 + * result.code 102 视为正常,走原有逻辑 */ fetchUserInfoByIdCard(name: string, idCard: string) { if (this.data.querying) return this.setData({ querying: true, serverResult: null, hasQueried: false }) - get('weighingScale/v3/getUserInfoByIdcard', { + get('weighingScale/v3/getUserInfoByIdcard', { sn: lefuService.deviceInfo?.serialNumber ?? '', idCard, realname: name @@ -220,13 +227,38 @@ Page({ this.setData({ hasQueried: true }) return } - const parsed = this.parseIdCard(serverResult.idCard) - this.setData({ - serverResult, - hasQueried: true, - 'form.gender': parsed.gender, - 'form.age': parsed.age - }) + if (serverResult.code === 101) { + const parsed = this.parseIdCard(serverResult.idCard) + this.setData({ + serverResult, + hasQueried: true, + readonly: true, + showConfirmModal: true, + 'form.name': serverResult.realname ?? '', + 'form.idCard': serverResult.idCard ?? '', + 'form.gender': parsed.gender, + 'form.age': parsed.age, + 'form.height': serverResult.height ? String(serverResult.height) : '', + 'form.weight': serverResult.weight ? String(serverResult.weight) : '' + }) + return + } + if (serverResult.code === 102) { + const parsed = this.parseIdCard(serverResult.idCard) + const data: Record = { + serverResult, + hasQueried: true, + 'form.gender': parsed.gender, + 'form.age': parsed.age + } + if (serverResult.height) { + data['form.height'] = String(serverResult.height) + } + if (serverResult.weight) { + data['form.weight'] = String(serverResult.weight) + } + this.setData(data) + } }) .catch(() => { // 查询失败保留本地解析结果,hasQueried 维持 false 以便用户重试时再次触发 @@ -259,6 +291,28 @@ Page({ }) }, + /** 确认弹框 - 确认 */ + onConfirmModalConfirm() { + this.setData({ showConfirmModal: false }) + this.onSubmit() + }, + + /** 确认弹框 - 取消 */ + onConfirmModalCancel() { + this.setData({ + showConfirmModal: false, + readonly: false, + form: { + name: '', + idCard: '', + gender: '', + age: '', + height: '', + weight: '' + } + }) + }, + onCancel() { wx.navigateBack() }, diff --git a/miniprogram/pages/addMember/addMember.wxml b/miniprogram/pages/addMember/addMember.wxml index 8ad52af..946e787 100644 --- a/miniprogram/pages/addMember/addMember.wxml +++ b/miniprogram/pages/addMember/addMember.wxml @@ -23,6 +23,7 @@ placeholder="请填写真实姓名" placeholder-class="form-placeholder" value="{{ form.name }}" + disabled="{{ readonly }}" bind:input="onNameInput" /> @@ -40,6 +41,7 @@ placeholder="请填写身份证号" placeholder-class="form-placeholder" value="{{ form.idCard }}" + disabled="{{ readonly }}" bind:input="onIdCardInput" /> @@ -93,6 +95,7 @@ placeholder="请填写身高" placeholder-class="form-placeholder" value="{{ form.height }}" + disabled="{{ readonly }}" bind:input="onHeightInput" /> cm @@ -113,6 +116,7 @@ placeholder="请填写体重" placeholder-class="form-placeholder" value="{{ form.weight }}" + disabled="{{ readonly }}" bind:input="onWeightInput" /> kg @@ -138,4 +142,12 @@ bind:close="onSelectMemberClose" bind:select="onSelectMember"> + + + +