|
|
@@ -2,20 +2,16 @@
|
|
|
<div class="edit-map">
|
|
|
<custom-header @goback="goBack" :isGoBack="true" :name="viewOnly ? '查看区域' : '勾选地块'"></custom-header>
|
|
|
<div class="region-type-tabs">
|
|
|
- <div
|
|
|
- v-for="item in regionTypeTabs"
|
|
|
- :key="item.value"
|
|
|
- class="region-type-tab"
|
|
|
- :class="{ 'region-type-tab--active': activeRegionType === item.value }"
|
|
|
- @click="handleRegionTypeClick(item)"
|
|
|
- >
|
|
|
- {{ item.label }}
|
|
|
+ <div v-for="item in regionTypeTabs" :key="item.code" class="region-type-tab"
|
|
|
+ :class="{ 'region-type-tab--active': activeRegionType === item.code }"
|
|
|
+ @click="handleRegionTypeClick(item)">
|
|
|
+ {{ item.name }}
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="variety-tabs" v-if="varietyTabs.length > 0">
|
|
|
<div v-for="(v, index) in varietyTabs" :key="index" class="variety-tab"
|
|
|
:class="{ 'variety-tab--active': activeVariety === index }" @click="handleVarietyClick(v, index)">
|
|
|
- {{ v.regionName }}
|
|
|
+ {{ v.regionName || v.problemZoneTypeName }}
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="edit-map-content">
|
|
|
@@ -28,19 +24,16 @@
|
|
|
<div class="edit-map-footer-btn" :class="{ 'confirm-btn-box': viewOnly }">
|
|
|
<template v-if="!viewOnly">
|
|
|
<div class="btn-reset" @click="resetPolygon">重置区域</div>
|
|
|
- <div class="btn-confirm" @click="openConfirmDrawTypePopup">确认</div>
|
|
|
+ <div class="btn-confirm" @click="openConfirmDrawTypePopup">确认区域</div>
|
|
|
</template>
|
|
|
<div v-else class="btn-confirm" @click="handleEditRegion">编辑区域</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<tip-popup v-model:show="showTipPopup" type="success" text="您的农情报告已生成" text2="请查看" buttonText="点击查看"
|
|
|
- @confirm="handleTipConfirm" />
|
|
|
+ @confirm="handleTipConfirm" />
|
|
|
|
|
|
- <confirm-draw-type-popup
|
|
|
- ref="confirmDrawTypePopupRef"
|
|
|
- @confirm="handleConfirmDrawType"
|
|
|
- />
|
|
|
+ <confirm-draw-type-popup ref="confirmDrawTypePopupRef" @confirm="handleConfirmDrawType" />
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
@@ -73,8 +66,10 @@ const selectedDrawTypeMeta = ref({
|
|
|
category: "",
|
|
|
remark: "",
|
|
|
});
|
|
|
-// 每个品种(tab)对应的地块数据草稿:key 为 tab index,value 为 { geomArr, geom }
|
|
|
+// 每个品种(tab)对应的地块数据草稿:key 为 tab index,value 为 { geomArr, geom }(与当前大类 Tab 一致时同步)
|
|
|
const regionsDraftByIndex = ref({});
|
|
|
+/** 按弹窗确认的「大类 + 小类」存几何与备注,避免与地图当前选中 Tab 不一致 */
|
|
|
+const regionsDraftByKey = ref({});
|
|
|
const submitting = ref(false);
|
|
|
// 仅在首次进入页面时根据路由 varietyId 定位一次,避免后续刷新覆盖当前流程进度
|
|
|
const hasAppliedInitialVariety = ref(false);
|
|
|
@@ -84,30 +79,22 @@ const varietyTabs = ref([]);
|
|
|
const activeVariety = ref(0);
|
|
|
const regionGeom = ref(null);
|
|
|
|
|
|
-const regionTypeTabs = [
|
|
|
- { label: "品种区", value: "variety" },
|
|
|
- { label: "异常问题区", value: "abnormal" },
|
|
|
- { label: "环境问题区", value: "environment" },
|
|
|
- { label: "休眠区", value: "sleep" },
|
|
|
-];
|
|
|
-const activeRegionType = ref("variety");
|
|
|
-
|
|
|
const categoryMap = {
|
|
|
variety: [],
|
|
|
- abnormal: [{regionName: "病害"}, {regionName: "虫害"}, {regionName: "长势过快"}, {regionName: "长势过慢"}],
|
|
|
- environment: [{regionName: "渍水不畅"}, {regionName: "密不透风"}, {regionName: "高温灼伤"}, {regionName: "低温冻害"}],
|
|
|
+ abnormal: [{ regionName: "病害" }, { regionName: "虫害" }, { regionName: "长势过快" }, { regionName: "长势过慢" }],
|
|
|
+ environment: [{ regionName: "渍水不畅" }, { regionName: "密不透风" }, { regionName: "高温灼伤" }, { regionName: "低温冻害" }],
|
|
|
sleep: [],
|
|
|
};
|
|
|
|
|
|
const handleRegionTypeClick = (item) => {
|
|
|
- activeRegionType.value = item.value;
|
|
|
+ activeRegionType.value = item.code;
|
|
|
activeVariety.value = 0;
|
|
|
- if (item.value === "variety") {
|
|
|
- varietyTabs.value = farmVarietyList.value;
|
|
|
+ if (item.code === "variety") {
|
|
|
+ varietyTabs.value = regionInfo.value.regionList || [];
|
|
|
} else {
|
|
|
- varietyTabs.value = categoryMap[item.value];
|
|
|
+ varietyTabs.value = item.children;
|
|
|
}
|
|
|
- // handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
|
|
|
+ handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
|
|
|
if (drawRegionMap.kmap) {
|
|
|
applyRegionStyles();
|
|
|
}
|
|
|
@@ -192,23 +179,26 @@ const applyRegionStyles = () => {
|
|
|
vertexColor = "#E03131";
|
|
|
fillColor = [100, 0, 0, 0.5];
|
|
|
strokeColor = "#E03131";
|
|
|
- }else if (activeRegionType.value === "environment") {
|
|
|
+ } else if (activeRegionType.value === "environment") {
|
|
|
lineColor = "#FDCF7F";
|
|
|
vertexColor = "#FDCF7F";
|
|
|
fillColor = [151, 96, 0, 0.5];
|
|
|
strokeColor = "#FDCF7F";
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
lineColor = "#A6A6A6";
|
|
|
vertexColor = "#A6A6A6";
|
|
|
fillColor = [166, 166, 166, 0.25];
|
|
|
strokeColor = "#A6A6A6";
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
|
|
|
// 勾画进行中:通过 Map.drawStyleColors 影响底层 drawStyleFunc 颜色
|
|
|
KMapMap.drawStyleColors = {
|
|
|
line: lineColor,
|
|
|
vertex: vertexColor,
|
|
|
+ // 只读回显时也复用当前大类颜色(避免查看态全部变绿)
|
|
|
+ fill: fillColor,
|
|
|
+ stroke: strokeColor,
|
|
|
};
|
|
|
|
|
|
kmap.polygonStyle = createPolygonStyleFunc(fillColor, strokeColor);
|
|
|
@@ -225,6 +215,35 @@ const isValidGeom = (geom) => {
|
|
|
return true;
|
|
|
};
|
|
|
|
|
|
+// 从 tab.geomItems[{geomWkt}] 中提取 WKT 数组(兼容单块/多块)
|
|
|
+const getGeomArrFromGeomItems = (tab) => {
|
|
|
+ const items = tab?.geomItems;
|
|
|
+ if (!Array.isArray(items) || items.length === 0) return [];
|
|
|
+ return items
|
|
|
+ .map((x) => x?.geomWkt)
|
|
|
+ .filter((x) => x !== undefined && x !== null)
|
|
|
+ .map((x) => String(x).trim())
|
|
|
+ .filter((x) => isValidGeom(x));
|
|
|
+};
|
|
|
+
|
|
|
+const draftKeyFromParts = (majorType, tabLike) => {
|
|
|
+ if (!majorType || !tabLike || typeof tabLike !== "object") return "";
|
|
|
+ const t = tabLike;
|
|
|
+ const id = t.regionId ?? t.problemZoneTypeId ?? t.typeId ?? t.id;
|
|
|
+ if (id != null && String(id).trim() !== "") {
|
|
|
+ return `${majorType}:${String(id).trim()}`;
|
|
|
+ }
|
|
|
+ const nm = (t.regionName || t.problemZoneTypeName || "").toString().trim();
|
|
|
+ return nm ? `${majorType}:name:${nm}` : "";
|
|
|
+};
|
|
|
+
|
|
|
+const getDraftGeomForTab = (majorType, tab, index) => {
|
|
|
+ const k = draftKeyFromParts(majorType, tab);
|
|
|
+ const byKey = k ? regionsDraftByKey.value[k] : null;
|
|
|
+ if (byKey?.geom) return byKey.geom;
|
|
|
+ return regionsDraftByIndex.value[index]?.geom;
|
|
|
+};
|
|
|
+
|
|
|
const resolveInitialVarietyIndex = (regionList) => {
|
|
|
const queryVarietyId = route.query?.varietyId;
|
|
|
if (!queryVarietyId || !Array.isArray(regionList) || regionList.length === 0) return 0;
|
|
|
@@ -245,7 +264,7 @@ const getReadonlyVarietyRegions = (activeIndex) => {
|
|
|
if (i === activeIndex) continue;
|
|
|
const tab = varietyTabs.value[i];
|
|
|
if (!tab) continue;
|
|
|
- const draftGeom = regionsDraftByIndex.value[i]?.geom;
|
|
|
+ const draftGeom = getDraftGeomForTab(activeRegionType.value, tab, i);
|
|
|
const geometry = draftGeom || tab.geom;
|
|
|
if (!isValidGeom(geometry)) continue;
|
|
|
readonlyRegions.push({
|
|
|
@@ -263,22 +282,72 @@ const renderReadonlyVarietyRegions = (activeIndex) => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+/**
|
|
|
+ * 仅渲染「品种区」所有已有地块(只读),用于在其它问题区查看/编辑时作为底图参考。
|
|
|
+ * 需求:只显示品种区地块,其它问题区地块不显示,且不可编辑。
|
|
|
+ */
|
|
|
+const renderAllVarietyRegionsReadonlyOnly = () => {
|
|
|
+ if (!drawRegionMap || typeof drawRegionMap.setStatusRegions !== "function") return;
|
|
|
+ const list = regionInfo.value?.regionList || [];
|
|
|
+ if (!Array.isArray(list) || list.length === 0) {
|
|
|
+ drawRegionMap.setStatusRegions([]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const regions = [];
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
+ const tab = list[i];
|
|
|
+ if (!tab) continue;
|
|
|
+ const draftGeom = getDraftGeomForTab("variety", tab, i);
|
|
|
+ const geometry = draftGeom || tab.geom;
|
|
|
+ if (!isValidGeom(geometry)) continue;
|
|
|
+ regions.push({
|
|
|
+ geometry,
|
|
|
+ label: tab.regionName || "",
|
|
|
+ displayMode: "readonlyVariety",
|
|
|
+ });
|
|
|
+ }
|
|
|
+ drawRegionMap.setStatusRegions(regions);
|
|
|
+};
|
|
|
+
|
|
|
const handleVarietyClick = (tab, index) => {
|
|
|
activeVariety.value = index;
|
|
|
- const currentGeom = regionsDraftByIndex.value[index]?.geom || tab.geom;
|
|
|
- regionGeom.value = currentGeom;
|
|
|
+ // 取值优先级:
|
|
|
+ // 1) 草稿(regionsDraftByKey / regionsDraftByIndex)
|
|
|
+ // 2) 接口返回的 tab.geomItems[].geomWkt(你给的结构)
|
|
|
+ // 3) 兜底 tab.geom(兼容旧结构)
|
|
|
+ const draftGeom = getDraftGeomForTab(activeRegionType.value, tab, index);
|
|
|
+ const geomArr =
|
|
|
+ isValidGeom(draftGeom)
|
|
|
+ ? [String(draftGeom).trim()]
|
|
|
+ : (() => {
|
|
|
+ const fromItems = getGeomArrFromGeomItems(tab);
|
|
|
+ if (fromItems.length) return fromItems;
|
|
|
+ return isValidGeom(tab?.geom) ? [String(tab.geom).trim()] : [];
|
|
|
+ })();
|
|
|
+ // 保留一份“当前选中地块”的原始字符串形态给其它逻辑使用
|
|
|
+ regionGeom.value = geomArr.length > 1 ? JSON.stringify(geomArr) : geomArr[0] || "";
|
|
|
// 地图尚未初始化时,仅更新状态,不做图层绘制,避免首次进入重复叠加
|
|
|
if (!drawRegionMap.kmap) return;
|
|
|
|
|
|
- // // 每次切换/重绘地块前先清空“当前可编辑图层”
|
|
|
- // if (drawRegionMap.kmap?.polygonLayer?.source) {
|
|
|
- // drawRegionMap.kmap.polygonLayer.source.clear();
|
|
|
- // }
|
|
|
- // 渲染当前品种之前的已勾画地块(灰色只读 + 品种名)
|
|
|
- renderReadonlyVarietyRegions(index);
|
|
|
- if (isValidGeom(currentGeom)) {
|
|
|
+ // 确保当前大类颜色样式生效(非品种区:黄色/红色/灰色;品种区:绿色)
|
|
|
+ applyRegionStyles();
|
|
|
+
|
|
|
+ // 非品种区:底图显示品种区(只读绿色)+ 当前小类(按当前大类颜色渲染)
|
|
|
+ // 品种区:显示其他品种只读 + 当前品种可编辑
|
|
|
+ if (activeRegionType.value !== "variety") {
|
|
|
+ renderAllVarietyRegionsReadonlyOnly();
|
|
|
+ } else {
|
|
|
+ renderReadonlyVarietyRegions(index);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 切换时先清空当前可编辑图层,避免叠加
|
|
|
+ drawRegionMap.kmap?.polygonLayer?.source?.clear?.();
|
|
|
+ if (geomArr.length > 0) {
|
|
|
setTimeout(() => {
|
|
|
- drawRegionMap.setAreaGeometry([currentGeom], true);
|
|
|
+ // 切换小类仅负责“显示”,不主动缩放;缩放留到点击“编辑”时触发
|
|
|
+ drawRegionMap.setAreaGeometry(geomArr, false);
|
|
|
+ // 需要 fit 时,确保视野包含当前渲染的所有地块(只读层 + 当前层)
|
|
|
+ drawRegionMap.fitAllRegions?.();
|
|
|
}, 50);
|
|
|
}
|
|
|
};
|
|
|
@@ -293,7 +362,7 @@ async function fetchFarmSubjectDetail() {
|
|
|
|
|
|
const { data } = await VE_API.basic_farm.fetchFarmSubjectDetail({ subjectId });
|
|
|
|
|
|
-
|
|
|
+
|
|
|
if (data?.regionList?.length) {
|
|
|
if (!hasAppliedInitialVariety.value && route.query?.varietyId) {
|
|
|
activeVariety.value = resolveInitialVarietyIndex(data?.regionList);
|
|
|
@@ -301,12 +370,147 @@ async function fetchFarmSubjectDetail() {
|
|
|
}
|
|
|
|
|
|
point.value = data.farmLocation;
|
|
|
- farmVarietyList.value = data.regionList;
|
|
|
- varietyTabs.value = data.regionList;
|
|
|
- handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
|
|
|
+ // farmVarietyList.value = data.regionList;
|
|
|
+ // varietyTabs.value = data.regionList;
|
|
|
+ // handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+const regionTypeTabs = ref([]);
|
|
|
+const activeRegionType = ref("variety");
|
|
|
+const regionInfo = ref([]);
|
|
|
+async function fetchRegionInfo() {
|
|
|
+ const { data } = await VE_API.basic_farm.fetchRegionInfo({ subjectId: route.query.subjectId });
|
|
|
+ if (data && data.length > 0) {
|
|
|
+ regionInfo.value = data[0] || [];
|
|
|
+ regionTypeTabs.value = regionInfo.value.problemZoneList || [];
|
|
|
+ regionTypeTabs.value.unshift({ name: "品种区", code: "variety" });
|
|
|
+ if (data[0]?.regionList?.length) {
|
|
|
+ if (!hasAppliedInitialVariety.value && route.query?.varietyId) {
|
|
|
+ activeVariety.value = resolveInitialVarietyIndex(data[0]?.regionList);
|
|
|
+ hasAppliedInitialVariety.value = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ point.value = data[0].point;
|
|
|
+
|
|
|
+ varietyTabs.value = regionInfo.value.regionList || [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const resolveProblemZoneGroupKind = (g) => {
|
|
|
+ if (!g) return "";
|
|
|
+ const code = (g.code ?? "").toString().trim().toLowerCase();
|
|
|
+ const name = (g.name ?? "").toString();
|
|
|
+ if (name.includes("异常") || code === "abnormal" || code.includes("abnormal")) return "abnormal";
|
|
|
+ if (name.includes("环境") || code === "environment" || code.includes("environment")) return "environment";
|
|
|
+ if (
|
|
|
+ name.includes("休眠") ||
|
|
|
+ code === "sleep" ||
|
|
|
+ code.includes("sleep") ||
|
|
|
+ code.includes("dormant") ||
|
|
|
+ code.includes("dormancy") ||
|
|
|
+ code.includes("hibern")
|
|
|
+ ) {
|
|
|
+ return "sleep";
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+};
|
|
|
+
|
|
|
+const findProblemZoneGroupByDrawType = (majorType) => {
|
|
|
+ if (!majorType || majorType === "variety") return null;
|
|
|
+ const list = regionInfo.value?.problemZoneList || [];
|
|
|
+ return (
|
|
|
+ list.find((x) => resolveProblemZoneGroupKind(x) === majorType) ||
|
|
|
+ list.find((x) => String(x?.code) === String(majorType))
|
|
|
+ );
|
|
|
+};
|
|
|
+
|
|
|
+const getTabsForMajorType = (majorType) => {
|
|
|
+ if (majorType === "variety") {
|
|
|
+ return regionInfo.value?.regionList || [];
|
|
|
+ }
|
|
|
+ const g = findProblemZoneGroupByDrawType(majorType);
|
|
|
+ return g?.children || [];
|
|
|
+};
|
|
|
+
|
|
|
+const findTabIndexForCategory = (tabs, category) => {
|
|
|
+ if (!Array.isArray(tabs) || !category || typeof category !== "object") return -1;
|
|
|
+ const fields = ["regionId", "problemZoneTypeId", "typeId", "id"];
|
|
|
+ for (let i = 0; i < tabs.length; i++) {
|
|
|
+ const t = tabs[i];
|
|
|
+ for (const f of fields) {
|
|
|
+ const cv = category[f];
|
|
|
+ const tv = t[f];
|
|
|
+ if (cv != null && cv !== "" && tv != null && String(cv) === String(tv)) return i;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const cname = (category.regionName || category.problemZoneTypeName || "").toString().trim();
|
|
|
+ if (cname) {
|
|
|
+ const idx = tabs.findIndex((t) => {
|
|
|
+ const tn = (t.regionName || t.problemZoneTypeName || "").toString().trim();
|
|
|
+ return tn === cname;
|
|
|
+ });
|
|
|
+ if (idx >= 0) return idx;
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+};
|
|
|
+
|
|
|
+/** 仅提交本次有勾画草稿(regionsDraftByKey)的品种区,不带未勾画项 */
|
|
|
+const buildRegionListForSubmit = () => {
|
|
|
+ const list = regionInfo.value?.regionList || [];
|
|
|
+ const out = [];
|
|
|
+ list.forEach((tab) => {
|
|
|
+ const k = draftKeyFromParts("variety", tab);
|
|
|
+ const d = k ? regionsDraftByKey.value[k] : null;
|
|
|
+ const geom = d?.geom != null ? String(d.geom).trim() : "";
|
|
|
+ if (!isValidGeom(geom)) return;
|
|
|
+ out.push({
|
|
|
+ regionId: tab.regionId,
|
|
|
+ typeId: tab.typeId,
|
|
|
+ regionName: tab.regionName,
|
|
|
+ geom,
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return out;
|
|
|
+};
|
|
|
+
|
|
|
+/** 仅包含有勾画草稿的问题分区子项;无任何子项勾画的分组整组不传 */
|
|
|
+const buildProblemZoneListForSubmit = () => {
|
|
|
+ const raw = regionInfo.value?.problemZoneList || [];
|
|
|
+ const subjectId = route.query.subjectId;
|
|
|
+ const groups = [];
|
|
|
+ raw.forEach((group) => {
|
|
|
+ const canonical = resolveProblemZoneGroupKind(group);
|
|
|
+ const children = (group.children || [])
|
|
|
+ .map((child) => {
|
|
|
+ if (!canonical) return null;
|
|
|
+ const k = draftKeyFromParts(canonical, child);
|
|
|
+ const d = k ? regionsDraftByKey.value[k] : null;
|
|
|
+ const geomWkt = d?.geom != null ? String(d.geom).trim() : "";
|
|
|
+ if (!isValidGeom(geomWkt)) return null;
|
|
|
+ const remark =
|
|
|
+ d && "remark" in d && d.remark != null ? String(d.remark) : "";
|
|
|
+ return {
|
|
|
+ farmSubjectId: subjectId,
|
|
|
+ problemZoneTypeId: child.problemZoneTypeId ?? child.typeId ?? "",
|
|
|
+ problemZoneTypeName: child.problemZoneTypeName ?? child.regionName ?? "",
|
|
|
+ parentName: group.name ?? "",
|
|
|
+ parentCode: group.code ?? "",
|
|
|
+ geomItems: [{ geomWkt, remark }],
|
|
|
+ };
|
|
|
+ })
|
|
|
+ .filter(Boolean);
|
|
|
+ if (children.length === 0) return;
|
|
|
+ groups.push({
|
|
|
+ name: group.name,
|
|
|
+ code: group.code,
|
|
|
+ children,
|
|
|
+ });
|
|
|
+ });
|
|
|
+ return groups;
|
|
|
+};
|
|
|
+
|
|
|
onActivated(async () => {
|
|
|
activeVariety.value = 0;
|
|
|
hasAppliedInitialVariety.value = false;
|
|
|
@@ -318,8 +522,8 @@ onActivated(async () => {
|
|
|
|
|
|
type.value = route.query.type;
|
|
|
const editable = !viewOnly.value;
|
|
|
- await fetchFarmSubjectDetail();
|
|
|
-
|
|
|
+ // await fetchFarmSubjectDetail();
|
|
|
+ await fetchRegionInfo();
|
|
|
drawRegionMap.initMap(point.value, mapContainer.value, editable, true, true);
|
|
|
applyRegionStyles();
|
|
|
|
|
|
@@ -407,35 +611,22 @@ const resetPolygon = () => {
|
|
|
});
|
|
|
};
|
|
|
|
|
|
-const buildRegionsPayload = () => {
|
|
|
- const regions = [];
|
|
|
- varietyTabs.value.forEach((tab, index) => {
|
|
|
- const draft = regionsDraftByIndex.value[index];
|
|
|
- if (!draft?.geom) return;
|
|
|
- regions.push({
|
|
|
- regionId: tab.regionId,
|
|
|
- typeId: tab.typeId,
|
|
|
- regionName: tab.regionName,
|
|
|
- geom: draft.geom,
|
|
|
- });
|
|
|
- });
|
|
|
- return regions;
|
|
|
-};
|
|
|
-
|
|
|
const submitRegions = async () => {
|
|
|
if (submitting.value) return;
|
|
|
- const regions = buildRegionsPayload();
|
|
|
- if (regions.length === 0) {
|
|
|
+ const regionList = buildRegionListForSubmit();
|
|
|
+ const problemZoneList = buildProblemZoneListForSubmit();
|
|
|
+ if (regionList.length === 0 && problemZoneList.length === 0) {
|
|
|
ElMessage.warning("请先勾画地块后再确认");
|
|
|
- return;
|
|
|
+ return false;
|
|
|
}
|
|
|
submitting.value = true;
|
|
|
try {
|
|
|
- const res = await VE_API.basic_farm.saveBasicFarmInfoByExpertV3({
|
|
|
- id: route.query.subjectId,
|
|
|
- expertMiniUserId: '81881',
|
|
|
- regions,
|
|
|
- });
|
|
|
+ const params = {
|
|
|
+ subjectId: route.query.subjectId,
|
|
|
+ regionList,
|
|
|
+ problemZoneList,
|
|
|
+ };
|
|
|
+ const res = await VE_API.basic_farm.ediRegionZone(params);
|
|
|
if (res?.code === 0) {
|
|
|
return true;
|
|
|
}
|
|
|
@@ -449,35 +640,89 @@ const submitRegions = async () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-const confirmArea = async () => {
|
|
|
- // 先把当前品种的地块保存到草稿
|
|
|
+/** 以弹窗 confirm 传入的 drawMeta(大类 type + 小类 category + remark)为准写入草稿并提交 */
|
|
|
+const confirmArea = async (drawMeta) => {
|
|
|
+ const meta =
|
|
|
+ drawMeta && drawMeta.type != null
|
|
|
+ ? drawMeta
|
|
|
+ : selectedDrawTypeMeta.value;
|
|
|
+ if (!meta?.type || meta.category == null) {
|
|
|
+ ElMessage.warning("请先在弹窗中选择勾画类型与类别");
|
|
|
+ return;
|
|
|
+ }
|
|
|
const polygonData = drawRegionMap.getAreaGeometry?.();
|
|
|
const geometryArr = polygonData?.geometryArr;
|
|
|
if (!Array.isArray(geometryArr) || geometryArr.length === 0) {
|
|
|
ElMessage.warning("请先勾画地块后再确认");
|
|
|
return;
|
|
|
}
|
|
|
- // geom 后端一般期望 string;若勾画多个,则序列化为 JSON 数组
|
|
|
const geom = geometryArr.length === 1 ? geometryArr[0] : JSON.stringify(geometryArr);
|
|
|
- regionsDraftByIndex.value[activeVariety.value] = { geomArr: geometryArr, geom };
|
|
|
+ const key = draftKeyFromParts(meta.type, meta.category);
|
|
|
+ if (!key) {
|
|
|
+ ElMessage.warning("无法识别勾画类别,请重新选择");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ regionsDraftByKey.value[key] = {
|
|
|
+ geomArr: geometryArr,
|
|
|
+ geom,
|
|
|
+ remark: meta.remark != null ? String(meta.remark) : "",
|
|
|
+ };
|
|
|
+ const tabList = getTabsForMajorType(meta.type);
|
|
|
+ const idx = findTabIndexForCategory(tabList, meta.category);
|
|
|
+ if (activeRegionType.value === meta.type && idx >= 0) {
|
|
|
+ regionsDraftByIndex.value[idx] = { geomArr: geometryArr, geom };
|
|
|
+ }
|
|
|
|
|
|
- // 每次确认都提交接口(携带目前已确认过的所有品种 regions)
|
|
|
const ok = await submitRegions();
|
|
|
- await VE_API.basic_farm.updateLastViewTime({
|
|
|
- regionId: varietyTabs.value[activeVariety.value].regionId,
|
|
|
- });
|
|
|
- fetchFarmSubjectDetail()
|
|
|
+ const rid = meta.category?.regionId;
|
|
|
+ if (rid != null && rid !== "") {
|
|
|
+ try {
|
|
|
+ await VE_API.basic_farm.updateLastViewTime({ regionId: rid });
|
|
|
+ } catch (_) {
|
|
|
+ /* 非品种区可能无 regionId,忽略 */
|
|
|
+ }
|
|
|
+ }
|
|
|
if (!ok) return;
|
|
|
|
|
|
+ // 保存成功后:不跳走,刷新当前页并回显最新数据,并切换为查看态
|
|
|
+ try {
|
|
|
+ await fetchRegionInfo();
|
|
|
+
|
|
|
+ // 恢复当前大类下的子类 tab(fetchRegionInfo 默认会填充品种区)
|
|
|
+ if (activeRegionType.value === "variety") {
|
|
|
+ varietyTabs.value = regionInfo.value?.regionList || [];
|
|
|
+ } else {
|
|
|
+ const group = (regionTypeTabs.value || []).find(
|
|
|
+ (x) => x?.code === activeRegionType.value
|
|
|
+ );
|
|
|
+ varietyTabs.value = group?.children || [];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 更新路由为查看态,确保按钮/头部状态同步
|
|
|
+ try {
|
|
|
+ router.replace({ query: { ...route.query, type: "viewOnly" } });
|
|
|
+ } catch (_) {
|
|
|
+ // 路由更新失败不影响回显
|
|
|
+ }
|
|
|
+
|
|
|
+ // 重新初始化地图(非编辑/查看模式),确保回显形状正确
|
|
|
+ if (drawRegionMap.kmap) {
|
|
|
+ drawRegionMap.destroyMap?.();
|
|
|
+ }
|
|
|
+ drawRegionMap.initMap(point.value, mapContainer.value, false, true, false);
|
|
|
+ applyRegionStyles();
|
|
|
+ if (varietyTabs.value.length > 0 && varietyTabs.value[activeVariety.value]) {
|
|
|
+ handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
|
|
|
+ }
|
|
|
+ drawRegionMap.fitAllRegions?.();
|
|
|
+ } catch (_) {
|
|
|
+ // 刷新失败不阻断用户继续操作,保持当前页面状态
|
|
|
+ }
|
|
|
+
|
|
|
if (route.query.showTipPopup) {
|
|
|
showTipPopup.value = true;
|
|
|
return;
|
|
|
}
|
|
|
- if (route.query.targetUrl) {
|
|
|
- router.replace(route.query.targetUrl);
|
|
|
- return;
|
|
|
- }
|
|
|
- router.go(-1);
|
|
|
};
|
|
|
|
|
|
const openConfirmDrawTypePopup = () => {
|
|
|
@@ -487,22 +732,28 @@ const openConfirmDrawTypePopup = () => {
|
|
|
ElMessage.warning("请先勾画地块后再确认");
|
|
|
return;
|
|
|
}
|
|
|
- confirmDrawTypePopupRef.value.openPopup(
|
|
|
- {
|
|
|
- varietyTabs: farmVarietyList.value,
|
|
|
- activeRegionType: activeRegionType.value,
|
|
|
- activeVarietyIndex: activeVariety.value,
|
|
|
- }
|
|
|
- );
|
|
|
+ confirmDrawTypePopupRef.value.openPopup({
|
|
|
+ varietyTabs: varietyTabs.value,
|
|
|
+ regionList: regionInfo.value?.regionList ?? [],
|
|
|
+ problemZoneList: regionInfo.value?.problemZoneList ?? [],
|
|
|
+ /** 接口未返回子类时与地图页本地 categoryMap 一致,避免弹窗内切换大类无选项 */
|
|
|
+ fallbackProblemCategories: {
|
|
|
+ abnormal: categoryMap.abnormal,
|
|
|
+ environment: categoryMap.environment,
|
|
|
+ sleep: categoryMap.sleep,
|
|
|
+ },
|
|
|
+ activeRegionType: activeRegionType.value,
|
|
|
+ activeVarietyIndex: activeVariety.value,
|
|
|
+ });
|
|
|
};
|
|
|
|
|
|
const handleConfirmDrawType = async (payload) => {
|
|
|
selectedDrawTypeMeta.value = payload;
|
|
|
- await confirmArea();
|
|
|
+ await confirmArea(payload);
|
|
|
};
|
|
|
|
|
|
const handleEditRegion = () => {
|
|
|
- // 从查看态切换到可勾画编辑态:移除查看标记并重建地图(editable=true)
|
|
|
+ // 从查看态切换到可勾画编辑态:移除查看标记(所有大类共用)
|
|
|
const nextQuery = { ...route.query };
|
|
|
delete nextQuery.type;
|
|
|
delete nextQuery.viewOnly;
|
|
|
@@ -513,19 +764,65 @@ const handleEditRegion = () => {
|
|
|
drawRegionMap.destroyMap();
|
|
|
}
|
|
|
|
|
|
+ // 若当前不在品种区(如环境/异常/休眠),点击“编辑”进入当前问题区的编辑态:
|
|
|
+ // - 地图可编辑(仅编辑当前选中的问题区子项)
|
|
|
+ // - 只显示「品种区」地块作为底图参考(只读)
|
|
|
+ // - 不显示其它问题区地块
|
|
|
+ if (activeRegionType.value !== "variety") {
|
|
|
+ drawRegionMap.initMap(point.value, mapContainer.value, true, true, true);
|
|
|
+ applyRegionStyles();
|
|
|
+ // 清空当前可编辑图层,避免残留
|
|
|
+ drawRegionMap.kmap?.polygonLayer?.source?.clear?.();
|
|
|
+ renderAllVarietyRegionsReadonlyOnly();
|
|
|
+
|
|
|
+ const tab = varietyTabs.value?.[activeVariety.value];
|
|
|
+ // 进入编辑时:缩放到当前要编辑的地块
|
|
|
+ const currentGeomStr = tab
|
|
|
+ ? (getDraftGeomForTab(activeRegionType.value, tab, activeVariety.value) || tab.geom)
|
|
|
+ : "";
|
|
|
+ const currentGeomArr = isValidGeom(currentGeomStr)
|
|
|
+ ? [String(currentGeomStr).trim()]
|
|
|
+ : getGeomArrFromGeomItems(tab);
|
|
|
+ regionGeom.value =
|
|
|
+ currentGeomArr.length > 1 ? JSON.stringify(currentGeomArr) : currentGeomArr[0] || "";
|
|
|
+ if (currentGeomArr.length > 0) {
|
|
|
+ drawRegionMap.setAreaGeometry(currentGeomArr, true);
|
|
|
+ } else {
|
|
|
+ // 仍自适应到品种区底图
|
|
|
+ drawRegionMap.fitAllRegions?.();
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
drawRegionMap.initMap(point.value, mapContainer.value, true, true, true);
|
|
|
applyRegionStyles();
|
|
|
|
|
|
- // 切到编辑态后立即补渲“其他品种只读地块”,避免首次点击编辑时不显示
|
|
|
- renderReadonlyVarietyRegions(activeVariety.value);
|
|
|
-
|
|
|
- if (varietyTabs.value.length && regionGeom.value?.length) {
|
|
|
- drawRegionMap.setAreaGeometry([regionGeom.value],true);
|
|
|
- }
|
|
|
- // 切到编辑态后,统一自适应到所有区域,避免画面偏移
|
|
|
- if (drawRegionMap.fitAllRegions) {
|
|
|
- drawRegionMap.fitAllRegions();
|
|
|
+ // 切到编辑态后:统一走一遍当前 tab 的点击逻辑,确保所有有地块的品种都能显示
|
|
|
+ if (varietyTabs.value.length && varietyTabs.value[activeVariety.value]) {
|
|
|
+ // 进入编辑时:让当前品种地块显示且缩放到当前编辑地块
|
|
|
+ handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
|
|
|
+ const tab = varietyTabs.value[activeVariety.value];
|
|
|
+ const draftGeom = getDraftGeomForTab(activeRegionType.value, tab, activeVariety.value);
|
|
|
+ const geomArr =
|
|
|
+ isValidGeom(draftGeom)
|
|
|
+ ? [String(draftGeom).trim()]
|
|
|
+ : (() => {
|
|
|
+ const fromItems = getGeomArrFromGeomItems(tab);
|
|
|
+ if (fromItems.length) return fromItems;
|
|
|
+ return isValidGeom(tab?.geom) ? [String(tab.geom).trim()] : [];
|
|
|
+ })();
|
|
|
+ drawRegionMap.kmap?.polygonLayer?.source?.clear?.();
|
|
|
+ if (geomArr.length > 0) {
|
|
|
+ drawRegionMap.setAreaGeometry(geomArr, true);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ renderReadonlyVarietyRegions(activeVariety.value);
|
|
|
+ const fallbackGeom = regionGeom.value;
|
|
|
+ if (isValidGeom(fallbackGeom)) {
|
|
|
+ drawRegionMap.setAreaGeometry([fallbackGeom], true);
|
|
|
+ }
|
|
|
}
|
|
|
+ // 编辑态下:保持缩放在当前要编辑地块,不再强制 fitAllRegions 覆盖
|
|
|
});
|
|
|
};
|
|
|
|