useVisitTargets.ts 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import { type Ref, ref, watch } from 'vue'
  2. import type { LocationResult } from '@/lib/location'
  3. import { getPointSignInfoApi } from '@/services/modules/task/taskVisit'
  4. import type { PointSignInfoItem } from '@/services/modules/task/taskVisit/type'
  5. import type { VisitTarget, VisitTargetType } from '../types'
  6. import { getDistanceInMeters } from '../utils/distance'
  7. const TARGET_TYPE_MAP: Record<string, VisitTargetType> = {
  8. '1': 'hospital',
  9. '2': 'company',
  10. '3': 'pharmacy',
  11. }
  12. export const useVisitTargets = (currentLocation: Ref<LocationResult | null>) => {
  13. const targets = ref<VisitTarget[]>([])
  14. const loading = ref(false)
  15. const errorMessage = ref('')
  16. const loadTargets = async () => {
  17. const location = currentLocation.value
  18. if (!location) {
  19. targets.value = []
  20. return
  21. }
  22. loading.value = true
  23. errorMessage.value = ''
  24. try {
  25. const res = await getPointSignInfoApi({
  26. latitude: location.latitude,
  27. longitude: location.longitude,
  28. })
  29. targets.value = (Array.isArray(res.data) ? res.data : [])
  30. .map((item) => normalizeTarget(item, location))
  31. .filter((item): item is VisitTarget => item !== null)
  32. .sort((left, right) => left.distanceMeters - right.distanceMeters)
  33. } catch (error) {
  34. errorMessage.value = error instanceof Error ? error.message : '获取附近拜访对象失败'
  35. } finally {
  36. loading.value = false
  37. }
  38. }
  39. watch(
  40. () => [currentLocation.value?.latitude, currentLocation.value?.longitude] as const,
  41. () => void loadTargets(),
  42. { immediate: true }
  43. )
  44. return { targets, loading, errorMessage, loadTargets }
  45. }
  46. const normalizeTarget = (
  47. item: PointSignInfoItem,
  48. currentLocation: LocationResult
  49. ): VisitTarget | null => {
  50. const type = TARGET_TYPE_MAP[String(item.signEntType)]
  51. const latitude = Number(item.latitude)
  52. const longitude = Number(item.longitude)
  53. if (!type || !Number.isFinite(latitude) || !Number.isFinite(longitude)) return null
  54. const distanceMeters = getDistanceInMeters(
  55. currentLocation.longitude,
  56. currentLocation.latitude,
  57. longitude,
  58. latitude
  59. )
  60. return {
  61. id: `${type}-${item.signEntId}`,
  62. signEntId: String(item.signEntId),
  63. signEntType: String(item.signEntType),
  64. type,
  65. name: item.signEntName || '未命名拜访地点',
  66. address: item.address || '暂无详细地址',
  67. latitude,
  68. longitude,
  69. entLatitude: item.latitude,
  70. entLongitude: item.longitude,
  71. distanceMeters,
  72. }
  73. }