| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437 |
- <template>
- <div class="edit-map">
- <custom-header :name="viewOnly ? '查看区域' : '勾选地块'"></custom-header>
- <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 }}
- </div>
- </div>
- <div class="edit-map-content">
- <div class="edit-map-tip" v-if="!viewOnly">操作提示:拖动圆点,即可调整地块边界</div>
- <div class="map-container" ref="mapContainer"></div>
- <div class="edit-map-footer">
- <div class="footer-back" @click="goBack">
- <img class="back-icon" src="@/assets/img/home/go-back.png" alt="" />
- </div>
- <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="confirmArea">确认</div>
- </template>
- <div v-else class="btn-confirm" @click="handleEditRegion">编辑区域</div>
- </div>
- </div>
- </div>
- <save-region-success-popup v-model:show="showSuccessPopup"
- :title="`${activeVarietyName} 区域已保存成功`"
- :has-next="varietyTabs.length > 0 && activeVariety < varietyTabs.length - 1" @know="handleKnow"
- @next="handleSelectNextVariety" />
- <tip-popup v-model:show="showTipPopup" type="success" text="您的农情报告已生成" text2="请查看" buttonText="点击查看"
- @confirm="handleTipConfirm" />
- </div>
- </template>
- <script setup>
- import customHeader from "@/components/customHeader.vue";
- import SaveRegionSuccessPopup from "@/components/popup/saveRegionSuccessPopup.vue";
- import { ref, computed, onActivated, onDeactivated, nextTick } from "vue";
- import { useStore } from "vuex";
- import DrawRegionMap from "../../interactionList/map/drawRegionMap.js";
- import { useRouter, useRoute } from "vue-router";
- import { convertPointToArray } from "@/utils/index";
- import { ElMessage, ElMessageBox } from "element-plus";
- import TipPopup from "@/components/popup/tipPopup.vue";
- const store = useStore();
- const router = useRouter();
- const route = useRoute();
- const mapContainer = ref(null);
- const drawRegionMap = new DrawRegionMap();
- const showSuccessPopup = ref(false);
- // 是否从第一个品种开始的引导流程(需要全部品种都确认后再退出)
- const isGuidedFlow = ref(false);
- // 每个品种(tab)对应的地块数据草稿:key 为 tab index,value 为 { geomArr, geom }
- const regionsDraftByIndex = ref({});
- const submitting = ref(false);
- const type = ref(null);
- const varietyTabs = ref([]);
- const activeVariety = ref(0);
- const regionGeom = ref(null);
- const handleVarietyClick = (tab, index) => {
- activeVariety.value = index;
- regionGeom.value = tab.geom;
- // 每次切换/重绘地块前先清空,避免多边形叠加残留
- if (drawRegionMap.kmap?.polygonLayer?.source) {
- drawRegionMap.kmap.polygonLayer.source.clear();
- }
- if (tab.geom?.length) {
- setTimeout(() => {
- drawRegionMap.setAreaGeometry([tab.geom], true);
- }, 50);
- }
- };
- const activeVarietyName = computed(() => {
- const current = varietyTabs.value[activeVariety.value];
- return current?.regionName || "";
- });
- const viewOnly = computed(() => route.query.type === "viewOnly");
- const point = ref(null);
- async function fetchFarmSubjectDetail() {
- const subjectId = route.query?.subjectId;
- if (!subjectId) return;
- const { data } = await VE_API.basic_farm.fetchFarmSubjectDetail({ subjectId });
-
- if (data?.regionList?.length) {
- if(route.query?.varietyId) {
- activeVariety.value = data?.regionList.findIndex(item => item.typeId == route.query?.varietyId);
- }
- point.value = data.farmLocation;
- varietyTabs.value = data.regionList;
- handleVarietyClick(varietyTabs.value[activeVariety.value], activeVariety.value);
- }
- }
- onActivated(async () => {
- activeVariety.value = 0;
- // keep-alive 场景下再次进入前先销毁旧地图实例,避免重复 init 导致图层状态错位
- if (drawRegionMap.kmap) {
- drawRegionMap.abortOngoingDrawSketch?.();
- drawRegionMap.destroyMap?.();
- }
- type.value = route.query.type;
- const editable = !viewOnly.value;
- await fetchFarmSubjectDetail();
- drawRegionMap.initMap(point.value, mapContainer.value, editable, true, true);
- // 从编辑态进入仅查看时,需重新初始化为不可编辑
- if (viewOnly.value && drawRegionMap.kmap && drawRegionMap.editable) {
- drawRegionMap.destroyMap();
- drawRegionMap.initMap(point.value, mapContainer.value, false, true, false);
- }
- // 从仅查看进入勾画(编辑)时,需重新初始化为可编辑
- if (!viewOnly.value && drawRegionMap.kmap && !drawRegionMap.editable) {
- drawRegionMap.destroyMap();
- drawRegionMap.initMap(point.value, mapContainer.value, true, true, true);
- }
- // 查看模式下已通过 fitAllRegions 适配;编辑模式再设置地图中心
- if (!viewOnly.value) {
- drawRegionMap.setMapPosition(convertPointToArray(point.value));
- }
- });
- onDeactivated(() => {
- activeVariety.value = 0;
- // 离开页面时中止未完成绘制并销毁地图,确保下次进入是干净实例
- drawRegionMap.abortOngoingDrawSketch?.();
- drawRegionMap.destroyMap?.();
- })
- const goBack = () => {
- // drawRegionMap.clearLayer()
- router.back()
- };
- const resetPolygon = () => {
- ElMessageBox.confirm(
- "确认要重置当前地块吗?重置后将恢复到进入页面时的区域形状。",
- "重置确认",
- {
- confirmButtonText: "确认重置",
- cancelButtonText: "取消",
- type: "warning",
- }
- )
- .then(() => {
- // 先取消进行中的勾画草图(未完成时线条在 Draw 的 overlay 上,清 source 去不掉)
- drawRegionMap.abortOngoingDrawSketch();
- // 只清空当前可编辑多边形,不影响只读状态图层
- if (drawRegionMap.kmap && drawRegionMap.kmap.polygonLayer && drawRegionMap.kmap.polygonLayer.source) {
- drawRegionMap.kmap.polygonLayer.source.clear();
- }
- // 使用进入页面时路由上带的 polygonData 作为“初始形状”进行回显
- const polygonDataStr = route.query.polygonData;
- if (polygonDataStr) {
- try {
- const parsed = JSON.parse(polygonDataStr);
- if (parsed && Array.isArray(parsed.geometryArr) && parsed.geometryArr.length) {
- drawRegionMap.setAreaGeometry(parsed.geometryArr);
- }
- } catch (_) {
- // 解析失败则不做处理,仅相当于清空重画
- }
- }
- ElMessage.success("地块已重置");
- })
- .catch(() => {
- // 用户取消重置,不做任何操作
- });
- };
- 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) {
- ElMessage.warning("请先勾画地块后再确认");
- return;
- }
- submitting.value = true;
- try {
- const res = await VE_API.basic_farm.saveBasicFarmInfoByExpertV3({
- id: route.query.subjectId,
- expertMiniUserId: '81881',
- regions,
- });
- if (res?.code === 0) {
- return true;
- }
- ElMessage.error(res?.msg || "保存失败");
- return false;
- } catch (e) {
- ElMessage.error("保存失败");
- return false;
- } finally {
- submitting.value = false;
- }
- };
- const confirmArea = async () => {
- // 先把当前品种的地块保存到草稿
- 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 };
- // 任意品种确认后都进入引导流程(中间品种也可继续“下一步”)
- isGuidedFlow.value = true;
- // 每次确认都提交接口(携带目前已确认过的所有品种 regions)
- const ok = await submitRegions();
- await VE_API.basic_farm.updateLastViewTime({
- regionId: varietyTabs.value[activeVariety.value].regionId,
- });
- fetchFarmSubjectDetail()
- if (!ok) return;
- // 引导流程:弹成功提示,由弹窗控制“下一步/完成”
- if (isGuidedFlow.value) {
- showSuccessPopup.value = true;
- return;
- }
- // 非引导流程:确认后返回上一页
- router.back();
- };
- const handleKnow = () => {
- showSuccessPopup.value = false;
- if (route.query.showTipPopup) {
- showTipPopup.value = true;
- return;
- }
- if(route.query.targetUrl) {
- router.replace(route.query.targetUrl);
- return;
- }
- router.back();
- };
- const handleSelectNextVariety = () => {
- if (varietyTabs.value.length === 0) {
- handleKnow();
- return;
- }
- const nextIndex = activeVariety.value + 1;
- if (nextIndex < varietyTabs.value.length) {
- const nextTab = varietyTabs.value[nextIndex];
- // 勾画当前品种完成后,先用统一的 clearLayer 方法重置图层,再切换到下一个品种
- if (drawRegionMap && typeof drawRegionMap.clearLayer === "function") {
- drawRegionMap.clearLayer();
- }
- handleVarietyClick(nextTab, nextIndex);
- showSuccessPopup.value = false;
- } else {
- // 如果已经是最后一个品种,则直接返回上一页
- handleKnow();
- }
- };
- const handleEditRegion = () => {
- // 从查看态切换到可勾画编辑态:移除查看标记并重建地图(editable=true)
- const nextQuery = { ...route.query };
- delete nextQuery.type;
- delete nextQuery.viewOnly;
- router.replace({ query: nextQuery });
- nextTick(() => {
- if (drawRegionMap.kmap) {
- drawRegionMap.destroyMap();
- }
- drawRegionMap.initMap(point.value, mapContainer.value, true, true, true);
- if (varietyTabs.value.length && regionGeom.value.length) {
- drawRegionMap.setAreaGeometry([regionGeom.value],true);
- }
- // 切到编辑态后,统一自适应到所有区域,避免画面偏移
- if (drawRegionMap.fitAllRegions) {
- drawRegionMap.fitAllRegions();
- }
- });
- };
- const showTipPopup = ref(false);
- const handleTipConfirm = () => {
- router.push("/growth_report?hideInteraction=true");
- }
- </script>
- <style lang="scss" scoped>
- .edit-map {
- width: 100%;
- height: 100vh;
- overflow: hidden;
- .variety-tabs {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 10px 12px 0;
- overflow-x: auto;
- overflow-y: hidden;
- flex-wrap: nowrap;
- -webkit-overflow-scrolling: touch;
- .variety-tab {
- padding: 4px 12px;
- border-radius: 2px;
- color: #767676;
- background: #fff;
- border: 0.5px solid rgba(174, 174, 174, 0.8);
- white-space: nowrap;
- }
- .variety-tab--active {
- background: #2199F8;
- color: #ffffff;
- }
- }
- .edit-map-content {
- width: 100%;
- margin-top: 10px;
- height: calc(100% - 58px);
- position: relative;
- .edit-map-tip {
- position: absolute;
- top: 23px;
- left: calc(50% - 256px / 2);
- z-index: 1;
- font-size: 12px;
- color: #fff;
- padding: 9px 20px;
- background: rgba(0, 0, 0, 0.5);
- border-radius: 20px;
- }
- .map-container {
- width: 100%;
- height: 100%;
- }
- .edit-map-footer {
- position: absolute;
- bottom: 110px;
- left: 12px;
- width: calc(100% - 24px);
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- .footer-back {
- padding: 6px 7px 9px;
- background: #fff;
- border-radius: 8px;
- margin-bottom: 12px;
- .back-icon {
- width: 20px;
- height: 18px;
- }
- }
- .edit-map-footer-btn {
- display: flex;
- justify-content: space-between;
- align-items: center;
- width: 100%;
- position: fixed;
- bottom: 0;
- left: 0;
- background: #fff;
- padding: 10px 12px 20px 12px;
- box-sizing: border-box;
- &.confirm-btn-box {
- justify-content: center;
- }
- div {
- width: 100px;
- text-align: center;
- color: #666666;
- font-size: 14px;
- padding: 8px 0;
- border-radius: 25px;
- border: 0.5px solid rgba(153, 153, 153, 0.5);
- }
- .btn-confirm {
- background: #2199F8;
- color: #fff;
- border: 1px solid #2199F8;
- }
- }
- }
- }
- }
- </style>
|