feat(family): 添加关爱对象表单页——必填校验、紧急联系人动态增删
This commit is contained in:
parent
a9dfb2485b
commit
9d1ea0abbc
|
|
@ -10,6 +10,7 @@ export default {
|
||||||
'pages/device/config',
|
'pages/device/config',
|
||||||
'pages/family/index',
|
'pages/family/index',
|
||||||
'pages/family/detail',
|
'pages/family/detail',
|
||||||
|
'pages/family/contact/add',
|
||||||
'pages/event/index'
|
'pages/event/index'
|
||||||
],
|
],
|
||||||
window: {
|
window: {
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
@ -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<EmergencyContact[]>([])
|
||||||
|
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 (
|
||||||
|
<View className={styles.page}>
|
||||||
|
<Navbar title="添加关爱对象" />
|
||||||
|
|
||||||
|
<View className={styles.card}>
|
||||||
|
<View className={styles.formRow}>
|
||||||
|
<Text className={styles.label}><Text className={styles.required}>*</Text>姓名</Text>
|
||||||
|
<Input
|
||||||
|
className={styles.input}
|
||||||
|
placeholder="请输入最多 10 个字"
|
||||||
|
maxLength={MAX_FAMILY_NAME_LEN}
|
||||||
|
value={name}
|
||||||
|
onInput={(e) => setName(e.detail.value)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View className={styles.formRow}>
|
||||||
|
<Text className={styles.label}><Text className={styles.required}>*</Text>身份证号</Text>
|
||||||
|
<Input
|
||||||
|
className={styles.input}
|
||||||
|
placeholder="请输入身份证号"
|
||||||
|
value={idNumber}
|
||||||
|
onInput={(e) => setIdNumber(e.detail.value)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View className={styles.formRow}>
|
||||||
|
<Text className={styles.label}><Text className={styles.required}>*</Text>关爱地址</Text>
|
||||||
|
<Input
|
||||||
|
className={styles.input}
|
||||||
|
placeholder="请输入关爱地址"
|
||||||
|
value={address}
|
||||||
|
onInput={(e) => setAddress(e.detail.value)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View className={styles.contactsCard}>
|
||||||
|
<View className={styles.contactsHead}>
|
||||||
|
<Text className={styles.contactsTitle}>紧急联系人</Text>
|
||||||
|
{contacts.length < MAX_EMERGENCY_CONTACTS && (
|
||||||
|
<Text className={styles.contactsAdd} onClick={() => setContacts((p) => [...p, emptyContact()])}>
|
||||||
|
+ 添加
|
||||||
|
</Text>
|
||||||
|
)}
|
||||||
|
</View>
|
||||||
|
<Text className={styles.contactsTip}>最多可添加 {MAX_EMERGENCY_CONTACTS} 位紧急联系人,可不填</Text>
|
||||||
|
|
||||||
|
{contacts.map((c) => (
|
||||||
|
<View key={c.id} className={styles.contactItem}>
|
||||||
|
<View className={styles.contactDel} onClick={() => removeContact(c.id)}>
|
||||||
|
<Text className={styles.contactDelText}>×</Text>
|
||||||
|
</View>
|
||||||
|
<View className={styles.formRow}>
|
||||||
|
<Text className={styles.label}>姓名</Text>
|
||||||
|
<Input
|
||||||
|
className={styles.input}
|
||||||
|
placeholder="联系人姓名"
|
||||||
|
value={c.name}
|
||||||
|
onInput={(e) => patchContact(c.id, 'name', e.detail.value)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View className={styles.formRow}>
|
||||||
|
<Text className={styles.label}>电话</Text>
|
||||||
|
<Input
|
||||||
|
className={styles.input}
|
||||||
|
type="number"
|
||||||
|
placeholder="联系人电话"
|
||||||
|
value={c.phone}
|
||||||
|
onInput={(e) => patchContact(c.id, 'phone', e.detail.value)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
<View className={styles.formRow}>
|
||||||
|
<Text className={styles.label}>关系</Text>
|
||||||
|
<Input
|
||||||
|
className={styles.input}
|
||||||
|
placeholder="如:配偶、儿子"
|
||||||
|
value={c.relation}
|
||||||
|
onInput={(e) => patchContact(c.id, 'relation', e.detail.value)}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
|
||||||
|
<View className={styles.submit} onClick={submit}>
|
||||||
|
<Text className={styles.submitText}>{submitting ? '提交中...' : '确认添加'}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue