| | |
| | | createPoint, |
| | | deletePoint, |
| | | fetchElectronicFenceAreaList, |
| | | fetchPointDetail, |
| | | fetchPointList, |
| | | updatePoint, |
| | | } from "@/service/api/point"; |
| | |
| | | const pointAddressQuery = ref(""); |
| | | const isSearchingPointAddress = ref(false); |
| | | const isPointAddressDropdownVisible = ref(false); |
| | | const pointDetailLoading = ref(false); |
| | | const fenceDetailLoading = ref(false); |
| | | const fenceSaving = ref(false); |
| | | const fenceEditMode = ref(false); |
| | |
| | | ); |
| | | if (activeTab.value === "station" && stationCreateMode.value) return null; |
| | | if (stationPanelClosed.value) return null; |
| | | const matchedStation = tabDataMap.value[activeTab.value].find( |
| | | (item) => item.id === selectedId.value |
| | | ); |
| | | if (matchedStation) return matchedStation; |
| | | if (String(stationDetailData.value?.id || "") === String(selectedId.value || "")) |
| | | return mapStationApiItemToListItem(stationDetailData.value); |
| | | return ( |
| | | tabDataMap.value[activeTab.value].find( |
| | | (item) => item.id === selectedId.value |
| | | ) || |
| | | currentList.value[0] || |
| | | null |
| | | ); |
| | |
| | | const workflowState = buildStationEditModeState(detail); |
| | | stationCreateMode.value = workflowState.stationCreateMode; |
| | | stationEditMode.value = workflowState.stationEditMode; |
| | | stationPanelClosed.value = false; |
| | | stationForm.value = workflowState.form; |
| | | selectedStationPointId.value = workflowState.selectedStationPointId; |
| | | enterStationDraftByDetail(detail); |
| | |
| | | } |
| | | } |
| | | if (isCreatingStation) { |
| | | workbenchStore.markListNeedRefresh(); |
| | | closeStationDetailPanelAfterSave(refreshedStation?.id || detail.id); |
| | | window.$message?.success(saveType === 0 ? "保存草稿成功" : "添加成功"); |
| | | return; |
| | | } |
| | | workbenchStore.markListNeedRefresh(); |
| | | closeStationDetailPanelAfterSave(refreshedStation?.id || detail.id); |
| | | window.$message?.success( |
| | | saveType === 0 ? "保存草稿成功" : isCreatingStation ? "添加成功" : "编辑成功" |
| | |
| | | (stationCreateMode.value || pendingWorkbenchType.value === "create") |
| | | ) |
| | | return; |
| | | const selectedStationDetailId = String(stationDetailData.value?.id || ""); |
| | | if ( |
| | | activeTab.value === "station" && |
| | | selectedId.value && |
| | | selectedStationDetailId && |
| | | selectedStationDetailId === selectedId.value |
| | | ) |
| | | return; |
| | | if (!list.length) { |
| | | selectedId.value = ""; |
| | | return; |
| | |
| | | pointCreateReady.value = false; |
| | | pointEditSnapshot.value = ""; |
| | | cleanupPointEditMapState(); |
| | | syncPointDetailFromSelected(); |
| | | await loadPointDetailData(id); |
| | | if (pendingWorkbenchType.value === "edit") { |
| | | handleEnterPointEdit(); |
| | | } |
| | |
| | | : await loadStationDetailData(entryContext.id); |
| | | if (entryContext.type === "edit" && stationDetail) |
| | | applyStationEditByDetail(stationDetail); |
| | | await nextTick(); |
| | | focusSelectedEntity(true); |
| | | } else if (entryContext.tab === "point") { |
| | | syncPointDetailFromSelected(); |
| | | if (entryContext.type === "edit") handleEnterPointEdit(); |
| | | const hasLoadedPointDetail = |
| | | String(pointDetailData.value?.id || "") === entryContext.id; |
| | | const pointDetail = hasLoadedPointDetail |
| | | ? pointDetailData.value |
| | | : await loadPointDetailData(entryContext.id); |
| | | if (entryContext.type === "edit" && pointDetail) |
| | | handleEnterPointEdit(); |
| | | } |
| | | pendingWorkbenchType.value = ""; |
| | | consumeWorkbenchEntryQuery(routeQuery); |
| | |
| | | }); |
| | | } |
| | | |
| | | function openPointSaveLeaveDialog() { |
| | | return new Promise<"save" | "discard" | "cancel">((resolve) => { |
| | | window.$dialog?.warning({ |
| | | title: "当前点位还未保存,确定离开吗?", |
| | | content: "删除点位,编辑的内容将丢失,确定离开吗?", |
| | | positiveText: "保存离开", |
| | | negativeText: "丢弃离开", |
| | | onPositiveClick: () => resolve("save"), |
| | | onNegativeClick: () => resolve("discard"), |
| | | onClose: () => resolve("cancel"), |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | async function confirmFenceOperationStrategyShortenEdit( |
| | | id: number | string, |
| | | operationStrategy: string |
| | |
| | | } |
| | | |
| | | async function confirmExitPointCreateTool() { |
| | | if (!hasUnsavedPointEdit()) return true; |
| | | const keepData = await openConfirmDialog( |
| | | "当前点位存在未保存内容,是否保留?", |
| | | "保留后将继续当前打点;不保留将删除已新建的数据并关闭。", |
| | | { |
| | | positiveText: "保留", |
| | | negativeText: "不保留", |
| | | } |
| | | ); |
| | | return !keepData; |
| | | return await confirmDiscardPointEdit(); |
| | | } |
| | | |
| | | async function confirmDiscardPointEdit() { |
| | | if (!hasUnsavedPointEdit()) return true; |
| | | if (pointCreateMode.value) { |
| | | const keepEditing = await openConfirmDialog( |
| | | "当前点位还未保存,确定离开吗?", |
| | | "删除点位,编辑的内容将丢失,确定离开吗?", |
| | | { |
| | | positiveText: "保存离开", |
| | | negativeText: "丢弃离开", |
| | | } |
| | | ); |
| | | return !keepEditing; |
| | | const action = await openPointSaveLeaveDialog(); |
| | | if (action === "save") |
| | | return await handleSavePointEdit(); |
| | | if (action === "discard") |
| | | return true; |
| | | return false; |
| | | } |
| | | return await openConfirmDialog( |
| | | "确定放弃本次修改吗?", |
| | |
| | | |
| | | async function handleDeletePointEditMarker() { |
| | | if (pointCreateMode.value) { |
| | | if (hasUnsavedPointEdit()) { |
| | | const keepEditing = await openConfirmDialog( |
| | | "当前点位还未保存,确定离开吗?", |
| | | "删除点位,编辑的内容将丢失,确定离开吗?", |
| | | { |
| | | positiveText: "继续编辑", |
| | | negativeText: "丢弃离开", |
| | | } |
| | | ); |
| | | if (keepEditing) return; |
| | | } |
| | | if (!(await confirmDiscardPointEdit())) return; |
| | | exitPointCreateMode(); |
| | | pointPanelClosed.value = true; |
| | | return; |
| | |
| | | return null; |
| | | } |
| | | |
| | | async function loadPointDetailData(id: string) { |
| | | pointDetailLoading.value = true; |
| | | pointEditMode.value = false; |
| | | pointCreateMode.value = false; |
| | | pointCreateReady.value = false; |
| | | try { |
| | | const numericId = String(id); |
| | | const res = await fetchPointDetail(numericId); |
| | | if (res.code === 200 && res.data) { |
| | | pointDetailData.value = res.data; |
| | | resetPointForm(res.data); |
| | | return res.data; |
| | | } |
| | | pointDetailData.value = null; |
| | | } catch (error) { |
| | | console.error("加载点位详情失败:", error); |
| | | const fallbackDetail = (selectedItem.value?.raw || null) as Entity.Point | null; |
| | | if (fallbackDetail) { |
| | | pointDetailData.value = fallbackDetail; |
| | | resetPointForm(fallbackDetail); |
| | | return fallbackDetail; |
| | | } |
| | | pointDetailData.value = null; |
| | | } finally { |
| | | pointDetailLoading.value = false; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | // 进入点位编辑时先重新渲染地图,再创建临时点位,避免和原始 marker 重叠。 |
| | | function handleEnterPointEdit() { |
| | | if (!pointDetailData.value) return; |
| | | async function handleEnterPointEdit() { |
| | | if (activeTab.value !== "point") return; |
| | | const targetId = String(selectedId.value || selectedItem.value?.id || ""); |
| | | if (!targetId) return; |
| | | const detail = String(pointDetailData.value?.id || "") === targetId |
| | | ? pointDetailData.value |
| | | : await loadPointDetailData(targetId); |
| | | if (!detail) return; |
| | | const workflowState = buildPointEditModeState({ |
| | | detail: pointDetailData.value, |
| | | detail, |
| | | fallbackPointPictures: selectedItem.value?.raw?.pointPictures, |
| | | defaultPointImage: DEFAULT_POINT_IMAGE, |
| | | }); |
| | |
| | | } |
| | | |
| | | async function handleSavePointEdit() { |
| | | if (!isPointFormMode.value) return; |
| | | if (!isPointFormMode.value) return false; |
| | | if (!pointForm.value.pointName.trim()) { |
| | | window.$message?.error("请输入点位名称"); |
| | | return; |
| | | return false; |
| | | } |
| | | if (!pointForm.value.pointAddress.trim()) { |
| | | window.$message?.error("请输入点位地址"); |
| | | return; |
| | | return false; |
| | | } |
| | | if (!pointForm.value.pointOnOff) { |
| | | window.$message?.error("请选择点位属性"); |
| | | return; |
| | | return false; |
| | | } |
| | | if (pointForm.value.pointLon === null || pointForm.value.pointLat === null) { |
| | | window.$message?.error("请先通过地图选点或地址搜索确定点位坐标"); |
| | | return; |
| | | return false; |
| | | } |
| | | if (pointForm.value.parkingTimeLimit) { |
| | | if (!/^\d+$/.test(pointForm.value.parkingTimeLimit)) { |
| | | window.$message?.error("限停时长需为数字"); |
| | | return; |
| | | return false; |
| | | } |
| | | if (Number(pointForm.value.parkingTimeLimit) > 60) { |
| | | window.$message?.error("限停时长最大为60分钟"); |
| | | return; |
| | | return false; |
| | | } |
| | | } |
| | | const supportOperationTime = ["可运营", "待生效", "启用中"].includes( |
| | |
| | | ); |
| | | if (supportOperationTime && !pointForm.value.parkingTimeLimit) { |
| | | window.$message?.error("请输入限停时长"); |
| | | return; |
| | | return false; |
| | | } |
| | | if ( |
| | | supportOperationTime && |
| | | pointForm.value.operationType === "2" && |
| | | !validatePointTimeRanges() |
| | | ) { |
| | | return; |
| | | return false; |
| | | } |
| | | if ( |
| | | Number( |
| | |
| | | !pointForm.value.remarks.trim() |
| | | ) { |
| | | window.$message?.error("请填写测试不通过原因"); |
| | | return; |
| | | return false; |
| | | } |
| | | if (uploadedImages.value.some((img) => img.status === "uploading")) { |
| | | window.$message?.warning("图片上传中,请等待上传完成后再保存"); |
| | | return; |
| | | return false; |
| | | } |
| | | const operationArea = resolveOperationArea( |
| | | fenceAreaData.value, |
| | |
| | | pointNumber: pointDetailData.value!.pointNumber, |
| | | }); |
| | | if (res.code === 200) { |
| | | workbenchStore.markListNeedRefresh(); |
| | | window.$message?.success("保存成功"); |
| | | const createdPointNumber = isCreatingPoint |
| | | ? String(res?.data?.pointNumber || (res as any)?.pointNumber || "") |
| | |
| | | if (createdItem) { |
| | | pointPanelClosed.value = false; |
| | | selectedId.value = createdItem.id; |
| | | syncPointDetailFromSelected(); |
| | | return; |
| | | await loadPointDetailData(String(createdItem.id)); |
| | | return true; |
| | | } |
| | | } |
| | | syncPointDetailFromSelected(); |
| | | return; |
| | | if (selectedId.value) |
| | | await loadPointDetailData(String(selectedId.value)); |
| | | return true; |
| | | } |
| | | return false; |
| | | // window.$message?.error(res.msg || "保存失败"); |
| | | } catch (error) { |
| | | console.error("保存点位失败:", error); |
| | | return false; |
| | | // window.$message?.error("保存失败"); |
| | | } finally { |
| | | pointSaving.value = false; |
| | |
| | | ? await addFence(params) |
| | | : await editFence(params); |
| | | if (res.code === 200) { |
| | | workbenchStore.markListNeedRefresh(); |
| | | window.$message?.success( |
| | | saveType === 0 |
| | | ? "保存草稿成功" |
| | |
| | | }); |
| | | map.value.on("moveend", handlePointMapMoveEnd); |
| | | await loadWorkbenchData(); |
| | | if (isPointFormMode.value && pointEditPosition.value) { |
| | | createOrUpdatePointEditMarker(pointEditPosition.value); |
| | | map.value.setCenter(pointEditPosition.value); |
| | | } |
| | | if ( |
| | | activeTab.value === "station" && |
| | | String(route.query.type || "") === "edit" && |
| | | selectedId.value |
| | | ) { |
| | | const detail = String(stationDetailData.value?.id || "") === String(selectedId.value) |
| | | ? stationDetailData.value |
| | | : await loadStationDetailData(String(selectedId.value)); |
| | | if (detail) |
| | | applyStationEditByDetail(detail); |
| | | } |
| | | if (isFenceFormMode.value && fenceDetailData.value) { |
| | | enterFenceDraftByDetail(fenceDetailData.value); |
| | | renderMapEntities(); |