Pārlūkot izejas kodu

Merge branch 'farmer' of http://www.sysuimars.cn:3000/feiniao/feiniao-farm-h5 into farmer

wangsisi 2 nedēļas atpakaļ
vecāks
revīzija
9abdd7a662

+ 7 - 0
src/router/globalRoutes.js

@@ -426,6 +426,13 @@ export default [
         meta: { keepAlive: true },
         component: () => import("@/views/old_mini/agri_record/subPages/statusDetail.vue"),
     },
+    // 转发处方页面
+    {
+        path: "/prescription_page",
+        name: "PrescriptionPage",
+        meta: { keepAlive: true },
+        component: () => import("@/views/old_mini/agri_record/subPages/prescriptionPage.vue"),
+    },
     // 农事互动列表
     {
         path: "/interaction_list",

+ 2 - 2
src/utils/map.js

@@ -31,8 +31,8 @@ function filterWktProp(data,key){
     return true
 }
 
-export const newAreaFeature = (data)=>{
-    let geom = new WKT().readGeometry(data["wkt"])
+export const newAreaFeature = (data, fieldGeom)=>{
+    let geom = new WKT().readGeometry(data[fieldGeom || "wkt"])
     let feature = new Feature({
         geometry: geom
     });

+ 124 - 0
src/views/old_mini/agri_record/components/areaMap.js

@@ -0,0 +1,124 @@
+import * as KMap from "@/utils/ol-map/KMap";
+import * as util from "@/common/ol_common.js";
+import config from "@/api/config.js";
+import { Vector as VectorSource } from "ol/source.js";
+import { Point } from 'ol/geom';
+import { newPoint, newAreaFeature } from "@/utils/map";
+import { GeoJSON, WKT } from 'ol/format'
+import { Feature } from "ol";
+import { getArea } from "ol/sphere"
+import * as turf from "@turf/turf"
+import Style from "ol/style/Style";
+import Icon from "ol/style/Icon";
+import { Fill, Text } from "ol/style";
+import * as proj from "ol/proj";
+import proj4 from "proj4"
+import { register } from "ol/proj/proj4";
+proj4.defs("EPSG:38572", "+proj=merc +a=6378137 +b=6378137 +lat_ts=0 +lon_0=0 +x_0=0 +y_0=0 +k=1 +units=m +nadgrids=@null +wktext +no_defs +type=crs");
+register(proj4);
+
+/**
+ *
+ */
+class AreaMap {
+    constructor() {
+        let that = this;
+        let vectorStyle = new KMap.VectorStyle()
+        this.gardenPolygonLayer = new KMap.VectorLayer("gardenPolygonLayer", 999, {
+            minZoom: 11,
+            maxZoom: 22,
+            source: new VectorSource({}),
+            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") + "亩",
+                        // offsetX: 28,
+                        offsetY: 10,
+                        fill: new Fill({ color: "#fff" }), // 字体颜色
+                    }),
+                });
+                return [style2, style3]
+            }
+        });
+
+        // 位置图标
+        this.clickPointLayer = new KMap.VectorLayer("clickPointLayer", 9999, {
+            style: (f) => {
+                return new Style({
+                    image: new Icon({
+                        src: require("@/assets/img/home/garden-point.png"),
+                        scale: 0.5,
+                        anchor: [0.5, 1],
+                    }),
+                });
+            },
+        });
+    }
+
+
+    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);
+        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);
+        this.kmap.addLayer(this.clickPointLayer.layer);
+    }
+
+    initLayer(item) {
+        // this.gardenPolygonLayer.refresh()
+        if (this.gardenPolygonLayer.source) {
+            this.gardenPolygonLayer.source.clear()
+        }
+        if (item.pointWkt) {
+            let f = newPoint(item, "pointWkt")
+            this.clickPointLayer.source.addFeature(f)
+        }
+        if (item.geomWkt) {
+            // let f = new Feature({
+            //     organId: item.organId, // 用于查找点击选中地块的编辑,有多个地块时用id筛选
+            //     geometry: new WKT().readGeometry(item.geomWkt)
+            // })
+            // let geometry = new WKT().readGeometry(item.geomWkt)
+            // geometry.transform(proj.get("EPSG:4326"), proj.get("EPSG:38572"))
+            let f = newAreaFeature(item, "geomWkt")
+            //   let area = getArea(geometry)
+            //   area = (area + area / 2) / 1000;
+            f.set("mianji", item.mianji)
+            this.gardenPolygonLayer.source.addFeature(f)
+        }
+        this.fitView()
+    }
+
+    /**
+   * 调整地图视图以适应地块范围
+   */
+    fitView() {
+        let extent = this.gardenPolygonLayer.source.getExtent()
+        // 地图自适应到区域可视范围
+        this.kmap.getView().fit(extent, { duration: 50, padding: [80, 80, 80, 80] });
+    }
+
+    fitByGardenId(gardenId, hasMapAnimate) {
+        this.gardenPolygonLayer.source.forEachFeature((f) => {
+            if (f.get("organId") == gardenId) {
+                const extent = f.getGeometry().getExtent()
+                this.kmap.getView().fit(extent, { padding: [160, 60, 340, 60], duration: hasMapAnimate ? 1500 : 0 });
+                const currentZoom = this.kmap.getView().getZoom();
+                if (currentZoom > 16) {
+                    // this.kmap.getView().setZoom(16);
+                    this.kmap.getView().animate({
+                        zoom: 16,
+                        duration: hasMapAnimate ? 1500 : 0 // 动画持续时间,单位为毫秒
+                    });
+                }
+            }
+        })
+    }
+}
+
+export default AreaMap;

