@@ -1,42 +1,67 @@
< template >
< view class = "flex h-full min-w-0 flex-col overflow-hidden bg-slate-100 text-slate-900" >
< scroll-view scroll -y class = "min-h-0 flex-1" >
< view class = "box-border w-full min-w-0 space-y-3 px-3 py-3 pb-2 8" >
< view v-if = "travelers.length" class="space-y-3" >
< button v-for = "traveler in travelers" :key="traveler.id" class="m-0 flex w-full items-center rounded-2xl bg-white px-4 py-4 text-left shadow-sm" @tap="selectTraveler(traveler.id)" >
< view v-if = "selectionMode" class="mr-3 flex h-5 w-5 shrink-0 items-center justify-center rounded-full border" :class="isSelected(traveler.id) ? 'border-emerald-500 bg-emerald-500 text-white' : 'border-slate-300 bg-white text-transparent'" > ✓ < / view >
< view class = "min-w-0 flex-1" >
< view class = "flex items-center" > < text class = "text-base font-semibold" > { { traveler . name } } < / text > < text class = "ml-2 rounded bg-slate-100 px-1.5 py-0.5 text-xs text-slate-500" > { { traveler . idType } } < / text > < / view >
< text class = "mt-2 block text-sm text-slate-600" > { { maskId ( traveler . idNumber ) } } < / text >
< text v-if = "traveler.phone" class="mt-1 block text-xs text-slate-500" > {{ maskPhone ( traveler.phone ) }} < / text >
< view class = "box-border w-full min-w-0 px-4 py-4 pb-8" >
< view class = "rounded-2xl bg-white p-4 shadow-sm" >
< view class = "flex items-start gap-3" >
< view class = " flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-blue-50" >
< uni-icons type = "personadd" size = "21" color = "#2563eb" / >
< / view >
< text v-if = "!selectionMode" class="text-slate-300" > › < / text >
< / button >
< view class = "min-w-0 flex-1" >
< text class = "block text-base font-semibold text-slate-900" > 新增出行人 < / text >
< text class = "mt-1 block text-xs leading-5 text-slate-500" > 保存后 , 购买实名票时可直接选择并自动填写 。 < / text >
< / view >
< / view >
< view class = "mt-4 flex flex-col gap-3" >
< input class = "box-border h-11 w-full rounded-xl border border-slate-200 px-3 text-sm" :value = "form.name" maxlength = "20" placeholder = "姓名" @input ="setFormField('name', $event.detail.value)" / >
< view class = "box-border flex h-11 w-full items-center rounded-xl border border-slate-200 bg-white px-3" >
< text class = "mr-3 shrink-0 border-r border-slate-200 pr-3 text-sm text-slate-500" > 身份证 < / text >
< input class = "min-w-0 flex-1 text-sm" :value = "form.idNumber" maxlength = "18" placeholder = "18位身份证号码" @input ="setFormField('idNumber', $event.detail.value.toUpperCase())" / >
< / view >
< input class = "box-border h-11 w-full rounded-xl border border-slate-200 px-3 text-sm" type = "number" :value = "form.phone" maxlength = "11" placeholder = "手机号(选填)" @input ="setFormField('phone', $event.detail.value)" / >
< / view >
< text v-if = "formError" class="mt-3 block rounded-xl bg-rose-50 px-3 py-2 text-xs leading-5 text-rose-500" > {{ formError }} < / text >
< button class = "m-0 mt-4 h-11 w-full rounded-xl bg-blue-600 p-0 text-sm font-semibold leading-[44px] text-white" @tap ="saveTraveler" > 保存出行人 < / button >
< / view >
< view v-else class = "flex flex-col items-center rounded-2xl bg-white px-4 py-14 text-center " >
< view class = "mt-4 flex items-center justify-between px-1 " >
< text class = "text-sm font-semibold text-slate-900" > 已保存的出行人 < / text >
< text class = "text-xs text-slate-400" > 姓名及证件信息 < / text >
< / view >
< view v-if = "travelers.length" class="mt-2 flex flex-col gap-[12px]" >
< view v-for = "traveler in travelers" :key="traveler.id" class="box-border flex w-full items-center rounded-2xl bg-white px-4 py-4 text-left shadow-sm" @tap="selectTraveler(traveler.id)" >
< view v-if = "selectionMode" class="mr-3 flex h-5 w-5 shrink-0 items-center justify-center rounded-full border" :class="isSelected(traveler.id) ? 'border-emerald-500 bg-emerald-500 text-white' : 'border-slate-300 bg-white text-transparent'" > ✓ < / view >
< view class = "min-w-0 flex-1" >
< text class = "text-base font-semibold" > { { traveler . name } } < / text >
< view class = "mt-2 flex min-w-0 items-center" >
< text class = "shrink-0 rounded bg-slate-100 px-1.5 py-0.5 text-xs text-slate-500" > { { traveler . idType } } < / text >
< text class = "ml-2 min-w-0 truncate text-sm text-slate-600" > { { maskId ( traveler . idNumber ) } } < / text >
< / view >
< view v-if = "traveler.phone" class="mt-2 flex min-w-0 items-center" >
< uni -icons type = "phone" size = "14" color = "#64748b" / >
< text class = "ml-1 min-w-0 truncate text-xs text-slate-500" > { { maskPhone ( traveler . phone ) } } < / text >
< / view >
< / view >
< view v-if = "!selectionMode" class="ml-3 flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-slate-50" @tap.stop="emit('delete', traveler.id)" >
< uni -icons type = "trash" size = "17" color = "#94a3b8" / >
< / view >
< / view >
< / view >
< view v-else class = "mt-2 flex flex-col items-center rounded-2xl bg-white px-4 py-14 text-center" >
< text class = "text-4xl" > 🧳 < / text >
< text class = "mt-4 text-base font-semibold" > 还没有常用出行人 < / text >
< text class = "mt-2 text-sm text-slate-500" > 添加出行人后 , 可在实名制订单中快速选择 < / text >
< / view >
< view v-if = "showForm" class=" rounded-2 xl bg-white px-4 py-4" >
< view class = "flex items-center justify-between" > < text class = "text-base font-semibold" > 新增出行人 < / text > < button class = "m-0 p-0 text-sm text-slate-500" @tap ="resetForm" > 取消 < / button > < / view >
< view class = "mt-3 flex items-center border-b border-slate-100 py-3" > < text class = "w-20 text-sm" > 姓名 < / text > < input class = "min-w-0 flex-1 text-right text-sm" :value = "form.name" placeholder = "请填写真实姓名" @input ="setFormField('name', $event.detail.value)" / > < / view >
< view class = "flex items-center border-b border-slate-100 py-3" > < text class = "w-20 text-sm" > 证件类型 < / text > < view class = "flex flex-1 justify-end gap-2" > < button v-for = "type in idTypes" :key="type" class="m-0 rounded-full border px-3 py-1 text-xs" :class="form.idType === type ? 'border-emerald-500 bg-emerald-50 text-emerald-700' : 'border-slate-200 bg-white text-slate-600'" @tap="setFormField('idType', type)" > {{ type }} < / button > < / view > < / view >
< view class = "flex items-center border-b border-slate-100 py-3" > < text class = "w-20 text-sm" > 证件号码 < / text > < input class = "min-w-0 flex-1 text-right text-sm" :value = "form.idNumber" placeholder = "请填写证件号码" @input ="setFormField('idNumber', $event.detail.value)" / > < / view >
< view class = "flex items-center py-3" > < text class = "w-20 text-sm" > 手机号 < / text > < input class = "min-w-0 flex-1 text-right text-sm" type = "number" maxlength = "11" :value = "form.phone" placeholder = "选填" @input ="setFormField('phone', $event.detail.value)" / > < / view >
< text v-if = "formError" class="mt-1 block text-xs text-rose-500" > {{ formError }} < / text >
< button class = "mt-3 w-full rounded-xl bg-emerald-600 py-3 text-sm font-semibold text-white" @tap ="saveTraveler" > 保存出行人 < / button >
< view class = "mt-4 flex items-start gap-2 rounded-xl bg-blue-50 p-3 text-xs leading-5 text-blue-700" >
< uni-icons class = "mt-0.5 shrink-0" type = "info" size = "16" color = "#1d4ed8" / >
< text class = "min-w-0 flex-1" > 出行人信息仅用于实名购票 、 第三方出票和身份核验 。 < / text >
< / view >
< view class = "rounded-2xl bg-slate-200/60 px-4 py-3 text-xs leading-5 text-slate-500" > 我们会严格保护您的身份与联系方式 , 仅用于实名制预约 、 出票及出行服务 。 < / view >
< / view >
< / scroll-view >
< view class = "box-border w-full min-w-0 shrink-0 bg-white px-4 py-3" >
< button class = "m-0 w-full rounded-full bg-emerald-600 py-3 text-sm font-semibold text-white" @tap ="showForm = true" > 新增出行人 < / button >
< / view >
< / view >
< / template >
@@ -49,11 +74,9 @@ const props = defineProps({
selectionMode : { type : Boolean , default : false } ,
} )
const emit = defineEmits ( [ 'toggle' , 'save' ] )
const idTypes = [ '身份证' , '护照' ]
const showForm = ref ( false )
const emit = defineEmits ( [ 'toggle' , 'save' , 'delete' ])
const formError = ref ( '' )
const form = reactive ( { name : '' , idType : '身份证' , idNumber : '' , phone : '' } )
const form = reactive ( { name : '' , idNumber : '' , phone : '' } )
const isSelected = ( id ) => props . selectedIds . includes ( id )
const selectTraveler = ( id ) => {
@@ -74,22 +97,30 @@ const setFormField = (key, value) => {
}
const resetForm = ( ) => {
form . name = ''
form . idType = '身份证'
form . idNumber = ''
form . phone = ''
formError . value = ''
showForm . value = false
}
const saveTraveler = ( ) => {
if ( ! form . name . trim ( ) || ! form . idNumber . trim ( ) ) {
formError . value = '请填写姓名和证件号码'
return
}
if ( ! /^\d{17}[\dX]$/ . test ( form . idNumber . trim ( ) . toUpperCase ( ) ) ) {
formError . value = '请填写正确的18位身份证号码'
return
}
if ( form . phone && ! /^1[3-9]\d{9}$/ . test ( form . phone ) ) {
formError . value = '请填写正确的手机号'
return
}
emit ( 'save' , { id : ` traveler- ${ Date . now ( ) } ` , name : form . name . trim ( ) , idType : form . idType , idNumber : form . idNumber . trim ( ) , phone : form . phone } )
emit ( 'save' , {
id : ` traveler- ${ Date . now ( ) } ` ,
name : form . name . trim ( ) ,
idType : '身份证' ,
idNumber : form . idNumber . trim ( ) . toUpperCase ( ) ,
phone : form . phone ,
} )
resetForm ( )
}
< / script >