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])
+ })
+})