董国庆
2026-05-14 7aff31e97ba8c49b9325bc80ebb281339e9d2193
feat(pointManagement): 优化点位点击逻辑,调整接口ID类型并重构数据处理

- 调整fetchPointDetail接口参数类型从number转为string,适配后端接口要求
- 提取normalizePointData工具函数统一处理点位数据映射,移除重复代码
- 重构handlePointClick为异步函数,拉取完整点位详情,添加请求ID防止过时请求
- 接口请求失败时回退使用列表本地数据作为兜底
- 同步更新测试demo页面的相关代码
4个文件已修改
309 ■■■■■ 已修改文件
src/service/api/copyText.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/service/api/point.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/businessOperations/pointManagement/index.vue 151 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/testDemo/testPointManagement/index.vue 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/service/api/copyText.ts
@@ -20,7 +20,7 @@
  return request.Post<Service.ResponseResult<any>>('/map/api/v1/testPoint/enableDisable', data)
}
export function fetchPointDetail(id: number) {
export function fetchPointDetail(id: string) {
  return request.Get<Service.ResponseResult<Entity.Point>>('/map/api/v1/testPoint/queryById', { params: { id } })
}
src/service/api/point.ts
@@ -19,7 +19,7 @@
  return request.Post<Service.ResponseResult<any>>('/map/api/v1/point/enableDisable', data)
}
export function fetchPointDetail(id: number) {
export function fetchPointDetail(id: string) {
  return request.Get<Service.ResponseResult<Entity.Point>>('/map/api/v1/point/queryById', { params: { id } })
}
src/views/businessOperations/pointManagement/index.vue
@@ -2,7 +2,7 @@
import { computed, nextTick, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'
import { useScriptTag } from '@vueuse/core'
import { useRoute } from 'vue-router'
import { createPoint, deletePoint, enableDisablePoint, fetchElectronicFenceAreaList, fetchPointList, updatePoint } from '@/service/api/point'
import { createPoint, deletePoint, enableDisablePoint, fetchElectronicFenceAreaList, fetchPointDetail, fetchPointList, updatePoint } from '@/service/api/point'
import PointStatusSteps from '@/components/PointStatusSteps/custom.vue'
import ConfirmDialog from '@/components/ConfirmDialog/index.vue'
import { debounce } from 'radash'
@@ -138,6 +138,7 @@
const pointList = ref<any[]>([])
const allPoints = ref<any[]>([])
let pointDetailRequestId = 0
async function initMap() {
  try {
@@ -314,35 +315,45 @@
  startAddFromAmap(point)
}
// 点击点位
function handlePointClick(point: any) {
  console.log('point', point)
  isCollapsed.value = false
  activePointId.value = point.id
  editPointSnapshot.value = null
  currentPoint.value = JSON.parse(JSON.stringify(point)) // 深拷贝,避免直接修改列表数据
  pointDetailMode.value = 'view'
  isStatusModified.value = false
  if (point.source === 'amap') {
    operationTimeType.value = 'sync'
    customTimeRanges.value = [{ id: Date.now(), startTime: null, endTime: null }]
    selectedEffectivePeriod.value = 1
    uploadedImages.value = []
    return
function normalizePointData(point: any) {
  return {
    ...point,
    id: point.id,
    pointNumber: point.pointNumber,
    name: point.pointName || point.name || '',
    address: point.pointAddress || point.address || '',
    status: point.status || getPointStatusText(point.operationStatus, point.verificationStatus),
    verificationStatus: point.verificationStatus,
    operationStatus: point.operationStatus,
    lon: point.pointLon ?? point.lon,
    lat: point.pointLat ?? point.lat,
    remark: point.remarks ?? point.remark ?? '',
    limitTime: point.parkingTimeLimit ?? point.limitTime ?? '',
    operationType: point.operationType,
    effectivePeriod: point.effectivePeriod,
    effectiveTimePeriod: point.effectiveTimePeriod,
    pointPictures: point.pointPictures,
    updateBy: point.updateBy,
    updateTime: point.updateTime,
    source: point.source || 'api',
  }
}
  if (map.value && point.pointLon && point.pointLat) {
    map.value.setCenter([Number(point.pointLon), Number(point.pointLat)])
function applyPointDetail(point: any) {
  const normalizedPoint = normalizePointData(point)
  currentPoint.value = JSON.parse(JSON.stringify(normalizedPoint))
  if (map.value && normalizedPoint.lon && normalizedPoint.lat) {
    map.value.setCenter([Number(normalizedPoint.lon), Number(normalizedPoint.lat)])
  }
  // 处理运营时间回显
  if (point.operationType === '2' || point.operationType === 2) {
  if (normalizedPoint.operationType === '2' || normalizedPoint.operationType === 2) {
    operationTimeType.value = 'custom'
    selectedEffectivePeriod.value = Number(point.effectivePeriod) || 1
    if (point.effectiveTimePeriod) {
    selectedEffectivePeriod.value = Number(normalizedPoint.effectivePeriod) || 1
    if (normalizedPoint.effectiveTimePeriod) {
      try {
        const ranges = JSON.parse(point.effectiveTimePeriod)
        const ranges = JSON.parse(normalizedPoint.effectiveTimePeriod)
        if (Array.isArray(ranges)) {
          customTimeRanges.value = ranges.map((rangeStr: string, index: number) => {
            const [start, end] = rangeStr.split('-')
@@ -357,7 +368,7 @@
      catch (e) {
        console.error('解析运营时间段失败:', e)
        // 兼容旧格式 (逗号分隔)
        const ranges = point.effectiveTimePeriod.split(',')
        const ranges = normalizedPoint.effectiveTimePeriod.split(',')
        customTimeRanges.value = ranges.map((rangeStr: string, index: number) => {
          const [start, end] = rangeStr.split('-')
          return {
@@ -377,9 +388,9 @@
  }
  // 处理图片回显
  if (point.pointPictures) {
  if (normalizedPoint.pointPictures) {
    try {
      const pictures = JSON.parse(point.pointPictures)
      const pictures = JSON.parse(normalizedPoint.pointPictures)
      if (Array.isArray(pictures)) {
        uploadedImages.value = pictures.map((img: any) => ({
          id: img.id || Date.now() + Math.random(),
@@ -396,13 +407,55 @@
  else {
    uploadedImages.value = []
  }
}
  // 回显创建人与创建时间(从列表项中获取,或需要后端返回字段支持)
  // 假设后端返回字段为 updateBy 和 updateTime
  currentPoint.value.updateBy = point.updateBy
  currentPoint.value.updateTime = point.updateTime
// 点击点位
async function handlePointClick(point: any) {
  console.log('point', point)
  isCollapsed.value = false
  activePointId.value = point.id
  editPointSnapshot.value = null
  pointDetailMode.value = 'view'
  isStatusModified.value = false
  console.log('点击点位:', point)
  if (point.source === 'amap') {
    currentPoint.value = JSON.parse(JSON.stringify(point)) // 深拷贝,避免直接修改列表数据
    operationTimeType.value = 'sync'
    customTimeRanges.value = [{ id: Date.now(), startTime: null, endTime: null }]
    selectedEffectivePeriod.value = 1
    uploadedImages.value = []
    return
  }
  const fallbackPoint = normalizePointData(point)
  const currentRequestId = ++pointDetailRequestId
  try {
    const pointId = String(point.id || '').trim()
    if (pointId) {
      const { data, isSuccess } = await fetchPointDetail(pointId)
      if (currentRequestId !== pointDetailRequestId) {
        return
      }
      if (isSuccess && data) {
        applyPointDetail(data)
        console.log('点击点位(详情接口):', data)
        return
      }
    }
  }
  catch (error) {
    if (currentRequestId !== pointDetailRequestId) {
      return
    }
    console.error('获取点位详情失败,回退列表数据:', error)
  }
  if (currentRequestId !== pointDetailRequestId) {
    return
  }
  applyPointDetail(fallbackPoint)
  console.log('点击点位(列表兜底):', fallbackPoint)
}
// 辅助函数:将 HH:mm 解析为当日的时间戳
@@ -1572,23 +1625,7 @@
      const { data, isSuccess } = await fetchPointList(buildPointListParams())
      if (isSuccess && data) {
        console.log('点位列表:', data)
        allPoints.value = data.map(point => ({
          ...point,
          id: point.id,
          pointNumber: point.pointNumber, // 显式映射 pointNumber 字段
          name: point.pointName || '',
          address: point.pointAddress || '',
          status: getPointStatusText(point.operationStatus, point.verificationStatus),
          verificationStatus: point.verificationStatus,
          operationStatus: point.operationStatus,
          lon: point.pointLon,
          lat: point.pointLat,
          remark: point.remarks || '',
          limitTime: point.parkingTimeLimit || '',
          updateBy: point.updateBy,
          updateTime: point.updateTime,
          source: 'api',
        }))
        allPoints.value = data.map(point => normalizePointData({ ...point, source: 'api' }))
        pointList.value = allPoints.value
        renderPoints(pointList.value)
      }
@@ -1602,23 +1639,7 @@
    const apiPoints: any[] = []
    if (apiResult.status === 'fulfilled' && apiResult.value.isSuccess && apiResult.value.data) {
      apiPoints.push(...apiResult.value.data.map(point => ({
        ...point,
        id: point.id,
        pointNumber: point.pointNumber, // 显式映射 pointNumber 字段
        name: point.pointName || '',
        address: point.pointAddress || '',
        status: getPointStatusText(point.operationStatus, point.verificationStatus),
        verificationStatus: point.verificationStatus,
        operationStatus: point.operationStatus,
        lon: point.pointLon,
        lat: point.pointLat,
        remark: point.remarks || '',
        limitTime: point.parkingTimeLimit || '',
        updateBy: point.updateBy,
        updateTime: point.updateTime,
        source: 'api',
      })))
      apiPoints.push(...apiResult.value.data.map(point => normalizePointData({ ...point, source: 'api' })))
    }
    const amapPoints: any[] = []
src/views/testDemo/testPointManagement/index.vue
@@ -2,7 +2,7 @@
import { computed, nextTick, onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'
import { useScriptTag } from '@vueuse/core'
import { useRoute } from 'vue-router'
import { createPoint, deletePoint, enableDisablePoint, fetchElectronicFenceAreaList, fetchPointList, updatePoint } from '@/service/api/copyText'
import { createPoint, deletePoint, enableDisablePoint, fetchElectronicFenceAreaList, fetchPointDetail, fetchPointList, updatePoint } from '@/service/api/copyText'
import PointStatusSteps from '@/components/PointStatusSteps/custom.vue'
import ConfirmDialog from '@/components/ConfirmDialog/index.vue'
import { debounce } from 'radash'
@@ -137,6 +137,7 @@
const pointList = ref<any[]>([])
const allPoints = ref<any[]>([])
let pointDetailRequestId = 0
async function initMap() {
  try {
@@ -313,35 +314,45 @@
  startAddFromAmap(point)
}
// 点击点位
function handlePointClick(point: any) {
  console.log('point', point)
  isCollapsed.value = false
  activePointId.value = point.id
  editPointSnapshot.value = null
  currentPoint.value = JSON.parse(JSON.stringify(point)) // 深拷贝,避免直接修改列表数据
  pointDetailMode.value = 'view'
  isStatusModified.value = false
  if (point.source === 'amap') {
    operationTimeType.value = 'sync'
    customTimeRanges.value = [{ id: Date.now(), startTime: null, endTime: null }]
    selectedEffectivePeriod.value = 1
    uploadedImages.value = []
    return
function normalizePointData(point: any) {
  return {
    ...point,
    id: point.id,
    pointNumber: point.pointNumber,
    name: point.pointName || point.name || '',
    address: point.pointAddress || point.address || '',
    status: point.status || getPointStatusText(point.operationStatus, point.verificationStatus),
    verificationStatus: point.verificationStatus,
    operationStatus: point.operationStatus,
    lon: point.pointLon ?? point.lon,
    lat: point.pointLat ?? point.lat,
    remark: point.remarks ?? point.remark ?? '',
    limitTime: point.parkingTimeLimit ?? point.limitTime ?? '',
    operationType: point.operationType,
    effectivePeriod: point.effectivePeriod,
    effectiveTimePeriod: point.effectiveTimePeriod,
    pointPictures: point.pointPictures,
    updateBy: point.updateBy,
    updateTime: point.updateTime,
    source: point.source || 'api',
  }
}
  if (map.value && point.pointLon && point.pointLat) {
    map.value.setCenter([Number(point.pointLon), Number(point.pointLat)])
function applyPointDetail(point: any) {
  const normalizedPoint = normalizePointData(point)
  currentPoint.value = JSON.parse(JSON.stringify(normalizedPoint))
  if (map.value && normalizedPoint.lon && normalizedPoint.lat) {
    map.value.setCenter([Number(normalizedPoint.lon), Number(normalizedPoint.lat)])
  }
  // 处理运营时间回显
  if (point.operationType === '2' || point.operationType === 2) {
  if (normalizedPoint.operationType === '2' || normalizedPoint.operationType === 2) {
    operationTimeType.value = 'custom'
    selectedEffectivePeriod.value = Number(point.effectivePeriod) || 1
    if (point.effectiveTimePeriod) {
    selectedEffectivePeriod.value = Number(normalizedPoint.effectivePeriod) || 1
    if (normalizedPoint.effectiveTimePeriod) {
      try {
        const ranges = JSON.parse(point.effectiveTimePeriod)
        const ranges = JSON.parse(normalizedPoint.effectiveTimePeriod)
        if (Array.isArray(ranges)) {
          customTimeRanges.value = ranges.map((rangeStr: string, index: number) => {
            const [start, end] = rangeStr.split('-')
@@ -355,8 +366,7 @@
      }
      catch (e) {
        console.error('解析运营时间段失败:', e)
        // 兼容旧格式 (逗号分隔)
        const ranges = point.effectiveTimePeriod.split(',')
        const ranges = normalizedPoint.effectiveTimePeriod.split(',')
        customTimeRanges.value = ranges.map((rangeStr: string, index: number) => {
          const [start, end] = rangeStr.split('-')
          return {
@@ -370,15 +380,13 @@
  }
  else {
    operationTimeType.value = 'sync'
    // 重置自定义时间
    customTimeRanges.value = [{ id: Date.now(), startTime: null, endTime: null }]
    selectedEffectivePeriod.value = 1
  }
  // 处理图片回显
  if (point.pointPictures) {
  if (normalizedPoint.pointPictures) {
    try {
      const pictures = JSON.parse(point.pointPictures)
      const pictures = JSON.parse(normalizedPoint.pointPictures)
      if (Array.isArray(pictures)) {
        uploadedImages.value = pictures.map((img: any) => ({
          id: img.id || Date.now() + Math.random(),
@@ -395,13 +403,55 @@
  else {
    uploadedImages.value = []
  }
}
  // 回显创建人与创建时间(从列表项中获取,或需要后端返回字段支持)
  // 假设后端返回字段为 updateBy 和 updateTime
  currentPoint.value.updateBy = point.updateBy
  currentPoint.value.updateTime = point.updateTime
// 点击点位
async function handlePointClick(point: any) {
  console.log('point', point)
  isCollapsed.value = false
  activePointId.value = point.id
  editPointSnapshot.value = null
  pointDetailMode.value = 'view'
  isStatusModified.value = false
  console.log('点击点位:', point)
  if (point.source === 'amap') {
    currentPoint.value = JSON.parse(JSON.stringify(point)) // 深拷贝,避免直接修改列表数据
    operationTimeType.value = 'sync'
    customTimeRanges.value = [{ id: Date.now(), startTime: null, endTime: null }]
    selectedEffectivePeriod.value = 1
    uploadedImages.value = []
    return
  }
  const fallbackPoint = normalizePointData(point)
  const currentRequestId = ++pointDetailRequestId
  try {
    const pointId = String(point.id || '').trim()
    if (pointId) {
      const { data, isSuccess } = await fetchPointDetail(pointId)
      if (currentRequestId !== pointDetailRequestId) {
        return
      }
      if (isSuccess && data) {
        applyPointDetail(data)
        console.log('点击点位(详情接口):', data)
        return
      }
    }
  }
  catch (error) {
    if (currentRequestId !== pointDetailRequestId) {
      return
    }
    console.error('获取点位详情失败,回退列表数据:', error)
  }
  if (currentRequestId !== pointDetailRequestId) {
    return
  }
  applyPointDetail(fallbackPoint)
  console.log('点击点位(列表兜底):', fallbackPoint)
}
// 辅助函数:将 HH:mm 解析为当日的时间戳
@@ -1558,23 +1608,7 @@
      const { data, isSuccess } = await fetchPointList(buildPointListParams())
      if (isSuccess && data) {
        console.log('点位列表:', data)
        allPoints.value = data.map(point => ({
          ...point,
          id: point.id,
          pointNumber: point.pointNumber, // 显式映射 pointNumber 字段
          name: point.pointName || '',
          address: point.pointAddress || '',
          status: getPointStatusText(point.operationStatus, point.verificationStatus),
          verificationStatus: point.verificationStatus,
          operationStatus: point.operationStatus,
          lon: point.pointLon,
          lat: point.pointLat,
          remark: point.remarks || '',
          limitTime: point.parkingTimeLimit || '',
          updateBy: point.updateBy,
          updateTime: point.updateTime,
          source: 'api',
        }))
        allPoints.value = data.map(point => normalizePointData({ ...point, source: 'api' }))
        pointList.value = allPoints.value
        renderPoints(pointList.value)
      }
@@ -1588,23 +1622,7 @@
    const apiPoints: any[] = []
    if (apiResult.status === 'fulfilled' && apiResult.value.isSuccess && apiResult.value.data) {
      apiPoints.push(...apiResult.value.data.map(point => ({
        ...point,
        id: point.id,
        pointNumber: point.pointNumber, // 显式映射 pointNumber 字段
        name: point.pointName || '',
        address: point.pointAddress || '',
        status: getPointStatusText(point.operationStatus, point.verificationStatus),
        verificationStatus: point.verificationStatus,
        operationStatus: point.operationStatus,
        lon: point.pointLon,
        lat: point.pointLat,
        remark: point.remarks || '',
        limitTime: point.parkingTimeLimit || '',
        updateBy: point.updateBy,
        updateTime: point.updateTime,
        source: 'api',
      })))
      apiPoints.push(...apiResult.value.data.map(point => normalizePointData({ ...point, source: 'api' })))
    }
    const amapPoints: any[] = []