+ 92 - 0
src/views/old_mini/agri_record/components/mapInfo.vue

@@ -0,0 +1,92 @@
+<template>
+    <div class="map-info">
+        <div class="popup-title" v-if="showTitle">执行区域</div>
+        <div class="map-box">
+            <div class="map" ref="mapContainer"></div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, nextTick, onMounted, watch } from "vue";
+import IndexMap from "@/views/old_mini/home/map/index.js";
+import AreaMap from "./areaMap.js";
+
+const props = defineProps({
+    farmId: {
+        type: [Number, String],
+        default: null,
+    },
+    showTitle: {
+        type: Boolean,
+        default: true,
+    },
+});
+
+const mapContainer = ref(null);
+const indexMap = new IndexMap();
+const areaMap = new AreaMap();
+
+// 加载农场地图信息
+const loadFarmMap = async () => {
+    if (!props.farmId) return;
+
+    try {
+        const res = await VE_API.farm.getFarmDetail({ farmId: props.farmId });
+        if (res.code !== 0 || !res.data) return;
+
+        const farmInfo = res.data;
+        const point = farmInfo.pointWkt;
+        const geometryArr = farmInfo.geomWkt;
+
+        nextTick(() => {
+            // 如果地图已经初始化,则更新中心点和地块;否则初始化地图
+            if (areaMap.kmap) {
+                areaMap.initLayer(farmInfo);
+            } else if (point && mapContainer.value) {
+                areaMap.initMap(point, mapContainer.value);
+                areaMap.initLayer(farmInfo);
+            }
+        });
+    } catch (e) {
+        // 忽略地图加载错误,避免影响主流程
+    }
+};
+
+onMounted(() => {
+    loadFarmMap();
+});
+
+// farmId 变化时重新加载地图
+watch(
+    () => props.farmId,
+    () => {
+        loadFarmMap();
+    }
+);
+</script>
+
+<style lang="scss" scoped>
+.map-info {
+    width: 100%;
+}
+    .popup-title {
+        text-align: center;
+        font-size: 24px;
+        font-family: "PangMenZhengDao";
+        padding-bottom: 12px;
+    }
+
+.map-box {
+    width: 100%;
+    height: 350px;
+    position: relative;
+
+    .map {
+        width: 100%;
+        height: 100%;
+        clip-path: inset(0px round 5px);
+        pointer-events: none;
+    }
+}
+</style>

