feat(family): 表单校验抽纯函数并补单测

This commit is contained in:
ozh 2026-09-09 15:26:29 +08:00
parent 9d1ea0abbc
commit 95a67ae412
3 changed files with 88 additions and 10 deletions

View File

@ -6,6 +6,7 @@ import { addCared, type EmergencyContact } from '@/api/family'
import { MAX_EMERGENCY_CONTACTS, MAX_FAMILY_NAME_LEN } from '@/constants/family' import { MAX_EMERGENCY_CONTACTS, MAX_FAMILY_NAME_LEN } from '@/constants/family'
import { navigateBack } from '@/utils/navigation' import { navigateBack } from '@/utils/navigation'
import { showToast } from '@/utils/toast' import { showToast } from '@/utils/toast'
import { validateContactForm } from './validate'
import styles from './add.module.scss' import styles from './add.module.scss'
const emptyContact = (): EmergencyContact => ({ const emptyContact = (): EmergencyContact => ({
@ -35,14 +36,9 @@ export default function ContactAdd() {
const submit = async () => { const submit = async () => {
if (submitting) return if (submitting) return
if (!name.trim() || !idNumber.trim() || !address.trim()) { const result = validateContactForm({ name, idNumber, address, contacts })
showToast('请填写完整') if (!result.ok) {
return showToast(result.error)
}
// 跳过完全未填的联系人卡,只提交有内容的
const filled = contacts.filter((c) => c.name.trim() || c.phone.trim())
if (filled.some((c) => !c.name.trim() || !c.phone.trim())) {
showToast('请完整填写联系人')
return return
} }
@ -53,7 +49,7 @@ export default function ContactAdd() {
name: name.trim(), name: name.trim(),
idNumber: idNumber.trim(), idNumber: idNumber.trim(),
address: address.trim(), address: address.trim(),
contacts: filled contacts: result.contacts
}) })
showToast('添加成功') showToast('添加成功')
setTimeout(() => navigateBack(), 500) setTimeout(() => navigateBack(), 500)
@ -74,7 +70,7 @@ export default function ContactAdd() {
<Input <Input
className={styles.input} className={styles.input}
placeholder="请输入最多 10 个字" placeholder="请输入最多 10 个字"
maxLength={MAX_FAMILY_NAME_LEN} maxlength={MAX_FAMILY_NAME_LEN}
value={name} value={name}
onInput={(e) => setName(e.detail.value)} onInput={(e) => setName(e.detail.value)}
/> />

View File

@ -0,0 +1,26 @@
import type { EmergencyContact } from '@/api/family'
export interface ContactFormInput {
name: string
idNumber: string
address: string
contacts: EmergencyContact[]
}
export type ValidateResult =
| { ok: true; contacts: EmergencyContact[] }
| { ok: false; error: string }
// 必填项齐全且联系人卡要么空白(忽略)要么填全,才允许提交
export function validateContactForm(input: ContactFormInput): ValidateResult {
if (!input.name.trim() || !input.idNumber.trim() || !input.address.trim()) {
return { ok: false, error: '请填写完整' }
}
const filled = input.contacts.filter((c) => c.name.trim() || c.phone.trim())
if (filled.some((c) => !c.name.trim() || !c.phone.trim())) {
return { ok: false, error: '请完整填写联系人' }
}
return { ok: true, contacts: filled }
}

View File

@ -0,0 +1,56 @@
import { describe, it, expect } from 'vitest'
import { validateContactForm, type ContactFormInput } from '@/pages/family/contact/validate'
import type { EmergencyContact } from '@/api/family'
const contact = (over: Partial<EmergencyContact> = {}): EmergencyContact => ({
id: 'c1',
name: '',
phone: '',
relation: '',
...over
})
const form = (over: Partial<ContactFormInput> = {}): ContactFormInput => ({
name: '王奶奶',
idNumber: '440301194001010000',
address: '深圳市南山区',
contacts: [],
...over
})
describe('添加关爱对象表单校验', () => {
it('必填齐全返回 ok', () => {
const result = validateContactForm(form())
expect(result.ok).toBe(true)
if (result.ok) expect(result.contacts).toEqual([])
})
it('任一必填缺失/空白报 请填写完整', () => {
const r1 = validateContactForm(form({ name: '' }))
const r2 = validateContactForm(form({ idNumber: ' ' }))
const r3 = validateContactForm(form({ address: '' }))
expect(!r1.ok && r1.error).toBe('请填写完整')
expect(!r2.ok && r2.error).toBe('请填写完整')
expect(!r3.ok && r3.error).toBe('请填写完整')
})
it('空白联系人卡被过滤,不阻断提交', () => {
const result = validateContactForm(form({ contacts: [contact()] }))
expect(result.ok).toBe(true)
if (result.ok) expect(result.contacts).toEqual([])
})
it('联系人只填了姓名或电话时报 请完整填写联系人', () => {
const r1 = validateContactForm(form({ contacts: [contact({ name: '张女士' })] }))
const r2 = validateContactForm(form({ contacts: [contact({ phone: '13800138000' })] }))
expect(!r1.ok && r1.error).toBe('请完整填写联系人')
expect(!r2.ok && r2.error).toBe('请完整填写联系人')
})
it('姓名电话齐全的联系人保留在结果中', () => {
const c = contact({ id: 'c9', name: '张女士', phone: '13800138000', relation: '配偶' })
const result = validateContactForm(form({ contacts: [c] }))
expect(result.ok).toBe(true)
if (result.ok) expect(result.contacts).toEqual([c])
})
})