diff --git a/src/app.config.ts b/src/app.config.ts index ad6049d..3298b6f 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -10,6 +10,7 @@ export default { 'pages/device/config', 'pages/family/index', 'pages/family/detail', + 'pages/family/contact/add', 'pages/event/index' ], window: { diff --git a/src/pages/family/contact/add.module.scss b/src/pages/family/contact/add.module.scss new file mode 100644 index 0000000..d2e2a88 --- /dev/null +++ b/src/pages/family/contact/add.module.scss @@ -0,0 +1,115 @@ +.page { + min-height: 100vh; + background: $color-bg; + padding: 24px 24px 40px; +} + +.card, +.contactsCard { + background: $color-bg-white; + border-radius: $radius-lg; + box-shadow: $shadow-card; + padding: 8px 32px; +} + +.contactsCard { + margin-top: 24px; +} + +.formRow { + min-height: 104px; + display: flex; + align-items: center; + border-bottom: 1px solid $color-border; +} + +.contactsCard .contactItem:last-child .formRow:last-child { + border-bottom: none; +} + +.card .formRow:last-child { + border-bottom: none; +} + +.label { + width: 180px; + flex-shrink: 0; + font-size: 28px; + color: $color-text; +} + +.required { + color: $color-danger; + margin-right: 4px; +} + +.input { + flex: 1; + min-width: 0; + height: 80px; + font-size: 28px; + color: $color-text; +} + +.contactsHead { + min-height: 96px; + display: flex; + align-items: center; + justify-content: space-between; +} + +.contactsTitle { + font-size: 30px; + font-weight: 600; + color: $color-text; +} + +.contactsAdd { + font-size: 28px; + color: $color-primary-deep; +} + +.contactsTip { + display: block; + padding-bottom: 16px; + font-size: 24px; + color: $color-text-tertiary; +} + +.contactItem { + position: relative; + border-top: 1px solid $color-border; +} + +.contactDel { + position: absolute; + top: 8px; + right: -8px; + width: 64px; + height: 64px; + display: flex; + align-items: center; + justify-content: center; + z-index: 1; +} + +.contactDelText { + font-size: 36px; + color: $color-danger; +} + +.submit { + height: 96px; + margin-top: 40px; + background: $color-primary-grad; + border-radius: 48px; + display: flex; + align-items: center; + justify-content: center; +} + +.submitText { + font-size: 32px; + font-weight: 600; + color: #ffffff; +} diff --git a/src/pages/family/contact/add.tsx b/src/pages/family/contact/add.tsx new file mode 100644 index 0000000..b85e43e --- /dev/null +++ b/src/pages/family/contact/add.tsx @@ -0,0 +1,155 @@ +import { useState } from 'react' +import { useRouter } from '@tarojs/taro' +import { View, Text, Input } from '@tarojs/components' +import { Navbar } from '@/components/navbar' +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 styles from './add.module.scss' + +const emptyContact = (): EmergencyContact => ({ + id: `tmp-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`, + name: '', + phone: '', + relation: '' +}) + +export default function ContactAdd() { + const router = useRouter() + const familyId = router.params.familyId ?? '' + + const [name, setName] = useState('') + const [idNumber, setIdNumber] = useState('') + const [address, setAddress] = useState('') + const [contacts, setContacts] = useState([]) + const [submitting, setSubmitting] = useState(false) + + const patchContact = (id: string, key: keyof EmergencyContact, value: string) => { + setContacts((prev) => prev.map((c) => (c.id === id ? { ...c, [key]: value } : c))) + } + + const removeContact = (id: string) => { + setContacts((prev) => prev.filter((c) => c.id !== id)) + } + + 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('请完整填写联系人') + return + } + + setSubmitting(true) + try { + await addCared({ + familyId, + name: name.trim(), + idNumber: idNumber.trim(), + address: address.trim(), + contacts: filled + }) + showToast('添加成功') + setTimeout(() => navigateBack(), 500) + } catch (error) { + showToast(error instanceof Error ? error.message : '添加失败') + } finally { + setSubmitting(false) + } + } + + return ( + + + + + + *姓名 + setName(e.detail.value)} + /> + + + *身份证号 + setIdNumber(e.detail.value)} + /> + + + *关爱地址 + setAddress(e.detail.value)} + /> + + + + + + 紧急联系人 + {contacts.length < MAX_EMERGENCY_CONTACTS && ( + setContacts((p) => [...p, emptyContact()])}> + + 添加 + + )} + + 最多可添加 {MAX_EMERGENCY_CONTACTS} 位紧急联系人,可不填 + + {contacts.map((c) => ( + + removeContact(c.id)}> + × + + + 姓名 + patchContact(c.id, 'name', e.detail.value)} + /> + + + 电话 + patchContact(c.id, 'phone', e.detail.value)} + /> + + + 关系 + patchContact(c.id, 'relation', e.detail.value)} + /> + + + ))} + + + + {submitting ? '提交中...' : '确认添加'} + + + ) +}