feat(addUser): 添加用户模块接入员工查询与身份证复用

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
17792275749
2026-08-24 19:31:04 +08:00
co-authored by Claude Sonnet 4.6
parent a80a5cd939
commit 4b61c882a1
4 changed files with 317 additions and 26 deletions
+3 -1
View File
@@ -1,5 +1,7 @@
{
"usingComponents": {},
"usingComponents": {
"user-info-confirm-modal": "/components/userInfoConfirmModal/userInfoConfirmModal"
},
"navigationBarTitleText": "添加用户",
"navigationBarTextStyle": "black",
"navigationBarBackgroundColor": "#FFFFFF"
+306 -20
View File
@@ -1,16 +1,55 @@
// pages/addUser/addUser.ts
import { get, put } from '../../utils/request/index'
import { getUserInfoByIdCard, type UserInfo } from '../../api/index'
import { parseIdCard, isIdCardValid } 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/v5/edit/user', data)
/** 目标设备 SN(由 userManagement 跳转传入) */
let targetSn = ''
Page({
data: {
userType: 'employee',
employeeId: '9527',
employeeInfo: {
name: '王旭',
company: '技术部·研发组',
gender: '',
age: '32岁'
},
height: '',
weight: ''
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,
},
onLoad(options: Record<string, string>) {
targetSn = decodeURIComponent(options.sn || '')
},
/** tabs 切换:清空查询结果、重置表单 */
@@ -18,21 +57,268 @@ Page({
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: '',
})
},
onTapType(e: WechatMiniprogram.TouchEvent) {
const type = e.currentTarget.dataset.type as string
this.setData({ userType: type })
/** 员工编号变更:清空查询状态与表单 */
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,
})
},
/** 失焦重新校验 */
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,
})
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 })
if (!serverResult) {
wx.showToast({ title: res.msg || '未查询到用户信息', icon: 'none' })
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(() => {})
},
/** 家庭用户:性别切换 */
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 })
},
/** 复用已有信息:关弹框直接提交 */
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: '',
})
},
onCancel() {
wx.navigateBack({
delta: 1
})
wx.navigateBack()
},
onSave() {
// 保存用户信息(待接入)
}
/** 提交用户 */
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
}
if (!height || isNaN(heightNum) || heightNum <= 0) {
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 <= 0) {
wx.showToast({ title: '请填写身高', icon: 'none' })
return
}
}
const userInfo = wx.getStorageSync('userInfo') as Record<string, any> | null
// 员工:以查询接口返回为 base;家庭:以身份证查询结果为 base
const baseSpread = 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,
birthday: this.data.birthday,
height: heightNum,
weight: isNaN(weightNum) ? 0 : weightNum,
}
addUser(payload)
.then(() => {
wx.showToast({ title: '添加成功', icon: 'success' })
// 调用上一个页面(userManagement)刷新成员列表
const pages = getCurrentPages()
const prevPage = pages[pages.length - 2] as any
prevPage?._loadMembers?.()
setTimeout(() => wx.navigateBack(), 1500)
})
.catch(() => {
wx.showToast({ title: '添加失败,请重试', icon: 'none' })
})
},
})
+6 -4
View File
@@ -27,13 +27,13 @@
</view>
<!-- 未查询 -->
<view class="workNoDesc">输入员工编号后自动查询员工信息</view>
<view class="workNoDesc" wx:if="{{ !employeeQueried }}">输入员工编号后自动查询员工信息</view>
<!-- 查询未找到 -->
<view class="workNoNull">未查询到员工信息,请确认员工编号是否正确</view>
<view class="workNoNull" wx:if="{{ employeeQueried && employeeNotFound }}">未查询到员工信息,请确认员工编号是否正确</view>
<!-- 查询成功 -->
<view class="workNoInfo">
<view class="workNoInfo" wx:if="{{ employeeQueried && !employeeNotFound }}">
<view class="workNoInfo_">
<view class="workNoInfoTitle">用户信息</view>
<view class="workNoInfoContent">
@@ -182,6 +182,8 @@
<!-- 保存按钮 -->
<view class="save-btn">
<view class="btn-cancel" bind:tap="onCancel">取消</view>
<view class="btn-primary" bind:tap="onSave">保存用户信息</view>
<view class="btn-primary" bind:tap="onSubmit">保存用户信息</view>
</view>
<user-info-confirm-modal show="{{ showConfirmModal }}" userInfo="{{ serverResult }}" bind:confirm="onConfirmModalConfirm" bind:cancel="onConfirmModalCancel" />
</view>
@@ -291,7 +291,8 @@ Page({
/** 添加用户 */
onTapAddUser() {
wx.navigateTo({ url: '/pages/addUser/addUser' })
const sn = targetDevice?.sn || ''
wx.navigateTo({ url: `/pages/addUser/addUser?sn=${encodeURIComponent(sn)}` })
},
/** 一键添加本人 */