index.tsx 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. import { View, ScrollView, Text } from '@tarojs/components'
  2. import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'
  3. import { useForm } from 'react-hook-form'
  4. import { zodResolver } from '@hookform/resolvers/zod'
  5. import { z } from 'zod'
  6. import { useEffect } from 'react'
  7. import Taro, { useRouter } from '@tarojs/taro'
  8. import { deliveryAddressClient } from '@/api'
  9. import { Navbar } from '@/components/ui/navbar'
  10. import { Card } from '@/components/ui/card'
  11. import { Button } from '@/components/ui/button'
  12. import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@/components/ui/form'
  13. import { Input } from '@/components/ui/input'
  14. import { Switch } from '@/components/ui/switch'
  15. import { CitySelector } from '@/components/ui/city-selector'
  16. const addressSchema = z.object({
  17. name: z.string().min(1, '请输入收货人姓名'),
  18. phone: z.string().regex(/^1[3-9]\d{9}$/, '请输入正确的手机号'),
  19. province: z.number().min(1, '请选择省份'),
  20. city: z.number().min(1, '请选择城市'),
  21. district: z.number().min(1, '请选择区县'),
  22. town: z.number().min(1).optional(),
  23. address: z.string().min(1, '请输入详细地址'),
  24. isDefault: z.boolean().optional()
  25. })
  26. type AddressFormData = z.infer<typeof addressSchema>
  27. export default function AddressEditPage() {
  28. const queryClient = useQueryClient()
  29. // 使用useRouter钩子获取路由参数
  30. const router = useRouter()
  31. const params = router.params
  32. const addressId = params?.id ? parseInt(params.id) : null
  33. // 获取地址详情
  34. const { data: address } = useQuery({
  35. queryKey: ['address', addressId],
  36. queryFn: async () => {
  37. if (!addressId) return null
  38. const response = await deliveryAddressClient[':id'].$get({
  39. param: { id: addressId }
  40. })
  41. if (response.status !== 200) {
  42. throw new Error('获取地址失败')
  43. }
  44. return response.json()
  45. },
  46. enabled: !!addressId,
  47. })
  48. // 表单设置
  49. const form = useForm<AddressFormData>({
  50. resolver: zodResolver(addressSchema),
  51. defaultValues: {
  52. name: '',
  53. phone: '',
  54. province: undefined, // 设为undefined,让CitySelector自动选择第一个省份
  55. city: undefined, // 设为undefined,让CitySelector自动选择第一个城市
  56. district: undefined, // 设为undefined,让CitySelector自动选择第一个区县
  57. town: undefined, // 设为undefined,让CitySelector自动选择第一个乡镇
  58. address: '',
  59. isDefault: false
  60. }
  61. })
  62. // 填充表单数据
  63. useEffect(() => {
  64. if (address) {
  65. form.reset({
  66. name: address.name,
  67. phone: address.phone,
  68. province: address.receiverProvince || undefined,
  69. city: address.receiverCity || undefined,
  70. district: address.receiverDistrict || undefined,
  71. town: address.receiverTown || undefined,
  72. address: address.address,
  73. isDefault: address.isDefault === 1
  74. })
  75. }
  76. }, [address, form])
  77. // 创建/更新地址
  78. const saveAddressMutation = useMutation({
  79. mutationFn: async (data: AddressFormData) => {
  80. const addressData: any = {
  81. name: data.name,
  82. phone: data.phone,
  83. receiverProvince: data.province,
  84. receiverCity: data.city,
  85. receiverDistrict: data.district,
  86. receiverTown: data.town || 0,
  87. address: data.address,
  88. isDefault: data.isDefault ? 1 : 0
  89. }
  90. let response
  91. //console.log("addressId:",addressId)
  92. //console.log("addressData:",addressData)
  93. if (addressId) {
  94. response = await deliveryAddressClient[':id'].$put({
  95. param: { id: addressId },
  96. json: addressData
  97. })
  98. //console.log("response:",response)
  99. return response.json()
  100. } else {
  101. response = await deliveryAddressClient.$post({ json: addressData })
  102. }
  103. if (response.status !== 200 && response.status !== 201) {
  104. throw new Error('保存地址失败')
  105. }
  106. return response.json()
  107. },
  108. onSuccess: () => {
  109. queryClient.invalidateQueries({ queryKey: ['delivery-addresses'] })
  110. Taro.showToast({
  111. title: addressId ? '更新成功' : '添加成功',
  112. icon: 'success'
  113. })
  114. Taro.navigateBack()
  115. },
  116. onError: (error) => {
  117. Taro.showToast({
  118. title: error.message || '保存失败',
  119. icon: 'none'
  120. })
  121. }
  122. })
  123. const onSubmit = (data: AddressFormData) => {
  124. console.debug('表单提交数据:', data)
  125. console.debug('表单验证状态:', form.formState.isValid)
  126. console.debug('表单错误:', form.formState.errors)
  127. saveAddressMutation.mutate(data)
  128. }
  129. return (
  130. <View className="min-h-screen bg-gray-50">
  131. <Navbar
  132. title={addressId ? '编辑地址' : '添加地址'}
  133. leftIcon="i-heroicons-chevron-left-20-solid"
  134. onClickLeft={() => Taro.navigateBack()}
  135. />
  136. <ScrollView className="h-screen pt-12 pb-20">
  137. <View className="px-4 py-4">
  138. <Form {...form}>
  139. <View className="space-y-4">
  140. <Card>
  141. <View className="p-4 space-y-4">
  142. <FormField
  143. name="name"
  144. render={({ field }) => (
  145. <FormItem>
  146. <FormLabel>收货人姓名</FormLabel>
  147. <FormControl>
  148. <Input placeholder="请输入收货人姓名" {...field} />
  149. </FormControl>
  150. <FormMessage />
  151. </FormItem>
  152. )}
  153. />
  154. <FormField
  155. name="phone"
  156. render={({ field }) => (
  157. <FormItem>
  158. <FormLabel>手机号码</FormLabel>
  159. <FormControl>
  160. <Input placeholder="请输入手机号码" {...field} />
  161. </FormControl>
  162. <FormMessage />
  163. </FormItem>
  164. )}
  165. />
  166. <View className="mb-4" style={{ display: 'none' }}>
  167. <Text className="text-sm font-medium text-gray-700 mb-2">所在地区</Text>
  168. <CitySelector
  169. provinceValue={form.watch('province')}
  170. cityValue={form.watch('city')}
  171. districtValue={form.watch('district')}
  172. townValue={form.watch('town')}
  173. onProvinceChange={(value) => value !== undefined && form.setValue('province', value)}
  174. onCityChange={(value) => value !== undefined && form.setValue('city', value)}
  175. onDistrictChange={(value) => value !== undefined && form.setValue('district', value)}
  176. onTownChange={(value) => value !== undefined && form.setValue('town', value)}
  177. showLabels={false}
  178. />
  179. </View>
  180. <FormField
  181. name="address"
  182. render={({ field }) => (
  183. <FormItem>
  184. <FormLabel>详细地址</FormLabel>
  185. <FormControl>
  186. <Input
  187. placeholder="请输入详细地址,如街道、门牌号等"
  188. {...field}
  189. />
  190. </FormControl>
  191. <FormMessage />
  192. </FormItem>
  193. )}
  194. />
  195. <FormField
  196. name="isDefault"
  197. render={({ field }) => (
  198. <FormItem>
  199. <View className="flex items-center justify-between">
  200. <FormLabel>设为默认地址</FormLabel>
  201. <FormControl>
  202. <Switch
  203. checked={field.value}
  204. onChange={field.onChange}
  205. color="#1976D2"
  206. />
  207. </FormControl>
  208. </View>
  209. </FormItem>
  210. )}
  211. />
  212. </View>
  213. </Card>
  214. <Button
  215. className="w-full"
  216. onClick={() => form.handleSubmit(onSubmit, (errors) => console.debug('表单验证错误:', errors))()}
  217. disabled={saveAddressMutation.isPending}
  218. >
  219. {saveAddressMutation.isPending ? '保存中...' : '保存地址'}
  220. </Button>
  221. </View>
  222. </Form>
  223. </View>
  224. </ScrollView>
  225. </View>
  226. )
  227. }