Bläddra i källkod

feat:修改首页数据

wangsisi 6 dagar sedan
förälder
incheckning
ffd61f9cc1

BIN
src/assets/img/common/lz-chart-1.png


BIN
src/assets/img/common/lz-chart-2.png


BIN
src/assets/img/common/lz-chart-3.png


BIN
src/assets/img/common/sd-1.png


BIN
src/assets/img/common/sd-2.png


BIN
src/assets/img/common/sd-3.png


BIN
src/assets/img/common/sd-4.png


BIN
src/assets/img/common/sd-5.png


BIN
src/assets/img/common/sd-6.png


BIN
src/assets/img/common/sd-chart-1.png


BIN
src/assets/img/common/sd-chart-2.png


BIN
src/assets/img/common/sd-chart-3.png


+ 2 - 2
src/components/gardenList.vue

@@ -35,7 +35,7 @@
                 </div>
             </div>
 
-            <div class="card-divider"></div>
+            <!-- <div class="card-divider"></div>
 
             <div class="stat-list">
                 <div
@@ -47,7 +47,7 @@
                     <div class="stat-title">{{ stat.title }}</div>
                     <div class="stat-label">{{ stat.label }}</div>
                 </div>
-            </div>
+            </div> -->
         </div>
     </div>
 

+ 1 - 0
src/components/pageComponents/ArchivesFarmTimeLine.vue

@@ -728,6 +728,7 @@ onBeforeRouteLeave(() => {
                                     border-radius: 2px;
                                     padding: 2px 5px;
                                     font-size: 10px;
+                                    min-width: fit-content;
                                 }
                             }
 

+ 6 - 5
src/components/pageComponents/GrowthStageTimeline.vue

