212 lines
4.8 KiB
TypeScript
212 lines
4.8 KiB
TypeScript
/** 表单数据模型 */
|
|
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<SelectMemberItem>) {
|
|
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()
|
|
}
|
|
})
|