+ 494 - 0
src/views/old_mini/agri_record/subPages/prescriptionPage.vue

@@ -0,0 +1,494 @@
+<template>
+    <div class="prescription-page">
+        <custom-header name="处方详情" isClose :showClose="false" @goback="handleClose"></custom-header>
+
+        <div class="prescription-content">
+            <div class="card-box content-card">
+                <div class="card-header">
+                    <div class="card-title-wrap">
+                        <div class="card-title">{{ prescriptionData.title }}</div>
+                        <div class="type-tag">{{ prescriptionData.type }}</div>
+                    </div>
+                </div>
+
+                <div class="card-info">
+                    <div class="info-item">
+                        <span class="info-label">下发专家</span>
+                        <span class="info-value">{{ prescriptionData.expert }}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">执行时间</span>
+                        <span class="info-value">{{ prescriptionData.executeTime }}</span>
+                    </div>
+                    <div class="info-item">
+                        <span class="info-label">施用方式</span>
+                        <span class="info-value">{{ prescriptionData.applyMethod }}</span>
+                    </div>
+                </div>
+            </div>
+
+            <!-- 处方详情 -->
+            <div class="card-box prescription-card mt-10">
+                <div class="card-header">
+                    <div class="card-title">
+                        药物处方
+                    </div>
+                </div>
+
+                <!-- <div class="table-item">
+                    <div class="form-item">
+                        <div class="item-name">施用方式</div>
+                        <div class="item-text">{{ detailData?.usageMode || '其他' }}</div>
+                    </div>
+                    <div class="form-item">
+                        <div class="item-name">执行方式</div>
+                        <div class="item-text">
+                            {{ quotationData?.executionMethodName }}
+                        </div>
+                    </div>
+                </div> -->
+                <div class="new-wrap"
+                    v-if="detailData?.prescriptionList?.length && detailData?.prescriptionList[0]?.pesticideFertilizerList?.length > 0">
+                    <div class="new-title">
+                        <div class="title-1">
+                            <div class="table-name">药肥类型</div>
+                        </div>
+                        <div class="title-2">
+                            <div class="table-name">药肥名称</div>
+                        </div>
+                        <div class="title-4">
+                            <div class="table-name">药肥配比</div>
+                        </div>
+                        <div class="title-5">
+                            <div class="table-name">单亩用量</div>
+                        </div>
+                    </div>
+                    <div class="new-table-wrap"
+                        v-for="(prescriptionItem, prescriptionI) in detailData?.prescriptionList" :key="prescriptionI">
+                        <div class="new-prescription" v-for="(subP, subI) in prescriptionItem.pesticideFertilizerList"
+                            :key="subI">
+                            <div class="new-table">
+                                <div class="line-l">
+                                    <div class="line-1 title-1">{{ subP.typeName }}</div>
+                                    <div class="line-2">{{ subP.defaultName || subP.pesticideFertilizerName }}</div>
+                                </div>
+                                <div class="line-r">
+                                    <div class="line-3">
+                                        <div class="sub-line title-4">{{ quotationData.executionMethod === 1 ?
+                                            subP.ratio2 : subP.ratio }}倍</div>
+                                        <div class="sub-line title-5">{{ quotationData.executionMethod === 1 ?
+                                            subP.muUsage2 : subP.muUsage }}{{ subP.unit }}</div>
+                                    </div>
+                                </div>
+                            </div>
+                            <div class="note-text" v-if="subP.remark">{{ subP.remark }}</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+            <!-- 执行区域 -->
+            <div class="card-box area-card mt-10">
+                <div class="card-header">
+                    <div class="card-title">
+                        执行区域
+                    </div>
+                </div>
+                <div class="card-content">
+                    <map-info :farm-id="farmId" :show-title="false" />
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script setup>
+import { ref, onMounted } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import customHeader from "@/components/customHeader.vue";
+import MapInfo from "@/views/old_mini/agri_record/components/mapInfo.vue";
+
+const router = useRouter();
+const route = useRoute();
+
+const prescriptionData = ref({
+    title: "秋梢防虫",
+    type: "标准农事",
+    expert: "韦帮稳",
+    executeTime: "2025.02.18",
+    applyMethod: "内膛喷施",
+});
+
+const farmId = ref(94500);
+
+onMounted(() => {
+});
+
+const handleClose = () => {
+    router.go(-1);
+};
+
+const handleViewPrescription = () => {
+    // 查看药物处方逻辑
+    // TODO: 实现查看药物处方功能
+};
+
+const handleViewArea = () => {
+    // 查看执行区域逻辑
+    // TODO: 实现查看执行区域功能
+};
+
+const quotationData = ref(
+    {
+        "executionMethodName": "地面喷施",
+        "executionMethod": 1,
+    }
+);
+
+const detailData = ref(
+    {
+        "consequenceText": "",
+        "id": "280962",
+        "reCheckText": "",
+        "orderId": "801082980008202240",
+        "farmWorkArrangeId": "11272",
+        "farmName": "荔枝博览园",
+        "farmPoint": "POINT(113.61702297075017 23.584863449735067)",
+        "area": 300,
+        "expert": "739294587868155904",
+        "orderStatus": 0,
+        "activeStatus": null,
+        "flowStatus": 5,
+        "farmId": 766,
+        "regionId": null,
+        "farmMiniUserId": 90739,
+        "farmMiniUserName": "",
+        "speciesId": "1",
+        "speciesName": "荔枝",
+        "agriculturalId": 214,
+        "agriculturalIcon": "",
+        "farmWorkId": "801074109092990976",
+        "farmWorkLibId": "801074109092990976",
+        "farmWorkLibName": "冬季防治(地面)",
+        "farmWorkName": "冬季防治(地面)",
+        "expertName": "飞鸟种植助手",
+        "expertUserName": "飞鸟种植助手",
+        "expertIcon": "https://birdseye-img-ali-cdn.sysuimars.com//expert/1757473957076.png",
+        "expertUserIcon": "https://birdseye-img-ali-cdn.sysuimars.com//expert/1757473957076.png",
+        "icon": null,
+        "indexName": "",
+        "indexChart": [],
+        "executeDate": "2026-01-19",
+        "executeDeadlineDate": "2026-01-19",
+        "expectedExecuteDate": "2026-01-19",
+        "finishDate": null,
+        "checkDate": null,
+        "beforeExecuteDate": null,
+        "indexJson": "",
+        "expertPrescription": "",
+        "code": "801074109080408065",
+        "condition": "",
+        "solarName": "",
+        "reCheck": 1,
+        "menu": 1,
+        "num": null,
+        "purpose": "",
+        "type": 1,
+        "farmWorkType": 3,
+        "farmWorkTypeName": "病虫",
+        "execute": 3,
+        "updateDate0": "2026-01-19",
+        "updateDate1": null,
+        "updateDate2": null,
+        "updateDate3": null,
+        "updateDate4": null,
+        "updateDate5": null,
+        "updateDate6": null,
+        "confirmPicture": [],
+        "executeEvidence": [
+            "birdseye-look-mini/94379/1768801082504.png",
+            "birdseye-look-mini/94379/1768801086136.png"
+        ],
+        "reviewImage": [],
+        "reviewImage2": [],
+        "reviewDate": null,
+        "reviewDate2": null,
+        "serviceRegion": "广州市从化区荔枝博览园",
+        "usageMode": "地面喷施",
+        "serviceMain": "数域行",
+        "executeMain": "数域行",
+        "storeShortName": "",
+        "weatherWarningMsg": "",
+        "userEvaluation": null,
+        "executeBlueZones": [],
+        "isMaster": null,
+        "isEdit": 0,
+        "selfExec": null,
+        "defaultFarmWork": 1,
+        "isPublic": 0,
+        "prescriptionList": [
+            {
+                "name": "病虫",
+                "pesticideFertilizerList": [
+                    {
+                        "defaultName": "",
+                        "id": null,
+                        "muPrice": 1,
+                        "muUsage": 20,
+                        "muUsage2": 20,
+                        "price": "",
+                        "ratio": 1000,
+                        "ratio2": 100,
+                        "remark": "",
+                        "usageMode": "",
+                        "usageModeList": [
+                            "叶面施"
+                        ],
+                        "pesticideFertilizerCode": "1522",
+                        "pesticideFertilizerId": "776945747475042304",
+                        "pesticideFertilizerName": "5%高氯·甲维盐微乳剂",
+                        "brand": "默认品牌",
+                        "typeName": "胃毒性",
+                        "unit": "ml"
+                    }
+                ]
+            }
+        ],
+        "needReview": 0,
+        "conditionList": [],
+        "actualAgriculturalInput": null,
+        "actualFarmServiceInput": null,
+        "actualTotalInput": 996,
+        "executeName": "张扬",
+        "executorIcon": "https://birdseye-img.sysuimars.com/dinggou-mini/defalut-icon.png",
+        "executorUserId": 94379
+    }
+);
+</script>
+
+<style lang="scss" scoped>
+.prescription-page {
+    height: 100vh;
+    width: 100%;
+    background: #f2f3f5;
+
+    .prescription-content {
+        height: calc(100% - 44px);
+        overflow: auto;
+        box-sizing: border-box;
+        padding: 12px;
+    }
+}
+
+.mt-10 {
+    margin-top: 10px;
+}
+
+.card-box {
+    background: #fff;
+    border-radius: 8px;
+    padding: 12px 10px 16px 10px;
+
+    .card-header {
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        margin-bottom: 8px;
+
+        .card-title {
+            font-size: 16px;
+            font-weight: bold;
+            color: #000;
+            margin-right: 5px;
+        }
+
+        .card-title-wrap {
+            display: flex;
+            align-items: center;
+            flex: 1;
+
+
+            .type-tag {
+                font-size: 12px;
+                padding: 0 10px;
+                color: #000000;
+                background: rgba(119, 119, 119, 0.1);
+                border-radius: 20px;
+                font-weight: normal;
+                height: 26px;
+                line-height: 26px;
+            }
+        }
+    }
+}
+
+.content-card {
+    .card-info {
+        padding-top: 12px;
+        border-top: 1px solid #f5f5f5;
+
+        .info-item {
+            display: flex;
+            align-items: center;
+            font-size: 14px;
+            color: #767676;
+            height: 24px;
+
+            .info-label {
+                width: 80px;
+                color: rgba(0, 0, 0, 0.2);
+            }
+
+            .info-value {
+                flex: 1;
+                color: #767676;
+            }
+        }
+    }
+
+    .card-actions {
+        display: flex;
+        gap: 8px;
+        margin-top: 6px;
+
+        .action-btn {
+            padding: 0 16px;
+            height: 32px;
+            line-height: 32px;
+            text-align: center;
+            background: #f7f8fa;
+            color: #4e5969;
+            font-size: 14px;
+            cursor: pointer;
+        }
+    }
+}
+
+
+
+.new-wrap {
+    margin-top: 12px;
+    border-radius: 5px;
+    text-align: center;
+    border: 1px solid rgba(225, 225, 225, 0.5);
+
+    .new-title {
+        background: rgba(241, 241, 241, 0.4);
+        border-radius: 5px 5px 0 0;
+        border-bottom: 1px solid rgba(225, 225, 225, 0.5);
+        display: flex;
+        color: #767676;
+        // justify-content: space-around;
+        padding: 5px 6px;
+        font-size: 12px;
+
+        .table-name {
+            width: 24px;
+            font-size: 12px;
+            margin: 0 auto;
+        }
+    }
+
+    .title-1 {
+        width: 46px;
+    }
+
+    .title-2 {
+        flex: 1;
+    }
+
+    .title-3 {
+        width: 52px;
+    }
+
+    .title-4 {
+        width: 56px;
+    }
+
+    .title-5 {
+        width: 52px;
+    }
+
+    .new-table-wrap {
+        .new-prescription {
+            .new-table {
+                height: 45px;
+                display: flex;
+                align-items: center;
+                background: #fff;
+                border-radius: 5px;
+                color: rgba(0, 0, 0, 0.6);
+                font-size: 11px;
+
+                .line-l {
+                    display: flex;
+                    flex: 1;
+
+                    .line-2 {
+                        flex: 1;
+                        padding: 0 2px;
+                    }
+                }
+
+                .line-r {
+                    &.has-border {
+                        border-left: 1px solid rgba(225, 225, 225, 0.8);
+                    }
+
+                    .line-3 {
+                        display: flex;
+                        align-items: center;
+                    }
+
+                    .sub-line {
+                        padding: 10px 0;
+                    }
+
+                    .line-4 {
+                        display: flex;
+                        align-items: center;
+                        border-top: 1px solid rgba(225, 225, 225, 0.8);
+                    }
+
+                    .execute-line {
+                        border-right: 1px solid rgba(225, 225, 225, 0.8);
+                    }
+                }
+            }
+
+            .note-text {
+                margin: 8px 0 4px 0;
+                color: rgba(0, 0, 0, 0.4);
+                background: #fff;
+                padding: 6px 8px;
+                border-radius: 5px;
+                text-align: left;
+                font-size: 11px;
+            }
+        }
+
+        .new-prescription+.new-prescription {
+            .new-table {
+                border-top: 1px solid rgba(0, 0, 0, 0.08);
+            }
+        }
+    }
+}
+
+.form-item {
+    display: flex;
+    align-items: center;
+    font-size: 14px;
+    color: #767676;
+    height: 24px;
+
+    .item-name {
+        width: 80px;
+        color: rgba(0, 0, 0, 0.2);
+    }
+}
+
+.form-item+.form-item {
+    padding-top: 2px;
+}
+</style>

