Files
bodyWeight/miniprogram/pages/addUser/addUser.ts
T
17792275749andClaude Opus 4.7 1dfda24645 feat(addUser): 生日不超今天、身高体重范围校验并失焦清空
- 出生年月 picker 限制到今天
- 身高 50-250cm、体重 20-300kg
- 失焦时越界值清空并提示

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-09-02 19:44:53 +08:00

448 lines
16 KiB
TypeScript

import { get, put } from '../../utils/request/index'
import { getUserInfoByIdCard, type UserInfo } from '../../api/index'
import { parseIdCard, isIdCardValid, calcAge } from '../../utils/idCard/index'
/** 表单数据模型 */
interface MemberForm {
workNo: string
name: string
idCard: string
gender: string
age: string
height: string
weight: string
sex: number
}
/** 员工编号查询接口(页面私有) */
const getEmployeeByWorkNo = (sn: string, workNo: string) =>
get<any>('weighingScale/v5/getUserInfoByWkno', { sn, workNo })
/** 添加/编辑用户接口(页面私有) */
const addUser = (data: Record<string, any>) =>
put('weighingScale/v6/edit/user', data)
/** 用户详情接口(编辑模式回填) */
const getUserInfoById = (id: string) =>
get<Record<string, any>>('weighingScale/v3/select/userinfo/byId', { id })
/** 目标设备 SN(由 userManagement 跳转传入) */
let targetSn = ''
/** 编辑的用户 id(空表示新增) */
let editId = ''
Page({
data: {
userType: 'employee' as 'employee' | 'family',
form: {
workNo: '',
name: '',
idCard: '',
gender: '',
age: '',
height: '',
weight: '',
sex: 0,
} as MemberForm,
birthday: '',
readonly: false,
showConfirmModal: false,
serverResult: null as UserInfo | null,
employeeQueried: false,
employeeNotFound: false,
unitDisplay: '',
employeeQueryResult: null as Record<string, any> | null,
rawUser: null as Record<string, any> | null,
isEdit: false,
queryError: false,
today: '',
},
onLoad(options: Record<string, string>) {
targetSn = decodeURIComponent(options.sn || '')
console.log(targetSn);
editId = decodeURIComponent(options.id || '')
const now = new Date()
const today = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`
this.setData({ isEdit: !!editId, today })
if (editId) {
this._loadEditUser(editId)
}
},
/** 编辑模式:加载用户详情回填表单 */
_loadEditUser(userId: string) {
getUserInfoById(userId)
.then((res) => {
const u = res.result
if (!u) {
wx.showToast({ title: '加载用户信息失败', icon: 'none' })
return
}
const isFamily = u.dataType === 1
const sex = u.sex ?? 0
const gender = sex === 1 ? '男' : sex === 2 ? '女' : ''
const age = calcAge(u.birthday ?? '')
this.setData({
rawUser: u,
userType: isFamily ? 'family' : 'employee',
birthday: u.birthday ?? '',
'form.workNo': u.workNo ?? '',
'form.name': u.realname ?? '',
'form.idCard': u.idCard ?? '',
'form.gender': gender,
'form.age': String(age),
'form.sex': sex,
'form.height': u.height ? String(u.height) : '',
'form.weight': u.weight ? String(u.weight) : '',
})
if (!isFamily) {
this.setData({
employeeQueried: true,
employeeQueryResult: u,
unitDisplay: [u.secondDepart, u.thirdDepart].filter(Boolean).join(' / '),
})
}
})
.catch((err: any) => {
console.error('[addUser] 加载用户信息失败:', err)
wx.showToast({ title: err?.msg || err?.message || '加载用户信息失败', icon: 'none' })
})
},
/** tabs 切换:清空查询结果、重置表单 */
onTabTap(e: WechatMiniprogram.TouchEvent) {
if (this.data.isEdit) return
const tab = e.currentTarget.dataset.value as string
this.setData({
userType: tab as 'employee' | 'family',
employeeQueried: false,
employeeNotFound: false,
unitDisplay: '',
employeeQueryResult: null,
readonly: false,
serverResult: null,
form: { workNo: '', name: '', idCard: '', gender: '', age: '', height: '', weight: '', sex: 0 },
birthday: '',
queryError: false,
})
},
/** 员工编号变更:清空查询状态与表单 */
onWorkNoInput(e: WechatMiniprogram.Input) {
this.setData({
'form.workNo': e.detail.value,
employeeQueried: false,
employeeNotFound: false,
unitDisplay: '',
employeeQueryResult: null,
'form.name': '',
'form.gender': '',
'form.age': '',
'form.height': '',
'form.weight': '',
})
},
/** 员工编号查询 */
onQueryEmployee() {
const workNo = this.data.form.workNo.trim()
if (!workNo) {
wx.showToast({ title: '请填写员工编号', icon: 'none' })
return
}
this.setData({ employeeQueried: false, employeeNotFound: false })
getEmployeeByWorkNo(targetSn, workNo)
.then((res) => {
const result = res.result
if (!result) {
this.setData({
employeeQueried: true,
employeeNotFound: true,
unitDisplay: '',
employeeQueryResult: null,
'form.name': '',
'form.gender': '',
'form.age': '',
'form.height': '',
'form.weight': '',
})
return
}
const idCard = result.idCard || ''
const parsed = parseIdCard(idCard)
const sex = result.sex || parsed.sex
this.setData({
employeeQueried: true,
employeeNotFound: false,
employeeQueryResult: result,
unitDisplay: [result.secondDepart, result.thirdDepart].filter(Boolean).join(' / '),
'form.name': result.realname || '',
'form.idCard': idCard,
'form.gender': sex === 1 ? '男' : (sex === 2 ? '女' : parsed.gender),
'form.age': parsed.age,
'form.sex': sex,
'form.height': result.height ? String(result.height) : '',
'form.weight': result.weight ? String(result.weight) : '',
birthday: result.birthday || '',
})
})
.catch(() => {
this.setData({ employeeQueried: true, employeeNotFound: true, unitDisplay: '', employeeQueryResult: null })
})
},
/** 家庭用户:姓名变更清空查询结果 */
onNameInput(e: WechatMiniprogram.Input) {
this.setData({
'form.name': e.detail.value.trim(),
serverResult: null,
'form.gender': '',
'form.age': '',
'form.sex': 0,
'form.height': '',
'form.weight': '',
birthday: '',
readonly: false,
queryError: false,
})
},
/** 失焦重新校验 */
onNameBlur() {
if (!this.data.form.name) return
this.validateIdCard()
},
/** 家庭用户:身份证变更清空查询结果 */
onIdCardInput(e: WechatMiniprogram.Input) {
const idCard = (e.detail.value || '').trim().toUpperCase()
this.setData({
'form.idCard': idCard,
serverResult: null,
'form.gender': '',
'form.age': '',
'form.sex': 0,
'form.height': '',
'form.weight': '',
birthday: '',
readonly: false,
queryError: false,
})
if (idCard.length === 18) this.validateIdCard()
},
/** 身份证合法且姓名已填则查询 */
validateIdCard() {
const { idCard, name } = this.data.form
if (isIdCardValid(idCard) && name) this.fetchUser()
},
/** 查询身份证对应的用户信息,101 复用 */
fetchUser() {
getUserInfoByIdCard({
sn: targetSn,
idCard: this.data.form.idCard,
realname: this.data.form.name,
}).then((res) => {
const serverResult = res.result
const { gender, age, sex, birthday } = parseIdCard(serverResult?.idCard || this.data.form.idCard)
this.setData({ 'form.gender': gender, 'form.age': age, 'form.sex': sex, birthday, queryError: false })
if (!serverResult) {
return
}
if (serverResult.flag === 101) {
this.setData({
serverResult,
'form.name': serverResult.realname ?? '',
'form.idCard': serverResult.idCard ?? '',
'form.height': serverResult.height ? String(serverResult.height) : '',
'form.weight': serverResult.weight ? String(serverResult.weight) : '',
readonly: true,
showConfirmModal: true,
})
return
}
if (serverResult.flag === null) {
this.setData({
serverResult,
'form.height': serverResult.height ? String(serverResult.height) : '',
'form.weight': serverResult.weight ? String(serverResult.weight) : '',
})
return
}
}).catch(() => {
// 查询报错:仍按身份证解析性别/年龄,标记需重新查询
const { gender, age, sex, birthday } = parseIdCard(this.data.form.idCard)
this.setData({ 'form.gender': gender, 'form.age': age, 'form.sex': sex, birthday, queryError: true })
})
},
/** 家庭用户:性别切换 */
onGenderTap(e: WechatMiniprogram.TouchEvent) {
const value = e.currentTarget.dataset.value as string
this.setData({ 'form.gender': value, 'form.sex': value === '男' ? 1 : 2 })
},
/** 出生年月变更 */
onBirthdayChange(e: WechatMiniprogram.PickerChange) {
this.setData({ birthday: e.detail.value as string })
},
onHeightInput(e: WechatMiniprogram.Input) {
this.setData({ 'form.height': e.detail.value })
},
onWeightInput(e: WechatMiniprogram.Input) {
this.setData({ 'form.weight': e.detail.value })
},
/** 身高失焦校验:不在 50-250 则清空 */
onHeightBlur() {
const height = this.data.form.height.trim()
if (!height) return
const h = parseFloat(height)
if (isNaN(h) || h < 50 || h > 250) {
wx.showToast({ title: '身高需在50-250cm之间', icon: 'none' })
this.setData({ 'form.height': '' })
}
},
/** 体重失焦校验:不在 20-300 则清空 */
onWeightBlur() {
const weight = this.data.form.weight.trim()
if (!weight) return
const w = parseFloat(weight)
if (isNaN(w) || w < 20 || w > 300) {
wx.showToast({ title: '体重需在20-300kg之间', icon: 'none' })
this.setData({ 'form.weight': '' })
}
},
/** 复用已有信息:关弹框直接提交 */
onConfirmModalConfirm() {
this.setData({ showConfirmModal: false })
this.onSubmit()
},
/** 不复用:清空整个表单 */
onConfirmModalCancel() {
this.setData({
showConfirmModal: false,
readonly: false,
serverResult: null,
form: { workNo: '', name: '', idCard: '', gender: '', age: '', height: '', weight: '', sex: 0 },
birthday: '',
queryError: false,
})
},
onCancel() {
wx.navigateBack()
},
/** 提交用户 */
async onSubmit() {
const { name, idCard, gender, height, weight, sex } = this.data.form
const { userType } = this.data
const heightNum = parseFloat(height)
const weightNum = parseFloat(weight)
if (userType === 'employee') {
if (!this.data.employeeQueried || this.data.employeeNotFound) {
wx.showToast({ title: '请先查询员工信息', icon: 'none' })
return
}
} else {
if (!name.trim()) {
wx.showToast({ title: '请填写昵称', icon: 'none' })
return
}
if (!gender) {
wx.showToast({ title: '请选择性别', icon: 'none' })
return
}
if (!this.data.birthday.trim()) {
wx.showToast({ title: '请填写出生年月', icon: 'none' })
return
}
}
// 身高体重范围校验(员工/家庭用户共用)
if (!height || isNaN(heightNum) || heightNum < 50 || heightNum > 250) {
wx.showToast({ title: '身高需在50-250cm之间', icon: 'none' })
return
}
if (weight && (isNaN(weightNum) || weightNum < 20 || weightNum > 300)) {
wx.showToast({ title: '体重需在20-300kg之间', icon: 'none' })
return
}
// 家庭用户新增:身份证查询报错 → 重新查询,成功后再提交
let sexFinal = sex
let birthdayFinal = this.data.birthday
if (userType === 'family' && !editId && this.data.queryError) {
try {
const res = await getUserInfoByIdCard({ sn: targetSn, idCard, realname: name.trim() })
const result = res.result
const parsed = parseIdCard(result?.idCard || idCard)
this.setData({
serverResult: result,
'form.gender': parsed.gender,
'form.age': parsed.age,
'form.sex': parsed.sex,
birthday: parsed.birthday,
queryError: false,
})
sexFinal = parsed.sex
birthdayFinal = parsed.birthday
} catch (err: any) {
console.error('[addUser] 重新查询失败:', err)
wx.showToast({ title: err?.msg || err?.message || '查询失败,请重试', icon: 'none' })
return
}
}
const userInfo = wx.getStorageSync('userInfo') as Record<string, any> | null
// 编辑:以详情接口返回为 base;新增:员工用查询结果、家庭用身份证查询结果
const baseSpread = editId
? (this.data.rawUser ?? {})
: (userType === 'employee'
? (this.data.employeeQueryResult ?? {})
: (this.data.serverResult ?? {}))
const payload: Record<string, any> = {
...baseSpread,
dataType: userType === 'family' ? 1 : 0,
parentUserId: userInfo?.userId ?? '',
sn: targetSn,
scaleDeviceId: targetSn,
realname: name.trim(),
idCard: idCard || null,
sex: sexFinal,
birthday: birthdayFinal,
height: heightNum,
weight: isNaN(weightNum) ? 0 : weightNum,
mode: getApp<IAppOption>().globalData.operationsEngineer ? 'ops' : 'normal',
}
if (editId) {
payload.id = editId
}
addUser(payload)
.then(() => {
wx.showToast({ title: editId ? '保存成功' : '添加成功', icon: 'success' })
// 调用上一个页面(userManagement)刷新成员列表
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2] as any
prevPage?._loadMembers?.()
setTimeout(() => wx.navigateBack(), 1500)
})
.catch((err: any) => {
console.error('[addUser] 添加用户失败:', err)
wx.showToast({ title: err?.msg || err?.message || '添加失败,请重试', icon: 'none' })
})
},
})