Files
bodyWeight/miniprogram/pages/editMember/editMember.ts
T

383 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { get, put } from '../../utils/request/index'
import { lefuService } from '../../lefu/index'
/** GET /weighingScale/v3/getUserInfoByIdcard 返回的 result 结构 */
interface UserInfoFromServer {
id: string | null
userId: string
parentUserId: string | null
scaleDeviceId: string
deviceId: string | null
deviceType: string
dataType: number
userType: string | null
idCard: string
height: number
weight: number
birthday: string
sex: number
avatar: string | null
phone: string
thirdId: string | null
realname: string
bmi: number
workNo: string
remark: string | null
relationType: string | null
sn: string
delFlag: number
sex_dictText: string
}
/** 表单数据模型 */
interface MemberForm {
name: string
idCard: string
gender: string
age: string
height: string
weight: string
/** 1=男 2=女 */
sex: number
}
/** 身份证解析结果 */
interface IdCardParsed {
gender: string
age: string
sex: number
birthday: string
}
/**
* 编辑用户页
* 根据用户 dataType 区分非家庭/家庭两种编辑模式
*/
Page({
data: {
userId: '',
/** dataType === 1 为家庭用户 */
isFamily: false,
/** 单位(非家庭用户) */
unitDisplay: '',
/** 出生年月 YYYY-MM-DD(家庭用户) */
birthday: '',
/** 接口返回的原始用户数据,提交时以此为 base 覆盖修改字段 */
rawUser: null as Record<string, any> | null,
/** 正在请求身份证查询接口 */
querying: false,
/** 是否已完成一次身份证查询 */
hasQueried: false,
/** 接口返回的用户信息 */
serverResult: null as UserInfoFromServer | null,
/** 表单只读状态(code=101 时置为 true */
readonly: false,
/** 是否显示确认弹框 */
showConfirmModal: false,
form: {
name: '',
idCard: '',
gender: '',
age: '',
height: '',
weight: '',
sex: 0,
} as MemberForm,
},
onLoad(options: Record<string, string>) {
const { userId } = options
if (!userId) {
wx.showToast({ title: '缺少用户信息', icon: 'none' })
setTimeout(() => wx.navigateBack(), 1500)
return
}
this.setData({ userId })
get<Record<string, any>>('weighingScale/v3/select/userinfo/byId', { id: userId }, { loading: true })
.then((res: any) => {
const u = res.result
if (!u) return
const isFamily = u.dataType === 1
const sex = u.sex ?? 0
const gender = sex === 1 ? '男' : sex === 2 ? '女' : ''
const age = this.calcAge(u.birthday ?? '')
this.setData({
rawUser: u,
isFamily,
unitDisplay: [u.secondDepart, u.thirdDepart].filter(Boolean).join(' / '),
birthday: u.birthday ?? '',
'form.name': u.realname ?? '',
'form.idCard': u.idCard ?? '',
'form.gender': gender,
'form.age': String(age),
'form.height': String(u.height ?? ''),
'form.weight': String(u.weight ?? ''),
'form.sex': sex,
})
})
.catch(() => {
wx.showToast({ title: '加载用户信息失败', icon: 'none' })
})
},
/** 从生日字符串计算周岁 */
calcAge(birthday: string): number {
if (!birthday) return 0
const parts = birthday.split('-').map(Number)
const [year, month, day] = parts
if (!year || !month || !day) return 0
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
return Math.max(0, age)
},
onNameInput(e: WechatMiniprogram.Input) {
const name = e.detail.value
this.setData({
'form.name': name,
serverResult: null,
hasQueried: false,
readonly: false
})
if (this.data.isFamily && 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()
if (!this.data.isFamily) {
this.setData({ 'form.idCard': idCard })
return
}
if (this.isIdCardValid(idCard)) {
const parsed = this.parseIdCard(idCard)
this.setData({
'form.idCard': idCard,
'form.gender': parsed.gender,
'form.age': parsed.age,
'form.sex': parsed.sex,
birthday: parsed.birthday,
})
} else {
this.setData({
'form.idCard': idCard,
'form.gender': '',
'form.age': '',
'form.sex': 0,
birthday: '',
})
}
},
/** 家庭用户性别切换 */
onGenderTap(e: WechatMiniprogram.TouchEvent) {
const value = e.currentTarget.dataset.value as string
const sex = value === '男' ? 1 : 2
this.setData({
'form.gender': value,
'form.sex': sex,
})
},
onHeightInput(e: WechatMiniprogram.Input) {
this.setData({ 'form.height': e.detail.value })
},
onWeightInput(e: WechatMiniprogram.Input) {
this.setData({ 'form.weight': e.detail.value })
},
isIdCardValid(idCard: string): boolean {
return /^\d{17}[\dX]$/.test(idCard)
},
parseIdCard(idCard: string): IdCardParsed {
const empty: IdCardParsed = { gender: '', age: '', sex: 0, birthday: '' }
if (!this.isIdCardValid(idCard)) return empty
const genderCode = parseInt(idCard.charAt(16), 10)
const sex = genderCode % 2 === 1 ? 1 : 2
const gender = sex === 1 ? '男' : '女'
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 < 1 || month > 12 || day < 1 || day > 31) return empty
const now = new Date()
let age = now.getFullYear() - year
if (now.getMonth() + 1 < month || (now.getMonth() + 1 === month && now.getDate() < day)) age -= 1
if (age < 0 || age > 150) return empty
const mm = String(month).padStart(2, '0')
const dd = String(day).padStart(2, '0')
return { gender, age: String(age), sex, birthday: `${year}-${mm}-${dd}` }
},
fetchUserInfoByIdCard(name: string, idCard: string) {
if (this.data.querying) return
this.setData({ querying: true, serverResult: null, hasQueried: false })
get<any>('weighingScale/v3/getUserInfoByIdcard', {
sn: lefuService.deviceInfo?.serialNumber ?? '',
idCard,
realname: name
}, { loading: true })
.then(res => {
const serverResult = res.result
if (!serverResult) {
wx.showToast({ title: res.message || '未查询到用户信息', icon: 'none' })
const parsed = this.parseIdCard(idCard)
this.setData({
hasQueried: true,
'form.gender': parsed.gender,
'form.age': parsed.age,
'form.sex': parsed.sex,
birthday: parsed.birthday,
})
return
}
if (serverResult.flag == 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.sex': parsed.sex,
'form.height': serverResult.height ? String(serverResult.height) : '',
'form.weight': serverResult.weight ? String(serverResult.weight) : '',
birthday: serverResult.birthday || parsed.birthday
})
return
}
if (serverResult.flag === null) {
const parsed = this.parseIdCard(serverResult.idCard)
const data: Record<string, any> = {
serverResult,
hasQueried: true,
'form.gender': parsed.gender,
'form.age': parsed.age,
'form.sex': parsed.sex,
birthday: serverResult.birthday || parsed.birthday
}
if (serverResult.height) {
data['form.height'] = String(serverResult.height)
}
if (serverResult.weight) {
data['form.weight'] = String(serverResult.weight)
}
this.setData(data)
}
})
.catch(() => {})
.finally(() => {
this.setData({ querying: false })
})
},
onConfirmModalConfirm() {
this.setData({ showConfirmModal: false })
this.onSubmit()
},
onConfirmModalCancel() {
this.setData({
showConfirmModal: false,
readonly: false,
'form.name': '',
'form.idCard': '',
'form.gender': '',
'form.age': '',
'form.height': '',
'form.weight': '',
serverResult: null,
hasQueried: false,
})
},
/** 出生年月变更,同步更新年龄 */
onBirthdayChange(e: WechatMiniprogram.PickerChange) {
const birthday = e.detail.value as string
const age = this.calcAge(birthday)
this.setData({
birthday,
'form.age': String(age),
})
},
onCancel() {
wx.navigateBack()
},
onSubmit() {
const { name, idCard, gender, height, weight, sex } = this.data.form
const { isFamily, rawUser } = this.data
const heightNum = parseFloat(height)
const weightNum = parseFloat(weight)
// 昵称(仅家庭用户必填)
if (isFamily && !name.trim()) {
wx.showToast({ title: '请填写昵称', icon: 'none' })
return
}
// 家庭用户性别必选
if (isFamily && !gender) {
wx.showToast({ title: '请选择性别', icon: 'none' })
return
}
// 家庭用户出生年月必填
if (isFamily && !this.data.birthday.trim()) {
wx.showToast({ title: '请填写出生年月', icon: 'none' })
return
}
if (!height || isNaN(heightNum) || heightNum <= 0) {
wx.showToast({ title: '请填写身高', icon: 'none' })
return
}
const connectDeviceInfoRaw = wx.getStorageSync('connectDeviceInfo')
// 以接口原始返回 + 身份证查询结果为 base,覆盖编辑后的字段
const serverResult = this.data.serverResult
const payload: Record<string, any> = {
...(rawUser ?? {}),
...(serverResult ?? {}),
id: this.data.userId,
realname: name.trim(),
idCard,
sex,
birthday: this.data.birthday,
height: heightNum,
weight: isNaN(weightNum) ? 0 : weightNum,
connectDeviceInfo: connectDeviceInfoRaw ? JSON.stringify(connectDeviceInfoRaw) : (rawUser?.connectDeviceInfo ?? ''),
}
put('weighingScale/v5/edit/user', payload)
.then(() => {
wx.showToast({ title: '保存成功', icon: 'success' })
setTimeout(() => {
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2] as any
if (prevPage && prevPage.data?.sn) {
prevPage._loadData(prevPage.data.sn)
}
wx.navigateBack()
}, 1500)
})
.catch(() => {
wx.showToast({ title: '保存失败,请重试', icon: 'none' })
})
}
})