+ 124 - 25
src/views/old_mini/agri_record/subPages/statusDetail.vue

@@ -23,8 +23,8 @@
                 <div class="card-box content-card">
                     <div class="card-header">
                         <div class="card-title-wrap">
-                            <div class="card-title">秋梢防虫</div>
-                            <div class="type-tag">标准农事</div>
+                            <div class="card-title">{{ prescriptionData.title }}</div>
+                            <div class="type-tag">{{ prescriptionData.type }}</div>
                         </div>
                         <div class="forward-link" @click="handleForward">转发处方</div>
                     </div>
@@ -32,15 +32,15 @@
                     <div class="card-info">
                         <div class="info-item">
                             <span class="info-label">下发专家</span>
-                            <span class="info-value">韦帮稳</span>
+                            <span class="info-value">{{ prescriptionData.expert }}</span>
                         </div>
                         <div class="info-item">
                             <span class="info-label">执行时间</span>
-                            <span class="info-value">2025.02.18</span>
+                            <span class="info-value">{{ prescriptionData.executeTime }}</span>
                         </div>
                         <div class="info-item">
                             <span class="info-label">施用方式</span>
-                            <span class="info-value">内膛喷施</span>
+                            <span class="info-value">{{ prescriptionData.applyMethod }}</span>
                         </div>
                     </div>
 
