| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- import { View, ScrollView, Text } from '@tarojs/components'
- import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
- import { useForm } from 'react-hook-form'
- import { zodResolver } from '@hookform/resolvers/zod'
- import { z } from 'zod'
- import { useState, useEffect } from 'react'
- import Taro from '@tarojs/taro'
- import { deliveryAddressClient, cityClient } from '@/api'
- import { InferResponseType, InferRequestType } from 'hono'
- import { Navbar } from '@/components/ui/navbar'
- import { Card } from '@/components/ui/card'
- import { Button } from '@/components/ui/button'
- import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@/components/ui/form'
- import { Input } from '@/components/ui/input'
- import { useAuth } from '@/utils/auth'
- type Address = InferResponseType<typeof deliveryAddressClient[':id']['$get'], 200>
- type CreateAddressRequest = InferRequestType<typeof deliveryAddressClient.$post>['json']
- type UpdateAddressRequest = InferRequestType<typeof deliveryAddressClient[':id']['$put']>['json']
- const addressSchema = z.object({
- name: z.string().min(1, '请输入收货人姓名'),
- phone: z.string().regex(/^1[3-9]\d{9}$/, '请输入正确的手机号'),
- province: z.number().positive('请选择省份'),
- city: z.number().positive('请选择城市'),
- district: z.number().positive('请选择区县'),
- address: z.string().min(1, '请输入详细地址'),
- isDefault: z.boolean().optional()
- })
- type AddressFormData = z.infer<typeof addressSchema>
- export default function AddressEditPage() {
- const { user } = useAuth()
- const queryClient = useQueryClient()
- const [addressId, setAddressId] = useState<number | null>(null)
- const [provinces, setProvinces] = useState<any[]>([])
- const [cities, setCities] = useState<any[]>([])
- const [districts, setDistricts] = useState<any[]>([])
- // 获取地址ID
- useEffect(() => {
- const params = Taro.getCurrentInstance().router?.params
- if (params?.id) {
- setAddressId(parseInt(params.id))
- }
- }, [])
- // 获取地址详情
- const { data: address } = useQuery({
- queryKey: ['address', addressId],
- queryFn: async () => {
- if (!addressId) return null
- const response = await deliveryAddressClient[':id'].$get({
- param: { id: addressId }
- })
- if (response.status !== 200) {
- throw new Error('获取地址失败')
- }
- return response.json()
- },
- enabled: !!addressId,
- })
- // 获取省份
- const { data: provinceData } = useQuery({
- queryKey: ['provinces'],
- queryFn: async () => {
- const response = await cityClient.$get({
- query: {
- page: 1,
- pageSize: 100,
- filters: JSON.stringify({ parentId: 0 })
- }
- })
- if (response.status !== 200) {
- throw new Error('获取省份失败')
- }
- return response.json()
- }
- })
- // 获取城市
- const fetchCities = async (provinceId: number) => {
- const response = await cityClient.$get({
- query: {
- page: 1,
- pageSize: 100,
- filters: JSON.stringify({ parentId: provinceId })
- }
- })
- if (response.status !== 200) {
- throw new Error('获取城市失败')
- }
- return response.json()
- }
- // 获取区县
- const fetchDistricts = async (cityId: number) => {
- const response = await cityClient.$get({
- query: {
- page: 1,
- pageSize: 100,
- filters: JSON.stringify({ parentId: cityId })
- }
- })
- if (response.status !== 200) {
- throw new Error('获取区县失败')
- }
- return response.json()
- }
- // 表单设置
- const form = useForm<AddressFormData>({
- resolver: zodResolver(addressSchema),
- defaultValues: {
- name: '',
- phone: '',
- province: 0,
- city: 0,
- district: 0,
- address: '',
- isDefault: false
- }
- })
- // 填充表单数据
- useEffect(() => {
- if (address) {
- form.reset({
- name: address.name,
- phone: address.phone,
- province: address.receiverProvince,
- city: address.receiverCity,
- district: address.receiverDistrict,
- address: address.address,
- isDefault: address.isDefault === 1
- })
- }
- }, [address, form])
- // 创建/更新地址
- const saveAddressMutation = useMutation({
- mutationFn: async (data: AddressFormData) => {
- const addressData: any = {
- name: data.name,
- phone: data.phone,
- receiverProvince: data.province,
- receiverCity: data.city,
- receiverDistrict: data.district,
- address: data.address,
- userId: user?.id,
- isDefault: data.isDefault ? 1 : 0
- }
- let response
- if (addressId) {
- response = await deliveryAddressClient[':id']['$put']({
- param: { id: addressId },
- json: addressData
- })
- } else {
- response = await deliveryAddressClient.$post({ json: addressData })
- }
- if (response.status !== 200 && response.status !== 201) {
- throw new Error('保存地址失败')
- }
- return response.json()
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['delivery-addresses'] })
- Taro.showToast({
- title: addressId ? '更新成功' : '添加成功',
- icon: 'success'
- })
- Taro.navigateBack()
- },
- onError: (error) => {
- Taro.showToast({
- title: error.message || '保存失败',
- icon: 'none'
- })
- }
- })
- // 处理省份变化
- const handleProvinceChange = async (provinceId: number) => {
- if (provinceId) {
- const response = await fetchCities(provinceId)
- setCities(response.data || [])
- setDistricts([])
- form.setValue('city', 0)
- form.setValue('district', 0)
- }
- }
- // 处理城市变化
- const handleCityChange = async (cityId: number) => {
- if (cityId) {
- const response = await fetchDistricts(cityId)
- setDistricts(response.data || [])
- form.setValue('district', 0)
- }
- }
- // 初始化省份
- useEffect(() => {
- if (provinceData?.data) {
- setProvinces(provinceData.data)
- }
- }, [provinceData])
- // 加载城市数据
- useEffect(() => {
- const provinceId = form.watch('province')
- if (provinceId) {
- handleProvinceChange(provinceId)
- }
- }, [form.watch('province')])
- // 加载区县数据
- useEffect(() => {
- const cityId = form.watch('city')
- if (cityId) {
- handleCityChange(cityId)
- }
- }, [form.watch('city')])
- const onSubmit = (data: AddressFormData) => {
- saveAddressMutation.mutate(data)
- }
- return (
- <View className="min-h-screen bg-gray-50">
- <Navbar
- title={addressId ? '编辑地址' : '添加地址'}
- leftIcon="i-heroicons-chevron-left-20-solid"
- onClickLeft={() => Taro.navigateBack()}
- />
-
- <ScrollView className="h-screen pt-12 pb-20">
- <View className="px-4 py-4">
- <Form {...form}>
- <View className="space-y-4">
- <Card>
- <View className="p-4 space-y-4">
- <FormField
- name="name"
- render={({ field }) => (
- <FormItem>
- <FormLabel>收货人姓名</FormLabel>
- <FormControl>
- <Input placeholder="请输入收货人姓名" {...field} />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
- <FormField
- name="phone"
- render={({ field }) => (
- <FormItem>
- <FormLabel>手机号码</FormLabel>
- <FormControl>
- <Input placeholder="请输入手机号码" {...field} />
- </FormControl>
- <FormMessage />
- </FormItem>
- )}
- />
- <FormField
- name="province"
- render={({ field }) => (
- <FormItem>
- <FormLabel>省份</FormLabel>
- <FormControl>
- <picker
- mode="selector"
- range={provinces}
- range-key="name"
- value={provin
|