董国庆
2026-04-24 3d15d8980607dbcdc03c15c2c5fed0b91dc552e6
refactor(operation-workbench): 统一路由参数传递并优化编辑状态处理

重构列表到地图页面的导航逻辑,统一通过URL query参数传递上下文信息,替代原有的store状态传递方式。优化场站编辑面板的保存后关闭逻辑,提取为独立函数。修复编辑模式下地图实体渲染和焦点管理的问题,确保编辑意图正确应用。
3个文件已修改
264 ■■■■■ 已修改文件
src/views/businessOperations/operationWorkbench/components/StationPanel.vue 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/businessOperations/operationWorkbench/list.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/businessOperations/operationWorkbench/map.vue 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/businessOperations/operationWorkbench/components/StationPanel.vue
@@ -649,10 +649,7 @@
      </div>
      <div class="drawer-footer">
        <NButton secondary class="footer-btn" @click="emit('cancel-edit')">
          取消
        </NButton>
        <NButton type="primary" class="footer-btn" @click="emit('edit-current')">
        <NButton type="primary" class="w-full" @click="emit('edit-current')">
          编辑
        </NButton>
      </div>
src/views/businessOperations/operationWorkbench/list.vue
@@ -681,20 +681,28 @@
    message.warning(stationCreateDisabledReason.value)
    return
  }
  workbenchStore.setContext({
  const context = {
    tab: activeTab.value,
    type: 'create',
    type: 'create' as const,
    cityCode: resolveWorkbenchContextCityCode(cityValue.value),
    id: '',
  }
  workbenchStore.setListContext({
    tab: context.tab,
    cityCode: context.cityCode,
  })
  router.push({
    name: 'operationWorkbenchMap',
    query: {
      tab: context.tab,
      cityCode: context.cityCode,
      type: context.type,
    },
  })
}
function handleFenceToDetail(row: any, type: 'detail' | 'edit') {
  const context = buildWorkbenchMapContext('fence', type, row)
  if (type === 'edit') {
    workbenchStore.setListContext({
      tab: context.tab,
      cityCode: context.cityCode,
@@ -707,18 +715,11 @@
        id: context.id,
        type: context.type,
      },
    })
    return
  }
  workbenchStore.setContext(context)
  router.push({
    name: 'operationWorkbenchMap',
  })
}
function handlePointToDetail(row: any, type: 'detail' | 'edit') {
  const context = buildWorkbenchMapContext('point', type, row)
  if (type === 'edit') {
    workbenchStore.setListContext({
      tab: context.tab,
      cityCode: context.cityCode,
@@ -731,18 +732,11 @@
        id: context.id,
        type: context.type,
      },
    })
    return
  }
  workbenchStore.setContext(context)
  router.push({
    name: 'operationWorkbenchMap',
  })
}
function handleStationToMap(row: any, type: 'detail' | 'edit') {
  const context = buildWorkbenchMapContext('station', type, row)
  if (type === 'edit') {
    workbenchStore.setListContext({
      tab: context.tab,
      cityCode: context.cityCode,
@@ -755,12 +749,6 @@
        id: context.id,
        type: context.type,
      },
    })
    return
  }
  workbenchStore.setContext(context)
  router.push({
    name: 'operationWorkbenchMap',
  })
}
src/views/businessOperations/operationWorkbench/map.vue
@@ -870,7 +870,7 @@
  options: OptionItem[] = cityOptions.value
): WorkbenchEntryContext {
  const routeQuery = route.query as Record<string, unknown>;
  if (hasWorkbenchEntryQuery(routeQuery))
  if (hasActiveWorkbenchEntryQuery(routeQuery))
    return resolveWorkbenchEntryContext(routeQuery, options);
  const defaultCityValue = options[0]?.value || DEFAULT_CITY_OPTIONS[0].value;
@@ -885,35 +885,37 @@
        ? cityCode
        : defaultCityValue
      : defaultCityValue,
    id: workbenchStore.context.id || undefined,
    type: workbenchStore.context.type || undefined,
    status: workbenchStore.context.status || undefined,
    id: undefined,
    type: undefined,
    status: undefined,
  };
}
function shouldConsumeWorkbenchStoreIntent(
  routeQuery: Record<string, unknown> = route.query as Record<string, unknown>
) {
  return !hasWorkbenchEntryQuery(routeQuery) &&
    !!(
      workbenchStore.context.id ||
      workbenchStore.context.type ||
      workbenchStore.context.status
    );
function buildWorkbenchEntryQueryKey(query: Record<string, unknown>) {
  if (!hasWorkbenchEntryQuery(query)) return "";
  return [
    getQueryStringValue(query.tab),
    getQueryStringValue(query.cityCode) || getQueryStringValue(query.cityId),
    getQueryStringValue(query.id) || getQueryStringValue(query.selectedId),
    getQueryStringValue(query.type) || getQueryStringValue(query.mode),
    getQueryStringValue(query.status),
  ].join("|");
}
function clearWorkbenchEntryIntentIfNeeded(
const consumedWorkbenchEntryQueryKey = ref("");
function hasActiveWorkbenchEntryQuery(
  routeQuery: Record<string, unknown> = route.query as Record<string, unknown>
) {
  if (!shouldConsumeWorkbenchStoreIntent(routeQuery)) return;
  workbenchStore.clearEntryIntent();
  return hasWorkbenchEntryQuery(routeQuery) &&
    buildWorkbenchEntryQueryKey(routeQuery) !== consumedWorkbenchEntryQueryKey.value;
}
function shouldApplyWorkbenchEditIntent(tab: WorkbenchTab, id: string) {
  const entryContext = getWorkbenchEntryContext(cityOptions.value);
  return entryContext.type === "edit" &&
    entryContext.tab === tab &&
    entryContext.id === id;
function consumeWorkbenchEntryQuery(
  routeQuery: Record<string, unknown> = route.query as Record<string, unknown>
) {
  if (!hasWorkbenchEntryQuery(routeQuery)) return;
  consumedWorkbenchEntryQueryKey.value = buildWorkbenchEntryQueryKey(routeQuery);
}
const initialEntryContext = getWorkbenchEntryContext();
@@ -3442,6 +3444,8 @@
  resetStationForm(tempDetail);
  stationEditSnapshot.value = stationEditPayloadSnapshot.value;
  renderMapEntities();
  await nextTick();
  focusSelectedEntity(true);
  startStationPolygonDraw();
}
@@ -3472,6 +3476,20 @@
  resetStationForm(detail);
  enterStationDraftByDetail(detail);
  stationEditSnapshot.value = stationEditPayloadSnapshot.value;
  renderMapEntities();
}
function closeStationDetailPanelAfterSave(nextSelectedId = "") {
  stationDetailData.value = null;
  stationCreateMode.value = false;
  stationEditMode.value = false;
  stationPanelClosed.value = true;
  selectedCreateTool.value = "";
  stationEditSnapshot.value = "";
  selectedStationPointId.value = "";
  selectedId.value = nextSelectedId;
  stationForm.value = createEmptyStationForm();
  cleanupStationEditorState();
  renderMapEntities();
}
@@ -3650,30 +3668,11 @@
      }
    }
    if (isCreatingStation) {
      stationDetailData.value = null;
      stationCreateMode.value = false;
      stationEditMode.value = false;
      stationPanelClosed.value = true;
      selectedCreateTool.value = "";
      stationEditSnapshot.value = "";
      selectedId.value = "";
      stationForm.value = createEmptyStationForm();
      cleanupStationEditorState();
      renderMapEntities();
      closeStationDetailPanelAfterSave(refreshedStation?.id || detail.id);
      window.$message?.success(saveType === 0 ? "保存草稿成功" : "添加成功");
      return;
    }
    stationDetailData.value = refreshedStation?.raw || detail;
    stationCreateMode.value = false;
    stationEditMode.value = false;
    selectedCreateTool.value = "";
    stationEditSnapshot.value = "";
    selectedId.value = refreshedStation?.id || detail.id;
    resetStationForm(refreshedStation?.raw || detail);
    cleanupStationEditorState();
    renderMapEntities();
    await nextTick();
    focusSelectedEntity(true);
    closeStationDetailPanelAfterSave(refreshedStation?.id || detail.id);
    window.$message?.success(
      saveType === 0 ? "保存草稿成功" : isCreatingStation ? "添加成功" : "编辑成功"
    );