@@ -79,8 +79,8 @@
                         <div class="forward-link" @click="handleShowQrCodePopup(1)">邀请拍照</div>
                     </div>
                     <div class="exe-upload">
+                        <img @click="showExample" class="example" src="@/assets/img/home/example-4.png" alt="" />
                         <upload ref="uploadRef" exampleImg class="upload-wrap" @handleUpload="handleUpload">
-                            <img class="example" src="@/assets/img/home/example-4.png" alt="" />
                             <img class="example" src="@/assets/img/home/plus.png" alt="" />
                         </upload>
                     </div>
@@ -101,7 +101,7 @@
                             <img class="example" src="@/assets/img/home/plus.png" alt="" />
                         </upload>
                     </div>
-                    <div class="no-text">暂未检测到拍照</div>
+                    <div class="no-text">暂未检测到工人执行</div>
                 </div>
             </div>
         </div>
@@ -115,46 +115,111 @@
                 <div class="text-wrap">
                     <div class="qr-code-text">
                         此二维码为
-                        <span v-if="qrCodeType === 1"><span class="work-name">梢期杀虫</span> 执行码</span>
-                        <span v-if="qrCodeType === 2"><span class="work-name">梢期杀虫</span> 上传执行照片邀请码</span>
+                        <span v-if="qrCodeType === 1"><span class="work-name">梢期杀虫</span> 上传执行照片邀请码</span>
+                        <span v-if="qrCodeType === 2"><span class="work-name">梢期杀虫</span> 执行码</span>
                     </div>
                     <div class="qr-code-text">有效期:2025.07.15之前</div>
                 </div>
                 <div class="code-tips">&lt;&lt;长按二维码保存或转发&gt;&gt;</div>
             </div>
         </popup>
