From 95a67ae412f44e63c994e4aa0c239b84436f4830 Mon Sep 17 00:00:00 2001 From: ozh Date: Wed, 9 Sep 2026 15:26:29 +0800 Subject: [PATCH] =?UTF-8?q?feat(family):=20=E8=A1=A8=E5=8D=95=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E6=8A=BD=E7=BA=AF=E5=87=BD=E6=95=B0=E5=B9=B6=E8=A1=A5?= =?UTF-8?q?=E5=8D=95=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/family/contact/add.tsx | 16 +++---- src/pages/family/contact/validate.ts | 26 ++++++++++ tests/unit/family/contact-validate.spec.ts | 56 ++++++++++++++++++++++ 3 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 src/pages/family/contact/validate.ts create mode 100644 tests/unit/family/contact-validate.spec.ts diff --git a/src/pages/family/contact/add.tsx b/src/pages/family/contact/add.tsx index b85e43e..40f49bc 100644 --- a/src/pages/family/contact/add.tsx +++ b/src/pages/family/contact/add.tsx @@ -6,6 +6,7 @@ import { addCared, type EmergencyContact } from '@/api/family' import { MAX_EMERGENCY_CONTACTS, MAX_FAMILY_NAME_LEN } from '@/constants/family' import { navigateBack } from '@/utils/navigation' import { showToast } from '@/utils/toast' +import { validateContactForm } from './validate' import styles from './add.module.scss' const emptyContact = (): EmergencyContact => ({ @@ -35,14 +36,9 @@ export default function ContactAdd() { const submit = async () => { if (submitting) return - if (!name.trim() || !idNumber.trim() || !address.trim()) { - showToast('请填写完整') - return - } - // 跳过完全未填的联系人卡,只提交有内容的 - const filled = contacts.filter((c) => c.name.trim() || c.phone.trim()) - if (filled.some((c) => !c.name.trim() || !c.phone.trim())) { - showToast('请完整填写联系人') + const result = validateContactForm({ name, idNumber, address, contacts }) + if (!result.ok) { + showToast(result.error) return } @@ -53,7 +49,7 @@ export default function ContactAdd() { name: name.trim(), idNumber: idNumber.trim(), address: address.trim(), - contacts: filled + contacts: result.contacts }) showToast('添加成功') setTimeout(() => navigateBack(), 500) @@ -74,7 +70,7 @@ export default function ContactAdd() { setName(e.detail.value)} /> diff --git a/src/pages/family/contact/validate.ts b/src/pages/family/contact/validate.ts new file mode 100644 index 0000000..4603d35 --- /dev/null +++ b/src/pages/family/contact/validate.ts @@ -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 } +} diff --git a/tests/unit/family/contact-validate.spec.ts b/tests/unit/family/contact-validate.spec.ts new file mode 100644 index 0000000..54ae959 --- /dev/null +++ b/tests/unit/family/contact-validate.spec.ts @@ -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 => ({ + id: 'c1', + name: '', + phone: '', + relation: '', + ...over +}) + +const form = (over: Partial = {}): 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]) + }) +})