/** 表单数据模型 */ interface MemberForm { /** 姓名 */ name: string /** 身份证号 */ idCard: string /** 性别(由身份证解析,只读) */ gender: string /** 年龄(由身份证解析,只读) */ age: string /** 身高(cm) */ height: string } /** 身份证解析结果 */ interface IdCardParsed { /** 性别,空字符串表示解析失败 */ gender: string /** 年龄,空字符串表示解析失败 */ age: string } /** 已有成员数据项 */ interface SelectMemberItem { /** 唯一标识 */ id: string /** 姓名 */ name: string /** 性别 */ gender: '男' | '女' /** 年龄 */ age: number /** 身高(cm) */ height: number /** 头像 URL,无则显示彩色占位圆 */ avatar?: string /** 是否已选中 */ selected?: boolean } /** * 添加成员页 * 收集姓名、身份证号、身高,并根据身份证自动解析性别与年龄 * 保存后返回设备成员列表页 */ Page({ data: { // 表单数据 form: { name: '', idCard: '', gender: '', age: '', height: '' } as MemberForm, // 抽屉显示状态 showSelectDrawer: false, // TODO: 后续替换为接口数据 existingMembers: [ { id: '1', name: '陈小飞', gender: '男', age: 32, height: 172, avatar: '' }, { id: '2', name: '李镇南', gender: '男', age: 35, height: 185, avatar: '' }, { id: '3', name: '张颖', gender: '女', age: 35, height: 185, avatar: '' }, { id: '4', name: '李镇南', gender: '男', age: 35, height: 185, avatar: '' }, { id: '5', name: '赵雪', gender: '女', age: 31, height: 165, avatar: '' } ] as SelectMemberItem[] }, /** * 姓名输入 */ onNameInput(e: WechatMiniprogram.Input) { this.setData({ 'form.name': e.detail.value }) }, /** * 身份证号输入 * 长度满 18 位时自动解析性别与年龄,否则清空 */ 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 }) }, /** * 身高输入 */ onHeightInput(e: WechatMiniprogram.Input) { this.setData({ 'form.height': e.detail.value }) }, /** * 解析身份证号,返回性别与年龄 * @param idCard 18 位身份证号 */ parseIdCard(idCard: string): IdCardParsed { // 简单校验:18 位且前 17 位为数字 const reg = /^\d{17}[\dX]$/ if (!reg.test(idCard)) { return { gender: '', age: '' } } // 性别:第 17 位奇数为男,偶数为女 const genderCode = parseInt(idCard.charAt(16), 10) const gender = genderCode % 2 === 1 ? '男' : '女' // 出生日期:第 7-14 位 const year = parseInt(idCard.substr(6, 4), 10) const month = parseInt(idCard.substr(10, 2), 10) const day = parseInt(idCard.substr(12, 2), 10) // 基本合法性校验 if ( !year || !month || !day || month < 1 || month > 12 || day < 1 || day > 31 ) { return { gender: '', age: '' } } // 计算周岁(看是否过了今年生日) const now = new Date() let age = now.getFullYear() - year const nowMonth = now.getMonth() + 1 const nowDay = now.getDate() if (nowMonth < month || (nowMonth === month && nowDay < day)) { age -= 1 } if (age < 0 || age > 150) { return { gender: '', age: '' } } return { gender, age: String(age) } }, /** * 从已有成员中选择 — 打开抽屉 */ onTapSelectExisting() { this.setData({ showSelectDrawer: true }) }, /** 关闭选择成员抽屉 */ onSelectMemberClose() { this.setData({ showSelectDrawer: false }) }, /** * 选中成员后填充表单 * @param e 携带 detail(SelectMemberItem) 的自定义事件 */ onSelectMember(e: WechatMiniprogram.CustomEvent) { const { name, gender, age, height } = e.detail this.setData({ showSelectDrawer: false, 'form.name': name, 'form.gender': gender, 'form.age': String(age), 'form.height': String(height) }) }, /** * 取消:直接返回上一页 */ onCancel() { wx.navigateBack() }, /** * 保存成员信息 * 必填:姓名、身份证号(18 位且解析成功)、身高 * 未通过时 toast 提示,通过后返回上一页 */ onSubmit() { const { name, idCard, gender, age, height } = this.data.form const heightNum = parseFloat(height) if (!name.trim()) { wx.showToast({ title: '请填写姓名', icon: 'none' }) return } if (idCard.length !== 18) { wx.showToast({ title: '请填写正确的身份证号', icon: 'none' }) return } if (!gender || !age) { wx.showToast({ title: '身份证号有误,请检查', icon: 'none' }) return } if (!height || isNaN(heightNum) || heightNum <= 0) { wx.showToast({ title: '请填写身高', icon: 'none' }) return } // TODO: 此处后续接入成员保存接口 wx.navigateBack() } })