+
+        <!-- 执行区域地图弹窗 -->
+        <popup v-model:show="showMapPopup" closeable class="map-popup">
+            <map-info :farm-id="farmId" />
+        </popup>
+
+        <!-- 处方卡片 -->
+        <detail-dialog ref="detailDialogRef" />
+
+        <!-- 示例照片 -->
+        <popup v-model:show="showExamplePopup" overlay-class="example-overlay" class="example-popup">
+            <div class="example-content">
+                <!-- <img src="@/assets/img/home/example-4.png" alt="" /> -->
+                <img class="example-img" src="https://birdseye-img-ali-cdn.sysuimars.com/birdseye-look-mini/94379/1768801082504.png" alt="" />
+                <div class="example-tips">
+                    拍摄要求:请采集代表农场作物物候期的照片,请采集代表农场作物物候期的照片。
+                </div>
+            </div>
+        </popup>
     </div>
 </template>
 
 <script setup>
-import { useRouter } from "vue-router";
+import { useRouter, useRoute } from "vue-router";
+import { showSuccessToast } from 'vant';
+import { ElMessage } from "element-plus";
 import { ref } from "vue";
 import customHeader from "@/components/customHeader.vue";
 import { Warning } from "@element-plus/icons-vue";
 import upload from "@/components/upload";