@@ -254,12 +254,13 @@ watch(
     [colCount, () => props.modelValue],
     () => {
         const mv = props.modelValue;
-        const next =
-            mv === undefined || mv === null
-                ? middleStageIndex()
-                : clampStageIndex(mv);
+        const hasParentIndex = mv !== undefined && mv !== null;
+        const next = hasParentIndex
+            ? clampStageIndex(mv)
+            : middleStageIndex();
         activeIndex.value = next;
-        if (mv === undefined || mv === null) {
+        // 仅在没有父级索引时回写默认档,避免覆盖父组件按物候编码算好的下标
+        if (!hasParentIndex) {
             nextTick(() => {
                 emit("update:modelValue", next);
             });

+ 4 - 3
src/components/weatherInfo.vue

@@ -57,10 +57,10 @@
                     </div>
 
                     <div class="button-wrap" v-if="hasFarm">
-                        <div class="button-item" @click="handleFarmInfo">
+                        <!-- <div class="button-item" @click="handleFarmInfo">
                             <img class="button-pre" src="@/assets/img/common/info.png" alt="">
                             {{ t("weather.farmInfoMaintain") }}
-                        </div>
+                        </div> -->
                         <!-- <div class="button-item">
                             <img class="button-pre" src="@/assets/img/common/idea.png" alt="">
                             种植档案管理
@@ -331,7 +331,8 @@ defineExpose({
     &.is-garden {
         border-radius: 8px;
         box-shadow: 0px -2px 4px 0px #0000000D;
-        height: 130px;
+        // height: 130px;
+        height: 96px;
     }
 
     &.no-weather {

+ 28 - 16
src/i18n/messages.js

@@ -56,11 +56,12 @@ export default {
             tooltipHint: "此为预估进程,请左右移动进行校准!",
         },
         growthReport: {
-            title: "荔枝长势报告",
+            title: "长势报告",
             cropTitle: "作物长势报告",
             weatherRisk: "气象风险",
             cropLychee: "荔枝",
-            phenologyFruitExpansion: "膨果期",
+            phenologyFruitExpansion: "转色期",
+            phenologyLateTillering: "分蘖末期",
             inStage: "处于{stage}",
             futureWeatherRisk: "未来7-15天气象风险",
             farmAdvice: "农事建议",
@@ -70,8 +71,9 @@ export default {
             lockSub: "点击解锁一键溯源增产",
             risk: {
                 pest: {
-                    title: "病虫风险",
-                    desc: "当前膨果期对病虫害高度敏感,易受害。经过飞鸟智慧大脑计算病虫风险:病虫胁迫指数处于中等水平,存在一定的病虫害发生风险,局部区域可能出现病害流行或虫害爆发,需加强监测预警,及时巡园",
+                    title: "高温干旱风险",
+                    desc: "经过飞鸟智慧大脑计算气象风险:高温干旱胁迫指数处于中等水平,存在果皮灼伤风险,局部区域可能会对果实品质造成伤害,需加强监测预警,及时执行相关农事。",
+                    descRice: "经过飞鸟智慧大脑计算气象风险:高温干旱胁迫指数处于低等水平,但目前即将进入拔节孕穗期,对水分会更加敏感,因此需加强监测预警,及时执行相关农事。",
                 },
                 rain: {
                     title: "阴雨寡照风险",
@@ -80,8 +82,10 @@ export default {
             },
             advice: {
                 foliar: {
-                    title: "根外追肥",
-                    desc: "荔枝膨果期遇持续阴雨寡照,需及时排水防渍,重点根外喷施磷酸二氢钾并配合补充钙硼肥,以快速恢复树势、促进膨果壮果。",
+                    title: "喷灌降温",
+                    desc: "荔枝转色期遭遇高温干旱风险,需及时喷撒清水,降低果园小气候与果皮表面温度,预防果皮灼伤。",
+                    titleRice: "灌水降温",
+                    descRice: "虽然当前高温干旱风险等级低,但由于水稻即将进入水分敏感时期,建议喷灌清水,降低田间温度,预防缺水影响物候进程。",
                 },
                 pestControl: {
                     title: "虫害防治",
@@ -91,11 +95,13 @@ export default {
             patrol: {
                 process: {
                     title: "进程互动",
-                    desc: "是否有60%的荔枝进入果实转色期?",
+                    desc: "是否有5%的荔枝进入果实转色期?",
+                    descRice: "是否有60%的水稻进入分蘖末期?",
                 },
                 growth: {
                     title: "长势互动",
-                    desc: "是是否有10%的荔枝出现生理落果或裂果症状",
+                    desc: "是否有10%的荔枝抽生新梢?",
+                    descRice: "是否有10%的水稻出现干旱缺素症状?",
                 },
                 pest: {
                     title: "病虫互动",
@@ -239,11 +245,12 @@ export default {
             tooltipHint: "This is an estimated progress. Drag left or right to calibrate.",
         },
         growthReport: {
-            title: "Lychee Growth Report",
+            title: "Growth Report",
             cropTitle: "Crop Growth Report",
             weatherRisk: "Weather risks",
             cropLychee: "Lychee",
-            phenologyFruitExpansion: "Fruit expansion stage",
+            phenologyFruitExpansion: "Color change stage",
+            phenologyLateTillering: "Late tillering stage",
             inStage: "in {stage}",
             futureWeatherRisk: "7–15 day weather risks",
             farmAdvice: "Farming advice",
@@ -253,8 +260,9 @@ export default {
             lockSub: "Tap to unlock traceability & yield boost",
             risk: {
                 pest: {
-                    title: "Pest & disease risk",
-                    desc: "During fruit expansion, crops are highly sensitive to pests and diseases. Feiniao AI assessment: moderate pest stress index. Local outbreaks are possible — strengthen monitoring and patrols.",
+                    title: "High temperature & drought risk",
+                    desc: "Feiniao AI weather risk assessment: moderate heat and drought stress index. Sunscald on fruit peel is possible; local areas may suffer fruit quality damage. Strengthen monitoring and early warning, and implement related farm practices promptly.",
+                    descRice: "Feiniao AI weather risk assessment: heat and drought stress index is at a low level, but jointing and heading stage is approaching, when crops become more sensitive to water stress. Strengthen monitoring and early warning, and implement related farm practices promptly.",
                 },
                 rain: {
                     title: "Rain & low-light risk",
@@ -263,8 +271,10 @@ export default {
             },
             advice: {
                 foliar: {
-                    title: "Foliar feeding",
-                    desc: "During prolonged rain and low light in fruit expansion, improve drainage. Apply potassium dihydrogen phosphate foliar spray with calcium and boron to restore vigor and promote fruit sizing.",
+                    title: "Sprinkler cooling",
+                    desc: "During the lychee color-change stage, heat and drought pose a risk. Spray clean water promptly to lower orchard microclimate and fruit peel surface temperature, and prevent fruit peel sunscald.",
+                    titleRice: "Irrigation cooling",
+                    descRice: "Although the current heat and drought risk level is low, rice is entering a water-sensitive period. Sprinkler irrigation with clean water is recommended to lower field temperature and prevent water stress from affecting phenological progress.",
                 },
                 pestControl: {
                     title: "Pest control",
@@ -274,11 +284,13 @@ export default {
             patrol: {
                 process: {
                     title: "Progress check",
-                    desc: "Have 60% of lychee trees entered fruit color-change stage?",
+                    desc: "Have 5% of lychee trees entered fruit color-change stage?",
+                    descRice: "Have 60% of rice entered late tillering stage?",
                 },
                 growth: {
                     title: "Growth check",
-                    desc: "Do 10% of lychee trees show physiological drop or fruit cracking?",
+                    desc: "Have 10% of lychee trees produced new shoots?",
+                    descRice: "Do 10% of rice plants show drought-related nutrient deficiency symptoms?",
                 },
                 pest: {
                     title: "Pest check",

+ 7 - 5
src/views/old_mini/agri_file/components/fileFloat.vue

@@ -21,11 +21,13 @@
                     <div class="tab-loading" v-if="loading">{{ t('agriFile.loading') }}</div>
                     <div class="tab-empty" v-else-if="currentList.length === 0">{{ t('agriFile.noData') }}</div>
                     <div v-else class="tab-content-item" v-for="item in displayList" :key="item.id">
-                        <div class="time-tag">{{ item.time }}</div>
-                        <div class="item-info">
-                            {{ item.recordText }}
-                            <span class="blue-text">{{ item.ratio }}{{ item.showRatio ? '%' : '' }}</span>
-                        </div>
+                        <template v-if="item?.recordText?.length">
+                            <div class="time-tag">{{ item.time }}</div>
+                            <div class="item-info">
+                                {{ item.recordText }}
+                                <span class="blue-text">{{ item.ratio }}{{ item.showRatio ? '%' : '' }}</span>
+                            </div>
+                        </template>
                     </div>
                 </template>
                 <div v-else-if="isRemoteSensingTab" class="remote-sensing-chart">

+ 2 - 2
src/views/old_mini/agri_file/index.vue

@@ -121,8 +121,8 @@ const MAP_TOOL_ITEMS = [
     { key: "habitat", label: "生境" },
     { key: "light", label: "光照" },
     { key: "water", label: "水源" },
-    { key: "fengshui", label: "风水" },
-    { key: "soil", label: "土壤" },
+    // { key: "fengshui", label: "风水" },
+    // { key: "soil", label: "土壤" },
 ];
 
 const mapToolItems = MAP_TOOL_ITEMS;

+ 91 - 0
src/views/old_mini/growth_report/historyRiskReport copy.vue

@@ -0,0 +1,91 @@
+<template>
+    <div class="history-risk-report-page">
+        <custom-header :name="$t('历史风险报告')" isGoBack @goback="handleGoBack"></custom-header>
+        <div v-loading="loading" class="history-risk-report-content">
+            <div v-if="reportContent" class="rich-text" v-html="reportContent"></div>
+            <div v-else-if="!loading" class="empty-text">{{ t('暂无内容') }}</div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { useI18n } from "@/i18n";
+const { t } = useI18n();
+import { onActivated, onMounted, ref } from "vue";
+import { useRouter } from "vue-router";
+import customHeader from "@/components/customHeader.vue";
+
+const router = useRouter();
+const loading = ref(false);
+const reportContent = ref("");
+
+const getReportDetail = () => {
+    loading.value = true;
+    VE_API.bbs
+        .postDetail({ id: "829511846204542976" })
+        .then((res) => {
+            reportContent.value = res?.data?.content || "";
+        })
+        .finally(() => {
+            loading.value = false;
+        });
+};
+
+const handleGoBack = () => {
+    if (window.history.length > 1) {
+        router.back();
+        return;
+    }
+    router.replace("/growth_report");
+};
+
+onMounted(() => {
+    getReportDetail();
+});
+
+onActivated(() => {
+    getReportDetail();
+});
+</script>
+
+<style scoped lang="scss">
+.history-risk-report-page {
+    width: 100%;
+    height: 100vh;
+    background: #ffffff;
+    overflow: hidden;
+
+    .history-risk-report-content {
+        height: calc(100vh - 40px);
+        padding: 12px 16px 20px;
+        box-sizing: border-box;
+        overflow-y: auto;
+        -webkit-overflow-scrolling: touch;
+    }
+
+    .rich-text {
+        font-size: 14px;
+        line-height: 1.75;
+        color: #333333;
+        word-break: break-word;
+
+        ::v-deep(img) {
+            max-width: 100%;
+            height: auto;
+            border-radius: 6px;
+        }
+
+        ::v-deep(table) {
+            width: 100% !important;
+            table-layout: fixed;
+        }
+    }
+
+    .empty-text {
+        padding-top: 40px;
+        text-align: center;
+        color: #999999;
+        font-size: 14px;
+    }
+}
+</style>

+ 372 - 51
src/views/old_mini/growth_report/historyRiskReport.vue

@@ -1,35 +1,109 @@
 <template>
     <div class="history-risk-report-page">
         <custom-header :name="$t('历史风险报告')" isGoBack @goback="handleGoBack"></custom-header>
-        <div v-loading="loading" class="history-risk-report-content">
-            <div v-if="reportContent" class="rich-text" v-html="reportContent"></div>
-            <div v-else-if="!loading" class="empty-text">{{ t('暂无内容') }}</div>
+        <div class="report-content-wrap" v-loading="loading" element-loading-background="rgba(0, 0, 0, 0.1)">
+            <div class="report-content has-report" :style="{ minHeight: 'calc(100vh - 40px)' }">
+                <img class="header-img" src="@/assets/img/home/report.png" alt="" />
+
+                <div class="report-header">
+                    <div class="report-title">农场历史风险报告</div>
+                    <div class="report-info">
+                        <div class="info-item">
+                            <img class="info-icon" src="@/assets/img/home/farm.png" alt="" />
+                            <span class="info-text">{{ currentFarmName }}</span>
+                        </div>
+                    </div>
+                </div>
+
+                <div class="report-box">
+                    <div class="box-title">历史气象风险统计</div>
+                    <div class="box-text">
+                        <div class="box-bg">
+                            <div class="types-info">
+                                基于历史气象站点与遥感数据,飞鸟统计近10年不同物候期冻害、高温干旱等风险的发生频率与平均等级。统计结果如下
+                            </div>
+                        </div>
+                        <div class="warning-part" v-if="currentFarmVariety === 1">
+                            <div class="report-part">
+                                <div class="part-title">梢期历史气象风险</div>
+                                <img class="part-img" src="@/assets/img/common/lz-chart-1.png" alt="" />
+                            </div>
+                            <div class="report-part">
+                                <div class="part-title">花期历史气象风险</div>
+                                <img class="part-img" src="@/assets/img/common/lz-chart-2.png" alt="" />
+                            </div>
+                            <div class="report-part">
+                                <div class="part-title">果期历史气象风险</div>
+                                <img class="part-img" src="@/assets/img/common/lz-chart-3.png" alt="" />
+                            </div>
+                        </div>
+                        <div class="warning-part" v-else>
+                            <div class="report-part">
+                                <div class="part-title">营养生长期历史气象风险</div>
+                                <img class="part-img" src="@/assets/img/common/sd-chart-1.png" alt="" />
+                            </div>
+                            <div class="report-part">
+                                <div class="part-title">穗期历史气象风险</div>
+                                <img class="part-img" src="@/assets/img/common/sd-chart-2.png" alt="" />
+                            </div>
+                            <div class="report-part">
+                                <div class="part-title">灌浆结实期历史气象风险</div>
+                                <img class="part-img" src="@/assets/img/common/sd-chart-3.png" alt="" />
+                            </div>
+                        </div>
+                    </div>
+                </div>
+
+                <div class="report-box">
+                    <div class="box-title">土壤改良分析</div>
+                    <div class="box-text">
+                        <div class="part-text" v-if="currentFarmVariety === 1">当前农场土壤为壤土,酸性至微酸性(pH
+                            6.5),有机质含量(6.25%),肥力良好。在后续的种植管理中,需保持土壤肥力,合理施肥,必要时需加入生石灰中和酸性,避免土壤酸化加剧。</div>
+                        <div class="part-text" v-else>当前农场土壤为壤土,酸性至微酸性(pH 5.9),有机质含量(5.52%),肥力良好,但酸性偏低。在后续的种植管理中,需保持土壤肥力,合理施肥,需加入生石灰中和酸性,降低土壤酸化问题。</div>
+                    </div>
+                </div>
+
+                <div class="report-box">
+                    <div class="box-title">耕作习惯分析</div>
+                    <div class="box-text">
+                        <div class="part-text" v-if="currentFarmVariety === 1">当前农场耕作管理制度完善,未出现频繁翻耕等问题。在后续的种植管理中,需继续维持合理的农事规划和农事操作,保持土壤活力。</div>
+                        <div class="part-text" v-else>当前农场耕作管理制度完善,未出现频繁翻耕等问题。在后续的种植管理中,需继续维持合理的农事规划和农事操作,保持土壤活力。但由于农场长期种植单一作物,导致土壤养分失衡,因此建议在施肥时多补充有机质和微量元素。同时,建议在水稻休耕时期轮种紫云英等绿肥作物,改善土壤问题。</div>
+                    </div>
+                </div>
+
+                <div class="report-box">
+                    <div class="box-title">设施投入建议</div>
+                    <div class="box-text">
+                        <div class="part-text" v-if="currentFarmVariety === 1">考虑到当前农场历史高发风险为高温干旱风险,高发概率达到80%,建议提前规划好喷灌/滴灌系统,以维持农场的日常灌溉,降低高温干旱风险的影响。</div>
+                        <div class="part-text" v-else>考虑到当前农场历史高发风险为低温冻害和暴雨涝渍风险,历史出现概率均超过90%,建议提前规划好排水沟渠以及灌溉系统,以便灵活排水灌水,合理控制田间温度和水层深度。</div>
+                    </div>
+                </div>
+            </div>
         </div>
     </div>
 </template>
 
 <script setup>
-import { useI18n } from "@/i18n";
-const { t } = useI18n();
-import { onActivated, onMounted, ref } from "vue";
-import { useRouter } from "vue-router";
+import { ref, computed } from "vue";
+import { useRouter ,useRoute} from "vue-router";
 import customHeader from "@/components/customHeader.vue";
 
 const router = useRouter();
 const loading = ref(false);
-const reportContent = ref("");
-
-const getReportDetail = () => {
-    loading.value = true;
-    VE_API.bbs
-        .postDetail({ id: "829511846204542976" })
-        .then((res) => {
-            reportContent.value = res?.data?.content || "";
-        })
-        .finally(() => {
-            loading.value = false;
-        });
-};
+const route = useRoute();
+const currentFarmName = computed(() => route.query.currentFarmName);
+const currentFarmVariety = computed(() => route.query.farmVariety);
+const riskList = ref([{ title: "梢期历史气象风险", description: "xxx" }]);
+const adviceList = ref([{ title: "xxx", description: "xxx" }]);
+const patrolList = ref([{ title: "xxx", description: "xxx" }]);
+const workItems = ref([
+    {
+        title: "xxx",
+        backgroundDesc: "xxx",
+        suggestion: "xxx",
+        summary: "xxx",
+    },
+]);
 
 const handleGoBack = () => {
     if (window.history.length > 1) {
@@ -38,54 +112,301 @@ const handleGoBack = () => {
     }
     router.replace("/growth_report");
 };
-
-onMounted(() => {
-    getReportDetail();
-});
-
-onActivated(() => {
-    getReportDetail();
-});
 </script>
 
 <style scoped lang="scss">
 .history-risk-report-page {
     width: 100%;
     height: 100vh;
-    background: #ffffff;
+    background: linear-gradient(195.35deg, #d4e4ff 16.34%, rgba(93, 189, 255, 0) 50.3%),
+        linear-gradient(156.64deg, rgba(255, 255, 255, 0.16) 27.7%, rgba(255, 255, 255, 0) 72.82%);
     overflow: hidden;
+    display: flex;
+    flex-direction: column;
 
-    .history-risk-report-content {
-        height: calc(100vh - 40px);
-        padding: 12px 16px 20px;
+    .report-content-wrap {
+        flex: 1;
+        overflow: auto;
         box-sizing: border-box;
-        overflow-y: auto;
+        position: relative;
         -webkit-overflow-scrolling: touch;
     }
 
-    .rich-text {
-        font-size: 14px;
-        line-height: 1.75;
-        color: #333333;
-        word-break: break-word;
+    .report-content {
+        background: #abd4ff;
+        background-size: 100% auto;
+        background-position: top center;
+        padding: 0 10px 26px 10px;
+        box-sizing: border-box;
+        position: relative;
 
-        ::v-deep(img) {
-            max-width: 100%;
-            height: auto;
-            border-radius: 6px;
+        &.has-report {
+            min-height: 100%;
+            background: linear-gradient(0deg, #9bccff, #9bccff),
+                linear-gradient(156.64deg, rgba(255, 255, 255, 0.16) 27.7%, rgba(255, 255, 255, 0) 72.82%);
         }
 
-        ::v-deep(table) {
-            width: 100% !important;
-            table-layout: fixed;
+        .header-img {
+            position: absolute;
+            top: 0;
+            left: 0;
+            width: 100%;
         }
-    }
 
-    .empty-text {
-        padding-top: 40px;
-        text-align: center;
-        color: #999999;
-        font-size: 14px;
+        .type-tabs {
+            background: rgba(255, 255, 255, 0.8);
+            display: flex;
+            align-items: center;
+            flex-wrap: wrap;
+            gap: 8px;
+            width: fit-content;
+            border-radius: 5px;
+            padding: 5px;
+            margin-bottom: 22px;
+
+            .type-item {
+                height: 28px;
+                line-height: 28px;
+                text-align: center;
+                padding: 0 6px;
+                min-width: 80px;
+                color: #9a9a9a;
+                background: #ffffff;
+                box-sizing: border-box;
+                border-radius: 2px;
+
+                &.type-item-active {
+                    background: #2199f8;
+                    color: #fff;
+                }
+            }
+        }
+
+        .report-header {
+            position: relative;
+            padding-top: 14px;
+
+            .time-tag {
+                background: #2199f8;
+                border-radius: 5px 0 5px 0;
+                height: 23px;
+                line-height: 23px;
+                font-size: 13px;
+                font-weight: 500;
+                color: #fff;
+                padding: 0 9px;
+                width: fit-content;
+                margin-bottom: 4px;
+            }
+
+            .report-title {
+                font-family: "PangMenZhengDao";
+                font-size: 34px;
+                line-height: 38px;
+                color: #000000;
+            }
+
+            .report-info {
+                padding: 12px 0 28px 0;
+
+                .info-item {
+                    width: fit-content;
+                    display: flex;
+                    height: 33px;
+                    align-items: center;
+                    padding: 0 18px 0 6px;
+                    background: rgba(255, 255, 255, 0.58);
+                    backdrop-filter: blur(5px);
+                    border-radius: 20px;
+                    gap: 6px;
+
+                    .info-icon {
+                        width: 26px;
+                        height: 26px;
+                        object-fit: cover;
+                        border-radius: 50%;
+                    }
+
+                    .info-text {
+                        font-size: 14px;
+                        color: #000;
+                    }
+                }
+            }
+        }
+
+        .report-box {
+            display: flex;
+            align-items: center;
+            padding: 8px 12px;
+            background: #fff;
+            border: 1px solid #ffffff;
+            border-radius: 8px;
+            gap: 5px;
+            position: relative;
+
+            .box-title {
+                position: absolute;
+                top: -8px;
+                left: -1px;
+                height: 32px;
+                line-height: 26px;
+                font-family: "PangMenZhengDao";
+                font-size: 14px;
+                padding: 0 10px;
+                color: #ffffff;
+                background: url("@/assets/img/home/title-bg.png") no-repeat center center / 100% 100%;
+            }
+
+            .box-text {
+                padding: 22px 0 8px 0;
+                font-weight: 350;
+                line-height: 21px;
+                width: 100%;
+                box-sizing: border-box;
+
+                .pre-text {
+                    white-space: pre-line;
+                    word-break: break-word;
+                }
+
+                .box-subtitle {
+                    color: #000;
+                }
+
+                .box-bg {
+                    font-weight: 400;
+                    color: rgba(0, 0, 0, 0.5);
+                    margin-bottom: 8px;
+                }
+
+                .types-info {
+                    background: rgba(33, 153, 248, 0.1);
+                    color: #000000;
+                    padding: 6px;
+                    border-radius: 5px;
+
+                    .text-bold {
+                        font-weight: bold;
+                    }
+                }
+
+                .tp-img {
+                    display: grid;
+                    grid-template-columns: repeat(3, 1fr);
+                    gap: 6px;
+                    width: 100%;
+                    margin-top: 8px;
+                    box-sizing: border-box;
+
+                    img {
+                        width: 100%;
+                        height: 78px;
+                        object-fit: contain;
+                    }
+                }
+
+                .report-part {
+                    color: rgba(0, 0, 0, 0.5);
+
+                    .part-title {
+                        background: #2199f8;
+                        height: 24px;
+                        line-height: 24px;
+                        padding: 0 8px;
+                        color: #fff;
+                        border-radius: 2px;
+                        width: fit-content;
+                    }
+
+                    .part-img {
+                        width: 100%;
+                        height: 180px;
+                        margin-top: 6px;
+                        object-fit: cover;
+                    }
+
+                    .part-text {
+                        padding-top: 6px;
+                    }
+
+                    .part-top {
+                        display: flex;
+                        align-items: center;
+                        justify-content: space-between;
+                    }
+                }
+
+                .warning-part+.warning-part {
+                    margin-top: 8px;
+                }
+
+                .report-part+.report-part {
+                    margin-top: 8px;
+                }
+
+                .warning-part {
+                    background: rgba(178, 178, 178, 0.08);
+                    border-radius: 5px;
+                    padding: 11px 6px 6px;
+                    color: rgba(0, 0, 0, 0.5);
+                    width: 100%;
+                    box-sizing: border-box;
+
+                    .warning-title {
+                        display: flex;
+                        align-items: center;
+                        justify-content: center;
+                        gap: 10px;
+                        padding-bottom: 13px;
+
+                        .title-l {
+                            display: flex;
+                            align-items: center;
+
+                            .title-line {
+                                width: 68px;
+                                height: 1px;
+                                background: linear-gradient(90deg,
+                                        rgba(118, 118, 118, 0) 0%,
+                                        rgba(118, 118, 118, 0.4) 100%);
+
+                                &.title-line-right {
+                                    background: linear-gradient(270deg,
+                                            rgba(118, 118, 118, 0) 0%,
+                                            rgba(118, 118, 118, 0.4) 100%);
+                                }
+                            }
+
+                            .title-block {
+                                width: 6px;
+                                height: 6px;
+                                background: rgba(61, 61, 61, 0.2);
+                                transform: rotate(45deg);
+                            }
+                        }
+                    }
+                }
+
+                .box-advice {
+                    color: rgba(0, 0, 0, 0.5);
+                    padding-top: 10px;
+                }
+
+                .box-sum {
+                    margin-top: 10px;
+                    background: rgba(33, 153, 248, 0.1);
+                    border-radius: 5px;
+                    padding: 10px;
+                    line-height: 20px;
+                    color: #2199f8;
+                }
+            }
+        }
+
+        .report-box+.report-box {
+            margin-top: 20px;
+        }
     }
 }
 </style>

+ 70 - 35
src/views/old_mini/growth_report/index.vue

@@ -26,12 +26,12 @@
 
         <div class="report-content-wrap" v-if="hasReport && activeGardenTab === 'current'" v-loading="loading"
             element-loading-background="rgba(0, 0, 0, 0.1)">
-            <!-- <div class="history-risk-report-btn" @click="handleHistoryRiskReportClick">
+            <div class="history-risk-report-btn" @click="handleHistoryRiskReportClick">
                 <span class="risk-report-icon">
                     <i></i>
                 </span>
                 <span class="risk-report-text">{{ t('历史风险报告') }}</span>
-            </div> -->
+            </div>
 
             <div class="report-content has-report" :style="{ minHeight: `calc(100vh - ${tabBarHeight}px)` }">
                 <!-- <img src="@/assets/img/home/qrcode.png" alt="" class="code-icon" /> -->
@@ -61,7 +61,7 @@
                     </div>
 
                     <div class="time-tag">{{ workItems?.[0]?.reportDate || new Date().toISOString().split('T')[0] }}</div>
-                    <div class="report-title report-title-toggle" @click="toggleLocale">{{ t("growthReport.title") }}</div>
+                    <div class="report-title report-title-toggle" @click="toggleLocale">{{ varietyName }}{{ t("growthReport.title") }}</div>
                     <div class="report-info">
                         <div class="info-item">
                             <img class="info-icon" src="@/assets/img/home/farm.png" alt="" />
@@ -79,10 +79,10 @@
                             </div> -->
                             <div class="types-info">
                                 {{ t("common.current") }}
-                                <span class="text-bold">{{ t("growthReport.cropLychee") }}</span>
-                                {{ t("growthReport.inStage", { stage: t("growthReport.phenologyFruitExpansion") }) }}
+                                <span class="text-bold">{{ varietyName }}</span>
+                                {{ t("growthReport.inStage", { stage: currentPhenologyStage }) }}
                             </div>
-                            <div class="tp-img">
+                            <div class="tp-img" v-if="currentFarmVariety === 1">
                                 <img src="@/assets/img/common/tp-1.png" alt="">
                                 <img src="@/assets/img/common/tp-2.png" alt="">
                                 <img src="@/assets/img/common/tp-3.png" alt="">
@@ -90,6 +90,14 @@
                                 <img src="@/assets/img/common/tp-5.png" alt="">
                                 <img src="@/assets/img/common/tp-6.png" alt="">
                             </div>
+                            <div class="tp-img" v-else>
+                                <img src="@/assets/img/common/sd-1.png" alt="">
+                                <img src="@/assets/img/common/sd-2.png" alt="">
+                                <img src="@/assets/img/common/sd-3.png" alt="">
+                                <img src="@/assets/img/common/sd-4.png" alt="">
+                                <img src="@/assets/img/common/sd-5.png" alt="">
+                                <img src="@/assets/img/common/sd-6.png" alt="">
+                            </div>
                         </div>
                         <div class="warning-part">
                             <div class="warning-title">
@@ -247,39 +255,55 @@ const swipeRef = ref(null);
 const riskList = computed(() => [
     {
         title: t("growthReport.risk.pest.title"),
-        description: t("growthReport.risk.pest.desc"),
-    },
-    {
-        title: t("growthReport.risk.rain.title"),
-        description: t("growthReport.risk.rain.desc"),
+        description:
+            currentFarmVariety.value == 1
+                ? t("growthReport.risk.pest.desc")
+                : t("growthReport.risk.pest.descRice"),
     },
+    // {
+    //     title: t("growthReport.risk.rain.title"),
+    //     description: t("growthReport.risk.rain.desc"),
+    // },
 ]);
 
 const adviceList = computed(() => [
     {
-        title: t("growthReport.advice.foliar.title"),
-        description: t("growthReport.advice.foliar.desc"),
-    },
-    {
-        title: t("growthReport.advice.pestControl.title"),
-        description: t("growthReport.advice.pestControl.desc"),
+        title:
+            currentFarmVariety.value == 1
+                ? t("growthReport.advice.foliar.title")
+                : t("growthReport.advice.foliar.titleRice"),
+        description:
+            currentFarmVariety.value == 1
+                ? t("growthReport.advice.foliar.desc")
+                : t("growthReport.advice.foliar.descRice"),
     },
+    // {
+    //     title: t("growthReport.advice.pestControl.title"),
+    //     description: t("growthReport.advice.pestControl.desc"),
+    // },
 ]);
 
-const patrolList = computed(() => [
-    {
-        title: t("growthReport.patrol.process.title"),
-        description: t("growthReport.patrol.process.desc"),
-    },
-    {
-        title: t("growthReport.patrol.growth.title"),
-        description: t("growthReport.patrol.growth.desc"),
-    },
-    {
-        title: t("growthReport.patrol.pest.title"),
-        description: t("growthReport.patrol.pest.desc"),
-    },
-]);
+const patrolList = computed(() => {
+    const isLychee = currentFarmVariety.value == 1;
+    return [
+        {
+            title: t("growthReport.patrol.process.title"),
+            description: isLychee
+                ? t("growthReport.patrol.process.desc")
+                : t("growthReport.patrol.process.descRice"),
+        },
+        {
+            title: t("growthReport.patrol.growth.title"),
+            description: isLychee
+                ? t("growthReport.patrol.growth.desc")
+                : t("growthReport.patrol.growth.descRice"),
+        },
+    ];
+    // {
+    //     title: t("growthReport.patrol.pest.title"),
+    //     description: t("growthReport.patrol.pest.desc"),
+    // },
+});
 //
 const paramsPage = ref({});
 const showBindSuccess = ref(false);
@@ -324,8 +348,17 @@ const handleGardenSelected = (garden) => {
     weatherInfoRef.value?.setSelectedGarden?.(garden);
 };
 
+const currentFarmVariety = ref(null);
+const varietyName = ref(null);
+const currentPhenologyStage = computed(() =>
+    currentFarmVariety.value == 1
+        ? t("growthReport.phenologyFruitExpansion")
+        : t("growthReport.phenologyLateTillering")
+);
 // 切换农场时,更新报告数据
-const changeGarden = async ({ id, name }) => {
+const changeGarden = async ({ id, name,farm_variety,variety_name }) => {
+    currentFarmVariety.value = farm_variety;
+    varietyName.value = variety_name;
     if (!id) return;
     currentFarmName.value = name;
     if (sessionStorage.getItem('activeSwipeIndex')) {
@@ -398,7 +431,7 @@ const handleAddFarm = () => {
 }
 
 const handleHistoryRiskReportClick = () => {
-    router.push("/history_risk_report");
+    router.push("/history_risk_report?farmVariety=" + currentFarmVariety.value + "&currentFarmName=" + currentFarmName.value);
 }
 
 const todayPatrolFocus = ref([]);
@@ -698,7 +731,8 @@ onUnmounted(() => {
         .history-risk-report-btn {
             position: absolute;
             right: 0px;
-            top: 110px;
+            // top: 155px;
+            top: 120px;
             z-index: 13;
             height: 26px;
             padding: 0 10px 0 8px;
@@ -909,7 +943,8 @@ onUnmounted(() => {
 
         .report-header {
             position: relative;
-            padding-top: 148px;
+            // padding-top: 148px;
+            padding-top: 120px;
 
             &.no-farm {
                 padding-top: 102px;

+ 136 - 29
src/views/old_mini/recordDetails/index.vue

@@ -8,7 +8,7 @@
             </div>
             <div class="record-header" v-else-if="recordType === 'pest'">
                 <span>{{ t('agriRecord.pestWorkName') }}</span>
-                <div class="question">{{ t('recordDetails.pestQuestion') }}</div>
+                <div class="question">{{ currentPestDetail?.interaction_reason }}</div>
             </div>
             <div class="record-header" v-else>
                 <span>{{ t('agriRecord.phenologyWorkName') }}</span>
@@ -46,7 +46,7 @@
                         <span class="item-label">{{ t('recordDetails.scienceLabel') }}</span>
                         <text-ellipsis class="item-value" :expand-text="expandCollapse.expand"
                             :collapse-text="expandCollapse.collapse" rows="3"
-                            :content="t('recordDetails.pestScience')" />
+                            :content="currentPestDetail?.kepu" />
                     </div>
                     <div class="pest-classify-picker">
                         <div class="pest-classify-picker__row pest-classify-picker__row--top">
@@ -132,9 +132,13 @@
                             <div class="current-status">{{ currentStatusText }}</div>
                         </div>
                         <div class="time-line">
-                            <GrowthStageTimeline v-model="growthStageIndex" :stages="growthStages"
-                                @scroll-settled="onStageScrollSettled" @locale-change="getFindPhenologyInfo" />
-                            <!-- <GrowthStageTimeline v-model="growthStageIndex" :stages="growthStages" /> -->
+                            <GrowthStageTimeline
+                                :key="phenologyTimelineKey"
+                                v-model="growthStageIndex"
+                                :stages="growthStages"
+                                @scroll-settled="onStageScrollSettled"
+                                @locale-change="getFindPhenologyInfo"
+                            />
                         </div>
                         <div class="confirm-btn-wrap">
                             <uploader @click="handleUploadClick" :before-read="beforeReadUpload" class="upload-wrap"
@@ -492,6 +496,7 @@ const beforeReadUpload = (file) => {
 const curStage = ref({});
 const curCode = ref('')
 function onStageScrollSettled(index, stage, code) {
+    shouldApplyPhenologyDefault.value = false;
     if (stage) curStage.value = stage;
     curCode.value = code ?? stage?.phenophase_code ?? "";
 }
@@ -613,22 +618,129 @@ const handleTabClick = (index) => {
     activeTab.value = index;
 };
 
-/** 生育期进程时间轴:接入接口后可替换为接口数据 */
-/** 不设初值时由 GrowthStageTimeline 默认选中间一档 */
+/**
+ * 物候时间轴默认定位编码(荔枝 crop_type=1:32=果皮速长/5%长果皮)
+ * 注意:farm_risk 的 current_phe_code / 路由 curCode 可能是 33、35 等,与轴上节点不一一对应,勿直接当数组下标用
+ */
+const DEFAULT_PHENOLOGY_CODE = '32';
+
 const growthStageIndex = ref();
 const growthStages = ref([]);
+const phenologyRawList = ref([]);
+const phenologyTimelineKey = ref(0);
+/** 数据加载后按物候编码定位,用户拖动后不再自动覆盖 */
+const shouldApplyPhenologyDefault = ref(true);
+
+function normalizePhenologyCode(code) {
+    if (code == null || code === '') return '';
+    return String(code).trim();
+}
+
+function findStageIndexByPhenophaseCode(stages, code) {
+    const target = normalizePhenologyCode(code);
+    if (!Array.isArray(stages) || !stages.length || !target) return -1;
+    return stages.findIndex(
+        (s) => normalizePhenologyCode(s.phenophase_code) === target
+    );
+}
+
+function resolveStageIndexByPhenophaseCode(stages, rawItems, code) {
+    const target = normalizePhenologyCode(code);
+    if (!target || !Array.isArray(stages) || !stages.length) return -1;
+
+    const byFlat = findStageIndexByPhenophaseCode(stages, target);
+    if (byFlat >= 0) return byFlat;
+
+    const period = (rawItems || []).find(
+        (item) =>
+            normalizePhenologyCode(item.phenophase_code ?? item.phenophaseCode) ===
+            target
+    );
+    if (!period) return -1;
+
+    const milestones = normalizeTimeDescribe(period.time_discribe);
+    const firstLabel = milestones[0]?.label;
+    if (!firstLabel) return -1;
+
+    return stages.findIndex(
+        (s) =>
+            s.label === firstLabel &&
+            normalizePhenologyCode(s.phenophase_code) === target
+    );
+}
+
+function buildGrowthStagesFlat(rawItems) {
+    const flat = [];
+    for (const item of rawItems) {
+        const periodCode =
+            item.phenophase_code ?? item.phenophaseCode ?? '';
+        const milestones = normalizeTimeDescribe(item.time_discribe);
+        for (const t of milestones) {
+            flat.push({
+                label: t.label ?? '',
+                tags: Array.isArray(t.tags) ? t.tags : [],
+                periodTitle: item.phenophase_name ?? '',
+                periodSubtitle: item.phenophase_discribe ?? '',
+                phenophase_code:
+                    t.phenophase_code ??
+                    t.phenophaseCode ??
+                    t.code ??
+                    periodCode,
+            });
+        }
+    }
+    return flat;
+}
+
+/** 时间轴初始定位用的物候编码(与病虫害等接口用的 route.query.curCode 分离) */
+function resolveTimelineDefaultCode() {
+    return DEFAULT_PHENOLOGY_CODE;
+}
+
+function applyTimelineDefaultIndex(flat, rawItems) {
+    const targetCode = resolveTimelineDefaultCode();
+    const defaultIndex = resolveStageIndexByPhenophaseCode(
+        flat,
+        rawItems,
+        targetCode
+    );
+    if (defaultIndex < 0) return -1;
+
+    shouldApplyPhenologyDefault.value = true;
+    growthStageIndex.value = defaultIndex;
+    growthStages.value = flat;
+    phenologyTimelineKey.value += 1;
+
+    return defaultIndex;
+}
 
-/** 与 GrowthStageTimeline 默认档一致:未绑 v-model 时用中间索引 */
 function syncCurStageFromModel() {
     const stages = growthStages.value;
     if (!Array.isArray(stages) || !stages.length) return;
     const n = stages.length;
-    let i = growthStageIndex.value;
-    if (i === undefined || i === null) {
-        i = Math.max(0, Math.floor((n - 1) / 2));
+    let i;
+
+    if (shouldApplyPhenologyDefault.value) {
+        const targetCode = resolveTimelineDefaultCode();
+        const byCode = resolveStageIndexByPhenophaseCode(
+            stages,
+            phenologyRawList.value,
+            targetCode
+        );
+        i = byCode >= 0 ? byCode : Math.max(0, Math.floor((n - 1) / 2));
+        if (byCode >= 0) {
+            growthStageIndex.value = i;
+            shouldApplyPhenologyDefault.value = false;
+        }
     } else {
-        i = Math.min(Math.max(0, i), n - 1);
+        i = growthStageIndex.value;
+        if (i === undefined || i === null) {
+            i = Math.max(0, Math.floor((n - 1) / 2));
+        } else {
+            i = Math.min(Math.max(0, i), n - 1);
+        }
     }
+
     const stage = stages[i];
     if (stage) curStage.value = stage;
     curCode.value = stage?.phenophase_code ?? "";
@@ -636,7 +748,7 @@ function syncCurStageFromModel() {
 
 watch([growthStages, growthStageIndex], syncCurStageFromModel, { immediate: true });
 
-onActivated(() => {
+onActivated(async () => {
     sessionStorage.removeItem('mapManageConfirmPayload');
     syncFormFromMapConfirmPayload();
     if (route.query.workId) {
@@ -648,7 +760,7 @@ onActivated(() => {
     if (route.query.type === 'growth') {
         getGrowthAnomalyInfo();
     }
-    getFindPhenologyInfo()
+    getFindPhenologyInfo();
     if (showMap.value) {
         location.value = "POINT(113.6142086995688 23.585836479509055)";
         indexMap.initMap(location.value, mapContainer.value);
@@ -698,21 +810,16 @@ const getFindPhenologyInfo = async () => {
     const cropType = JSON.parse(localStorage.getItem('selectedFarmData')).farm_variety;
     const res = await VE_API.monitor.getFindPhenologyInfo({ crop_type: cropType });
     if (res.code === 200 && Array.isArray(res.data) && res.data.length) {
-        const flat = [];
-        for (const item of res.data) {
-            const milestones = normalizeTimeDescribe(item.time_discribe);
-            for (const t of milestones) {
-                flat.push({
-                    label: t.label ?? '',
-                    tags: Array.isArray(t.tags) ? t.tags : [],
-                    periodTitle: item.phenophase_name ?? '',
-                    periodSubtitle: item.phenophase_discribe ?? '',
-                    phenophase_code: item.phenophase_code ?? item.phenophaseCode ?? '',
-                });
-            }
-        }
-        if (flat.length) {
-            growthStages.value = flat;
+        phenologyRawList.value = res.data;
+        const flat = buildGrowthStagesFlat(res.data);
+        if (!flat.length) return;
+
+        const defaultIndex = applyTimelineDefaultIndex(flat, res.data);
+        await nextTick();
+        if (defaultIndex >= 0) {
+            growthStageIndex.value = defaultIndex;
+            shouldApplyPhenologyDefault.value = false;
+            syncCurStageFromModel();
         }
     }
 };

+ 61 - 15
src/views/old_mini/work_detail/components/areaMap.js

@@ -32,16 +32,22 @@ class AreaMap {
             style: function (f) {
                 let style2 = vectorStyle.getPolygonStyle("#00000080", "#2199F8", 2)
 
-                let style3 = new Style({
-                    text: new Text({
-                        font: "14px sans-serif",
-                        text: f.get("mianji") ? `${f.get("mianji")}亩` : "",
-                        // offsetX: 28,
-                        offsetY: 10,
-                        fill: new Fill({ color: "#fff" }), // 字体颜色
-                    }),
-                });
-                return [style2]
+                const label = f.get("zone_name") || (f.get("mianji") ? `${f.get("mianji")}亩` : "");
+                const style3 = label
+                    ? new Style({
+                          text: new Text({
+                              font: "14px sans-serif",
+                              text: label,
+                              offsetY: 10,
+                              fill: new Fill({ color: "#fff" }),
+                              stroke: new Stroke({
+                                  color: "#000",
+                                  width: 0.5,
+                              }),
+                          }),
+                      })
+                    : null;
+                return style3 ? [style2, style3] : [style2];
             }
         });
 
@@ -76,7 +82,22 @@ class AreaMap {
     initMap(location, target) {
         let level = 16;
         let coordinate = util.wktCastGeom(location).getFirstCoordinate();
-        this.kmap = new KMap.Map(target, level, coordinate[0], coordinate[1], null, 8, 22);
+        // 详情页仅展示地块:禁用拖拽、滚轮缩放及触摸缩放
+        this.kmap = new KMap.Map(
+            target,
+            level,
+            coordinate[0],
+            coordinate[1],
+            null,
+            8,
+            22,
+            undefined,
+            false,
+            false
+        );
+        if (this.kmap?.map) {
+            this.kmap.map.getInteractions().forEach((i) => i.setActive(false));
+        }
         let xyz2 = config.base_img_url3 + "map/lby/{z}/{x}/{y}.png";
         this.kmap.addXYZLayer(xyz2, { minZoom: 8, maxZoom: 22 }, 2);
         this.kmap.addLayer(this.gardenPolygonLayer.layer);
@@ -84,17 +105,42 @@ class AreaMap {
     }
 
     initLayer(rangeWkt) {
+        if (!rangeWkt) {
+            this.initZones([]);
+            return;
+        }
+        this.initZones([{ zone_geometry: rangeWkt }]);
+    }
+
+    /** @param {{ zone_geometry?: string, zone_name?: string }[]} zones */
+    initZones(zones) {
         if (this.gardenPolygonLayer.source) {
             this.gardenPolygonLayer.source.clear();
         }
         if (this.clickPointLayer.source) {
             this.clickPointLayer.source.clear();
         }
-        if (!rangeWkt) return;
 
-        let f = newAreaFeature({ geomWkt: rangeWkt }, "geomWkt");
-        this.gardenPolygonLayer.source.addFeature(f);
-        this.fitView()
+        const list = Array.isArray(zones) ? zones : [];
+        const seen = new Set();
+
+        list.forEach((zone) => {
+            const wkt =
+                typeof zone?.zone_geometry === "string"
+                    ? zone.zone_geometry.trim()
+                    : "";
+            if (!wkt || seen.has(wkt)) return;
+            seen.add(wkt);
+            try {
+                const f = newAreaFeature({ geomWkt: wkt }, "geomWkt");
+                f.set("zone_name", zone.zone_name ?? "");
+                this.gardenPolygonLayer.source.addFeature(f);
+            } catch (e) {
+                console.warn("[AreaMap] zone_geometry parse failed", e);
+            }
+        });
+
+        this.fitView();
     }
 
     /**

+ 73 - 24
src/views/old_mini/work_detail/index.vue

@@ -142,14 +142,19 @@
                             <div class="map-container" ref="mapContainer"></div>
                         </div>
                         <div class="area-list">
-                            <div class="area-item">
+                            <div
+                                v-for="(zone, zoneIndex) in farmZones"
+                                :key="`${zone.zone_name || 'zone'}-${zoneIndex}`"
+                                class="area-item"
+                            >
                                 <div class="area-l">
-                                    {{ $t('workDetail.ownedPlot') }}{{ farmData.work_time }}
-                                    <span class="area-tag"
-                                        style="background: rgba(55, 193, 27, 0.1); color: #37C11B;">{{ $t('workDetail.verified') }}</span>
-                                    <!-- <span class="area-tag">{{ $t('未激活') }}</span> -->
+                                    {{ zone.zone_name }}
+                                    <span> {{ zone.execute_time }}</span>
+                                    <span
+                                        class="area-tag"
+                                        :style="backgroundFarmWorkStatus(farmData.work_status)"
+                                    >{{ workStatusObj[farmData.work_status] }}</span>
                                 </div>
-                                <!-- <div class="area-r">{{ $t('我已完成') }}</div> -->
                             </div>
                         </div>
                         <!-- <div class="ecological-plant-card">
@@ -316,30 +321,45 @@ const ecologicalPlantThumbUrls = ref([imgFq1, imgFq2]);
 const ecologicalExecutorOrg = computed(
     () => detail.value?.executorOrganizationName || "某某某农资机构"
 );
-const mapData = ref("MULTIPOLYGON(((107.995696309223 24.9716283493399, 107.997730748383 24.9701649808213, 107.997870541717 24.9690287881909, 107.998141205407 24.9672322951316, 107.995761744401 24.9662448188141, 107.994830780282 24.9679461334333, 107.995696309223 24.9716283493399)))")
+const farmData = ref({});
 
 const wktFmt = new WKT();
+const MAP_CENTER_FALLBACK = "POINT(113.1093017627431 22.57454083668)";
 
-/** 从面/多多边形 WKT 取首坐标作为初始中心,initLayer 会 fit 到整块区域 */
-function wktCenterPointFromArea(wkt) {
-    const fallback = "POINT(113.1093017627431 22.57454083668)";
-    if (!wkt || typeof wkt !== "string") return fallback;
-    try {
-        const c = wktFmt.readGeometry(wkt).getFirstCoordinate();
-        return `POINT(${c[0]} ${c[1]})`;
-    } catch {
-        return fallback;
+const farmZones = computed(() => {
+    const zones = farmData.value?.zones;
+    if (!Array.isArray(zones)) return [];
+    return zones.filter(
+        (z) => z && typeof z.zone_geometry === "string" && z.zone_geometry.trim()
+    );
+});
+
+/** 从地块 WKT 取首坐标作为初始中心,initZones 会 fit 到全部地块 */
+function wktCenterPointFromZones(zones) {
+    const list = Array.isArray(zones) ? zones : [];
+    for (const zone of list) {
+        const wkt = zone?.zone_geometry;
+        if (!wkt || typeof wkt !== "string") continue;
+        try {
+            const c = wktFmt.readGeometry(wkt.trim()).getFirstCoordinate();
+            return `POINT(${c[0]} ${c[1]})`;
+        } catch {
+            /* try next zone */
+        }
     }
+    return MAP_CENTER_FALLBACK;
 }
 
-onActivated(() => {
-
+function initWorkDetailMap() {
     nextTick(() => {
         if (!mapContainer.value) return;
-        areaMap.initMap(wktCenterPointFromArea(mapData.value), mapContainer.value);
-        areaMap.initLayer(mapData.value);
+        const zones = farmZones.value;
+        areaMap.initMap(wktCenterPointFromZones(zones), mapContainer.value);
+        areaMap.initZones(zones);
     });
+}
 
+onActivated(() => {
     headerTitle.value = route.query?.title || '返青追肥';
     if (headerTitle.value === '返青追肥') {
         ecologicalPlantThumbUrls.value = [imgFq1, imgFq2]
@@ -357,12 +377,41 @@ onActivated(() => {
     getDetail();
 });
 
-const farmData = ref({})
+const workStatusObj = {
+    0: "待校准",
+    1: "机动执行",
+    2: "待执行",
+    3: "未激活",
+    4: "已认证",
+    5: "已失效",
+    6: "已执行",
+}
+
+const backgroundFarmWorkStatus = (status) => {
+    let background = 'rgba(33, 153, 248, 0.1)';
+    let color = '#2199F8';
+    if (status === 0 || status === 1) {
+        background = 'rgba(255, 149, 61, 0.1)';
+        color = '#FF953D';
+    }else if (status === 4) {
+        background = 'rgba(55, 193, 27, 0.1)';
+        color = '#37C11B';
+    }else if (status === 3 || status === 5) {
+        background = 'rgba(98, 98, 98, 0.1)';
+        color = '#626262';
+    }
+    return {
+        background,
+        color,
+    }
+}
+
 const getDetail = () => {
     if (!route.query.id) return;
     VE_API.monitor.getWorkDetail({ id: route.query.id }).then(res => {
         if (res.code === 200 && res.data.length) {
-            farmData.value = res.data[0]
+            farmData.value = res.data[0];
+            initWorkDetailMap();
         }
     })
     // if (!miniJson.value) return;
@@ -695,13 +744,13 @@ const areaMap = new AreaMap();
         }
     }
 
-    &.status-0 {
+    &.status-5 {
         &::after {
             background: #C7C7C7;
         }
     }
 
-    &.status-1 {
+    &.status-0, &.status-1 {
         &::after {
             background: #FF953D;
         }