@@ -3724,6 +3723,13 @@
  }
  if (activeTab.value === "fence" && fenceCreateMode.value) return;
  if (activeTab.value === "fence") {
    const selectedFenceDetailId = String(fenceDetailData.value?.id || "");
    if (
      selectedId.value &&
      selectedFenceDetailId &&
      selectedFenceDetailId === selectedId.value
    )
      return;
    if (selectedId.value && !list.some((item) => item.id === selectedId.value))
      selectedId.value = "";
    return;
@@ -3778,14 +3784,11 @@
      pointEditSnapshot.value = "";
      cleanupPointEditMapState();
      syncPointDetailFromSelected();
      if (
        pendingWorkbenchType.value === "edit" ||
        shouldApplyWorkbenchEditIntent("point", id)
      ) {
      if (pendingWorkbenchType.value === "edit") {
        handleEnterPointEdit();
      }
      pendingWorkbenchType.value = "";
      clearWorkbenchEntryIntentIfNeeded();
      consumeWorkbenchEntryQuery();
      return;
    }
@@ -3802,32 +3805,24 @@
      stationDetailData.value = null;
      selectedStationPointId.value = "";
      await loadFenceDetailData(id);
      if (
        pendingWorkbenchType.value === "edit" ||
        shouldApplyWorkbenchEditIntent("fence", id)
      ) {
      if (pendingWorkbenchType.value === "edit") {
        handleEnterFenceEdit();
      }
      pendingWorkbenchType.value = "";
      clearWorkbenchEntryIntentIfNeeded();
      consumeWorkbenchEntryQuery();
      await nextTick();
      focusSelectedEntity(true);
      return;
    }
    if (stationPanelClosed.value && pendingWorkbenchType.value !== "edit") return;
    fenceDetailData.value = null;
    const stationDetail = await loadStationDetailData(id);
    if (
      stationDetail &&
      (
        pendingWorkbenchType.value === "edit" ||
        shouldApplyWorkbenchEditIntent("station", id)
      )
    ) {
    if (stationDetail && pendingWorkbenchType.value === "edit") {
      applyStationEditByDetail(stationDetail);
    }
    pendingWorkbenchType.value = "";
    clearWorkbenchEntryIntentIfNeeded();
    consumeWorkbenchEntryQuery();
    await nextTick();
    focusSelectedEntity(true);
  },
@@ -3868,11 +3863,12 @@
});
watch(
  () => [route.name, route.fullPath, workbenchStore.version],
  () => {
  () => [route.name, route.fullPath],
  async () => {
    if (route.name !== "operationWorkbenchMap") return;
    const entryContext = getWorkbenchEntryContext(cityOptions.value);
    const routeQuery = route.query as Record<string, unknown>;
    const hasActiveEntryQuery = hasActiveWorkbenchEntryQuery(routeQuery);
    const cityChanged = cityValue.value !== entryContext.cityCode;
    if (activeTab.value !== entryContext.tab)
      activeTab.value = entryContext.tab;
@@ -3888,22 +3884,34 @@
    ) {
      handleWorkbenchCreateByTab(entryContext.tab);
      pendingWorkbenchType.value = "";
      clearWorkbenchEntryIntentIfNeeded(routeQuery);
      consumeWorkbenchEntryQuery(routeQuery);
    }
    else if (
      entryContext.type === "edit" &&
      hasActiveEntryQuery &&
      (entryContext.type === "edit" || entryContext.type === "detail") &&
      entryContext.id &&
      selectedId.value === entryContext.id
    ) {
      if (entryContext.tab === "station") {
        handleEnterStationEdit();
      } else if (entryContext.tab === "fence") {
        handleEnterFenceEdit();
      if (entryContext.tab === "fence") {
        const hasLoadedFenceDetail =
          String(fenceDetailData.value?.id || "") === entryContext.id;
        if (!hasLoadedFenceDetail) await loadFenceDetailData(entryContext.id);
        if (entryContext.type === "edit") handleEnterFenceEdit();
      } else if (entryContext.tab === "station") {
        const hasLoadedStationDetail =
          String(stationDetailData.value?.id || "") === entryContext.id;
        const stationDetail = hasLoadedStationDetail
          ? stationDetailData.value
          : await loadStationDetailData(entryContext.id);
        if (entryContext.type === "edit" && stationDetail)
          applyStationEditByDetail(stationDetail);
      } else if (entryContext.tab === "point") {
        handleEnterPointEdit();
        syncPointDetailFromSelected();
        if (entryContext.type === "edit") handleEnterPointEdit();
      }
      pendingWorkbenchType.value = "";
      clearWorkbenchEntryIntentIfNeeded(routeQuery);
      consumeWorkbenchEntryQuery(routeQuery);
      return;
    }
  }
);
@@ -4000,6 +4008,8 @@
}
async function handleSelectItem(id: string) {
  const currentSelectedId = String(selectedId.value || "");
  const isSameSelection = currentSelectedId === String(id || "");
  if (
    activeTab.value === "point" &&
    isPointFormMode.value &&
@@ -4038,6 +4048,14 @@
  if (activeTab.value === "fence") fencePanelClosed.value = false;
  if (activeTab.value === "station") stationPanelClosed.value = false;
  selectedId.value = id;
  if (activeTab.value === "station" && !isStationFormMode.value) {
    if (isSameSelection) {
      await loadStationDetailData(id);
    }
    await nextTick();
    focusSelectedEntity(true);
    return;
  }
  if (activeTab.value === "fence" && !isFenceFormMode.value) {
    await nextTick();
    focusSelectedEntity(true);
@@ -6414,6 +6432,26 @@
      ? (res.data as any).records
      : [];
    stationData.value = stationList.map(mapStationApiItemToListItem);
    console.log("[operationWorkbench][station:list]", {
      cityCode: cityValue.value || undefined,
      apiCount: stationList.length,
      mappedCount: stationData.value.length,
      stations: stationList.map((item: any, index: number) => {
        const mappedItem = stationData.value[index];
        return {
          id: String(item?.id || ""),
          stationName: item?.stationName || "-",
          status: item?.status,
          centerLon: item?.centerLon,
          centerLat: item?.centerLat,
          fencePoints: item?.fencePoints || "",
          fencePointCount: parseFencePoints(item?.fencePoints).length,
          polygonPathCount: Array.isArray(mappedItem?.polygonPath)
            ? mappedItem.polygonPath.length
            : 0,
        };
      }),
    });
  } catch (error) {
    console.error("加载场站失败:", error);
    stationData.value = [];
@@ -6425,6 +6463,7 @@
  if (
    activeTab.value !== "point" &&
    activeTab.value !== "fence" &&
    !stationCreateMode.value &&
    !selectedId.value &&
    pendingWorkbenchType.value !== "create"
  ) {
@@ -6495,7 +6534,13 @@
      handlePointMapMoveEnd();
    });
    map.value.on("moveend", handlePointMapMoveEnd);
    loadWorkbenchData();
    await loadWorkbenchData();
    if (isFenceFormMode.value && fenceDetailData.value) {
      enterFenceDraftByDetail(fenceDetailData.value);
      renderMapEntities();
      await nextTick();
      focusSelectedEntity(false);
    }
  } catch (error) {
    mapError.value = `地图初始化失败: ${(error as Error).message}`;
  } finally {
@@ -6683,12 +6728,43 @@
  }
  if (layerControl.value.showStation) {
    const stationRenderDiagnostics = visibleStationList.value.map((item) => {
      const polygonPathCount = Array.isArray(item.polygonPath)
        ? item.polygonPath.length
        : 0;
      const hiddenByEditMode =
        !!(
          stationEditMode.value &&
          !stationCreateMode.value &&
          selectedId.value &&
          String(item.id) === String(selectedId.value)
        );
      return {
        id: String(item.id),
        name: item.name,
        status: item.status,
        polygonPathCount,
        hiddenByEditMode,
        renderable: polygonPathCount >= 3 && !hiddenByEditMode,
      };
    });
    console.log("[operationWorkbench][station:render]", {
      activeTab: activeTab.value,
      stationCreateMode: stationCreateMode.value,
      stationEditMode: stationEditMode.value,
      selectedId: selectedId.value,
      visibleStationCount: visibleStationList.value.length,
      renderableCount: stationRenderDiagnostics.filter((item) => item.renderable).length,
      hiddenCount: stationRenderDiagnostics.filter((item) => !item.renderable).length,
      stations: stationRenderDiagnostics,
    });
    stationPolygons.value = visibleStationList.value
      .filter((item) => Array.isArray(item.polygonPath) && item.polygonPath.length >= 3)
      .filter(
        (item) =>
          !(
            isStationFormMode.value &&
            stationEditMode.value &&
            !stationCreateMode.value &&
            selectedId.value &&
            String(item.id) === String(selectedId.value)
          )
@@ -6739,6 +6815,11 @@
      map.value.setFitView([stationDraftPolygon.value], false, [80, 80, 80, 80]);
    return;
  }
  if (stationCreateMode.value && activeTab.value === "station") {
    if (stationPolygons.value.length && fitView)
      map.value.setFitView(stationPolygons.value, false, [80, 80, 80, 80]);
    return;
  }
  if (!selectedItem.value) return;
  if (selectedItem.value.type === "station" && selectedStationPointId.value) {