+import detailDialog from "@/components/detailDialog.vue";
+import MapInfo from "@/views/old_mini/agri_record/components/mapInfo.vue";
 import { Popup } from "vant";
 
 const router = useRouter();
+const route = useRoute();
 
 const status = ref(1);
 
+// 处方数据(可以从接口获取或从路由参数获取)
+const prescriptionData = ref({
+    id: 280962,
+    title: "秋梢防虫",
+    type: "标准农事",
+    expert: "韦帮稳",
+    executeTime: "2025.02.18",
+    applyMethod: "内膛喷施",
+});
+
 const handleClose = () => {
     router.go(-1);
 };
 
-const handleForward = () => {
-    // 转发处方逻辑
-    // TODO: 实现转发处方功能
+const handleForward = async () => {
+    // 转发处方:复制处方链接到剪贴板
+    const url = `${window.location.origin}/#/prescription_page?id=${prescriptionData.value.id}`;
+
+    try {
+        if (navigator.clipboard && navigator.clipboard.writeText) {
+            await navigator.clipboard.writeText(url);
+            // showSuccessToast('复制成功');
+            ElMessage.success('复制成功');
+        } else {
+            // 兼容不支持 clipboard API 的环境
+            const textarea = document.createElement("textarea");
+            textarea.value = url;
+            textarea.style.position = "fixed";
+            textarea.style.opacity = "0";
+            document.body.appendChild(textarea);
+            textarea.select();
+            document.execCommand("copy");
+            document.body.removeChild(textarea);
+        }
+    } catch (e) {
+        // 复制失败时不抛出错误,避免影响主流程
+    }
 };
 
+const detailDialogRef = ref(null);
 const handleViewPrescription = () => {
-    // 查看药物处方逻辑
-    // TODO: 实现查看药物处方功能
+    // 查看药物处方
+    detailDialogRef.value.showDialog('801074109092990976', "", false);
 };
 
+// 执行区域地图
+const showMapPopup = ref(false);
+// TODO: 根据实际数据来源设置 farmId,比如从接口详情或路由参数中获取
+const farmId = ref(94500);
+
 const handleViewArea = () => {
-    // 查看执行区域逻辑
-    // TODO: 实现查看执行区域功能
+    // 查看执行区域:弹出地图信息
+    showMapPopup.value = true;
+};
+
+const showExamplePopup = ref(false);
+const showExample = () => {
+    showExamplePopup.value = true;
 };
 
 const uploadRef = ref(null);
@@ -353,15 +418,13 @@ const handleShowQrCodePopup = (type) => {
 
     .exe-upload {
         padding-top: 4px;
+        display: flex;
+        align-items: center;
 
-        .upload-wrap {
-            .example {
-                width: 80px;
-                height: 80px;
-            }
-            .example + .example {
-                margin-left: 12px;
-            }
+        .example {
+            width: 80px;
+            height: 80px;
+            margin-right: 12px;
         }
     }
 
@@ -412,4 +475,40 @@ const handleShowQrCodePopup = (type) => {
         }
     }
 }
+
+.map-popup {
+    width: 92%;
+    // max-width: 420px;
+    border-radius: 8px;
+    padding: 12px;
+    box-sizing: border-box;
+}
+
+.example-popup {
+    width: 100%;
+    border-radius: 0;
+    background: none;
+    max-width: 100%;
+    .example-content {
+        text-align: center;
+        .example-img {
+            width: 100%;
+        }
+    }
+    .example-tips {
+        margin: 16px 12px 6px 12px;
+        background: #3d3d3d;
+        padding: 8px 10px;
+        border-radius: 4px;
+        backdrop-filter: blur(4px);
+        color: #fff;
+        font-size: 14px;
+        line-height: 21px;
+        text-align: left;
+    }
+}
+.example-overlay {
+    background: rgba(0, 0, 0, 0.6);
+    backdrop-filter: blur(8px);
+}
 </style>

+ 1 - 10
src/views/old_mini/home/map/index.js

@@ -37,15 +37,6 @@ class IndexMap {
     this.kmap.addLayer(this.clickPointLayer.layer);
     let point = new Feature(new Point(coordinate))
     this.clickPointLayer.addFeature(point)
-
-    this.kmap.on("singleclick", (evt) => {
-          // that.kmap.map.forEachFeatureAtPixel(evt.pixel, function (feature, layer) {
-          //   if ( layer instanceof VectorLayer && layer.get("name") === "reportPolygonLayer" ) {
-          //     areaId.data = feature.get("id")
-          //   }
-          // });
-          console.log('evt.coordinate', evt.coordinate);
-        });
   }
 
   /**
@@ -83,7 +74,7 @@ class IndexMap {
     geometryArr.map(item => {
       that.kmap.setLayerWkt(item)
     })
-    this.fitView()
+    // this.fitView()
   }
 
   /**