| src/service/api/testOperationWorkbench.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/businessOperations/operationWorkbench/map.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/businessOperations/operationWorkbench/workbench.payload.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/testDemo/operationWorkbench/map.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/views/testDemo/operationWorkbench/workbench.payload.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/service/api/testOperationWorkbench.ts
@@ -84,7 +84,7 @@ type: number name: string ids: number | string }>>>('/map/api/v1/electronicFence/findListFenceAndStationDemo', { params }) }>>>('/map/api/v1/electronicFence/findListFenceAndStation', { params }) } export function exportPointExcel(data: any) { src/views/businessOperations/operationWorkbench/map.vue
@@ -3475,6 +3475,21 @@ resolveStationOperationFenceId(stationOperationArea.value), ) // 场站当前若匹配不到运营区,保存时优先沿用详情接口里原有的围栏归属字段, // 避免仅因地图默认隐藏停用围栏,就把 electronicAreaId / electronicId 意外清空。 function getStationOperationAreaFieldFallback() { const source = stationDetailData.value || selectedItem.value?.raw || null return { electronicAreaId: source?.electronicAreaId ?? source?.raw?.electronicAreaId ?? null, electronicId: source?.electronicId ?? source?.raw?.electronicId ?? resolveStationOperationFenceId(source) ?? null, } } async function ensureStationOperationLifecycleFallback() { if (activeTab.value !== 'station') { stationOperationLifecycleFallback.value = null @@ -4092,6 +4107,7 @@ : undefined const currentSelectedStation = selectedItem.value const operationArea = resolveStationOperationAreaByPolygon(polygonPath) const operationAreaFieldFallback = getStationOperationAreaFieldFallback() const stationArea = Number(calcFenceArea(polygonPath).toFixed(2)) const detail = { id: @@ -4121,6 +4137,8 @@ areaStatus, pointStop, operationArea, fallbackElectronicAreaId: operationAreaFieldFallback.electronicAreaId, fallbackElectronicId: operationAreaFieldFallback.electronicId, polygonPath, operationType: stationForm.value.operationType, parkingTimeLimit: stationForm.value.parkingTimeLimit, @@ -4202,9 +4220,18 @@ watch( [isStationEditWorkflow, stationOperationArea, () => stationForm.value.areaStatus], ([editing, operationArea, areaStatus]) => { ([editing, operationArea, areaStatus], previousValue) => { if (!editing || operationArea || Number(areaStatus) !== 1) return const [previousEditing, , previousAreaStatus] = Array.isArray(previousValue) ? previousValue : [false, null, undefined] // 仅在用户主动把开关切到“启用”时提示原因;如果是进入编辑态或几何联动回退,则静默兜底。 if (previousEditing && Number(previousAreaStatus) !== 1) { window.$message?.warning( '当前场站所属运营围栏已停用或不可用,无法匹配运营区域,不允许启用', ) } stationForm.value.areaStatus = 2 }, ) src/views/businessOperations/operationWorkbench/workbench.payload.ts
@@ -302,6 +302,8 @@ areaStatus: number; pointStop?: boolean; operationArea: any; fallbackElectronicAreaId?: number | string | null; fallbackElectronicId?: number | string | null; polygonPath: LngLatTuple[]; operationType: "1" | "2"; parkingTimeLimit: string; @@ -320,6 +322,8 @@ areaStatus, pointStop, operationArea, fallbackElectronicAreaId, fallbackElectronicId, polygonPath, operationType, parkingTimeLimit, @@ -337,7 +341,15 @@ ); // 场站保存状态码。 const statusCode = getStationStatusCode(saveType, areaStatus); const shouldClearOperationArea = !isCreatingStation && !operationArea; const resolvedElectronicAreaId = operationArea?.id ?? fallbackElectronicAreaId ?? null; const resolvedElectronicId = operationArea?.electronicId ?? fallbackElectronicId ?? null; const shouldClearOperationArea = !isCreatingStation && !operationArea && resolvedElectronicAreaId === null && resolvedElectronicId === null; return omitUndefinedFields({ ...(isCreatingStation ? {} : { id: Number(detailId) }), @@ -346,15 +358,14 @@ effectivePeriod: 1, effectiveTimePeriod: effectiveTimePeriod || undefined, electronicAreaId: operationArea?.id !== undefined && operationArea?.id !== null ? Number(operationArea.id) resolvedElectronicAreaId !== undefined && resolvedElectronicAreaId !== null ? Number(resolvedElectronicAreaId) : shouldClearOperationArea ? null : undefined, electronicId: operationArea?.electronicId !== undefined && operationArea?.electronicId !== null ? Number(operationArea.electronicId) resolvedElectronicId !== undefined && resolvedElectronicId !== null ? Number(resolvedElectronicId) : shouldClearOperationArea ? null : undefined, src/views/testDemo/operationWorkbench/map.vue
@@ -1844,9 +1844,20 @@ return '请输入场站名称' if (stationDraftPoints.value.length < 3) return '请先在运营区内绘制场站' const geometryError = getStationGeometryInvalidReason(stationDraftPoints.value) const geometryError = getStationGeometryInvalidReason(stationDraftPoints.value, { allowOutsideOperationArea: isStationEditWorkflow.value, }) if (geometryError) return geometryError // 编辑已有场站时允许它暂时落在围栏外,方便修复历史数据或承接围栏变更后的残留场站; // 但只要当前没有匹配到任何运营区,就不能把状态切回“启用”。 if ( isStationEditWorkflow.value && !resolveStationOperationAreaByPolygon(stationDraftPoints.value) && Number(stationForm.value.areaStatus || 1) === 1 ) { return '当前场站不在围栏区域内,不允许启用' } if (!stationForm.value.parkingTimeLimit) return '请输入限停时长' return getStationCustomTimeErrorMessage() @@ -2042,6 +2053,18 @@ .filter(item => item.points.length >= 3) } // 根据整个场站 polygon 反查所属运营区。 // 这里不使用中心点命中,而是要求“场站整体完全落在某个运营区内”, // 以便和保存校验、围栏解绑逻辑保持一致。 function resolveStationOperationAreaByPolygon(points: LngLatTuple[]) { if (points.length < 3) return null return ( getStationOperationAreas().find(area => isRingInRing(points, area.points)) || null ) } function getStationRestrictedAreas() { return fenceAreaData.value .filter((item: any) => Number(item.areaType) === 2) @@ -2071,16 +2094,18 @@ .filter(item => item.points.length >= 3) } function getStationGeometryInvalidReason(points: LngLatTuple[]) { function getStationGeometryInvalidReason( points: LngLatTuple[], options: { allowOutsideOperationArea?: boolean } = {}, ) { if (points.length < 3) return '请绘制至少3个点的场站' if (isFencePolygonSelfIntersect(points)) return '场站区域不允许自相交' const operationAreas = getStationOperationAreas() const isInsideOperationArea = operationAreas.some(area => isRingInRing(points, area.points), ) if (!isInsideOperationArea) const matchedOperationArea = resolveStationOperationAreaByPolygon(points) if (!matchedOperationArea && !options.allowOutsideOperationArea) return '场站需完全处于运营区内' const otherStations = getOtherStations() const geometryUtil = (window as any).AMap?.GeometryUtil @@ -3483,9 +3508,55 @@ const stationLifecycleCache = ref<Record<string, Record<string, any> | null>>({}) const stationOperationLifecycleFallback = ref<Record<string, any> | null>(null) const stationOperationArea = computed(() => resolveStationOperationArea()) function resolveStationOperationFenceId(source?: Record<string, any> | null) { if (!source) return '' const fenceId = source.electronicId ?? source.electronicFenceId ?? source.fenceId ?? source.raw?.electronicId ?? source.raw?.electronicFenceId ?? source.raw?.fenceId return fenceId !== undefined && fenceId !== null ? String(fenceId) : '' } // testDemo 场站启用限制需要直接读取所属围栏状态, // 避免只在保存时才因为“找不到运营区”间接报错,导致交互反馈滞后。 function isStationParentFenceDisabled(source?: Record<string, any> | null) { const fenceId = resolveStationOperationFenceId(source) if (!fenceId) return false const matchedFence = fenceData.value.find( item => String(item.id || '') === fenceId, ) if (!matchedFence) return false const rawStatus = matchedFence.raw?.status if (rawStatus !== undefined && rawStatus !== null) return Number(rawStatus) === 3 return String(matchedFence.status || '').trim() === '已停用' } const stationOperationFenceId = computed(() => String(stationOperationArea.value?.electronicId || ''), resolveStationOperationFenceId(stationOperationArea.value), ) // 场站当前若匹配不到运营区,保存时优先沿用详情接口里原有的围栏归属字段, // 避免仅因地图默认隐藏停用围栏,就把 electronicAreaId / electronicId 意外清空。 function getStationOperationAreaFieldFallback() { const source = stationDetailData.value || selectedItem.value?.raw || null return { electronicAreaId: source?.electronicAreaId ?? source?.raw?.electronicAreaId ?? null, electronicId: source?.electronicId ?? source?.raw?.electronicId ?? resolveStationOperationFenceId(source) ?? null, } } async function ensureStationOperationLifecycleFallback() { if (activeTab.value !== 'station') { @@ -3995,14 +4066,8 @@ ? Number(polygonCenter?.[1]) : undefined const currentSelectedStation = selectedItem.value const operationArea = polygonCenter && fenceAreaData.value.length ? resolveOperationArea( fenceAreaData.value, Number(polygonCenter[0]), Number(polygonCenter[1]), ) : null const operationArea = resolveStationOperationAreaByPolygon(polygonPath) const operationAreaFieldFallback = getStationOperationAreaFieldFallback() const stationArea = Number(calcFenceArea(polygonPath).toFixed(2)) const detail = { id: @@ -4031,6 +4096,8 @@ saveType, areaStatus, operationArea, fallbackElectronicAreaId: operationAreaFieldFallback.electronicAreaId, fallbackElectronicId: operationAreaFieldFallback.electronicId, polygonPath, operationType: stationForm.value.operationType, parkingTimeLimit: stationForm.value.parkingTimeLimit, @@ -4367,6 +4434,33 @@ ) watch( [isStationEditWorkflow, stationOperationArea, () => stationForm.value.areaStatus], ([editing, operationArea, areaStatus], previousValue) => { if (!editing || Number(areaStatus) !== 1) return const [previousEditing, , previousAreaStatus] = Array.isArray(previousValue) ? previousValue : [false, null, undefined] const enableTriggeredByUser = previousEditing && Number(previousAreaStatus) !== 1 const parentFenceDisabled = isStationParentFenceDisabled( stationDetailData.value || selectedItem.value?.raw || null, ) if (!parentFenceDisabled && operationArea) return // 仅在用户主动把开关切到“启用”时提示原因;如果是进入编辑态或几何联动回退,则静默兜底。 if (enableTriggeredByUser) { window.$message?.warning( parentFenceDisabled ? '当前场站所属围栏已停用,不允许启用' : '当前场站所属运营围栏已停用或不可用,无法匹配运营区域,不允许启用', ) } stationForm.value.areaStatus = 2 }, ) watch( () => [route.name, route.fullPath], async () => { if (route.name !== 'testDemoOperationWorkbenchMap') src/views/testDemo/operationWorkbench/workbench.payload.ts
@@ -293,6 +293,8 @@ saveType: 0 | 1; areaStatus: number; operationArea: any; fallbackElectronicAreaId?: number | string | null; fallbackElectronicId?: number | string | null; polygonPath: LngLatTuple[]; operationType: "1" | "2"; parkingTimeLimit: string; @@ -310,6 +312,8 @@ saveType, areaStatus, operationArea, fallbackElectronicAreaId, fallbackElectronicId, polygonPath, operationType, parkingTimeLimit, @@ -327,6 +331,10 @@ ); // 场站保存状态码。 const statusCode = getStationStatusCode(saveType, areaStatus); const resolvedElectronicAreaId = operationArea?.id ?? fallbackElectronicAreaId ?? null; const resolvedElectronicId = operationArea?.electronicId ?? fallbackElectronicId ?? null; return omitUndefinedFields({ ...(isCreatingStation ? {} : { id: Number(detailId) }), @@ -335,13 +343,12 @@ effectivePeriod: 1, effectiveTimePeriod: effectiveTimePeriod || undefined, electronicAreaId: operationArea?.id !== undefined && operationArea?.id !== null ? Number(operationArea.id) resolvedElectronicAreaId !== undefined && resolvedElectronicAreaId !== null ? Number(resolvedElectronicAreaId) : undefined, electronicId: operationArea?.electronicId !== undefined && operationArea?.electronicId !== null ? Number(operationArea.electronicId) resolvedElectronicId !== undefined && resolvedElectronicId !== null ? Number(resolvedElectronicId) : undefined, fencePoints: stringifyFencePoints(polygonPath) || undefined, operationType: Number(operationType || 1),