|
|
@@ -2,134 +2,96 @@
|
|
|
<div class="record-wrap">
|
|
|
<custom-header :name="t('recordDetails.workName')"></custom-header>
|
|
|
<div class="record-content">
|
|
|
- <div class="record-header" v-if="recordType === 'growth'">
|
|
|
- <span>{{ t('agriRecord.growthWorkName') }}</span>
|
|
|
- <div class="question">{{ currentGrowthAnomalyDetail?.interact_question }}</div>
|
|
|
- </div>
|
|
|
- <div class="record-header" v-else-if="recordType === 'pest'">
|
|
|
- <span>{{ t('agriRecord.pestWorkName') }}</span>
|
|
|
- <div class="question">{{ currentPestDetail?.interaction_reason }}</div>
|
|
|
- </div>
|
|
|
- <div class="record-header" v-else>
|
|
|
- <span>{{ t('agriRecord.phenologyWorkName') }}</span>
|
|
|
- <div class="question">{{ workDetail.interaction_issue }}</div>
|
|
|
+ <div class="record-header">
|
|
|
+ <span>{{ t(recordHeaderInfo.titleKey) }}</span>
|
|
|
+ <div class="question">{{ recordHeaderInfo.question }}</div>
|
|
|
</div>
|
|
|
<div class="record-body">
|
|
|
- <div class="card-wrap" v-if="recordType === 'growth'">
|
|
|
- <div class="card-item">
|
|
|
- <span class="item-label">{{ t('recordDetails.scienceLabel') }}</span>
|
|
|
- <text-ellipsis class="item-value" :expand-text="expandCollapse.expand"
|
|
|
- :collapse-text="expandCollapse.collapse" rows="3"
|
|
|
- :content="currentGrowthAnomalyDetail?.agri_judgment" />
|
|
|
- </div>
|
|
|
- <div class="tabs-list" v-if="!showMap">
|
|
|
- <div class="item-tab" :class="{ 'item-tab--active': activeGrowthAnomalyIndex === index }"
|
|
|
- v-for="(item, index) in growthAnomalyTabs" :key="index"
|
|
|
- @click="handleGrowthAnomalyTabClick(index)">{{ item.label }}
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="card-item">
|
|
|
- <span class="item-label">{{ t('recordDetails.phenotypeLabel') }}</span>
|
|
|
- <text-ellipsis class="item-value" :expand-text="expandCollapse.expand"
|
|
|
- :collapse-text="expandCollapse.collapse" rows="3"
|
|
|
- :content="currentGrowthAnomalyDetail?.phenotype" />
|
|
|
- </div>
|
|
|
- <div class="card-item">
|
|
|
- <span class="item-label">{{ t('recordDetails.highRiskLabel') }}</span>
|
|
|
- <text-ellipsis class="item-value" :expand-text="expandCollapse.expand"
|
|
|
- :collapse-text="expandCollapse.collapse" rows="3"
|
|
|
- :content="currentGrowthAnomalyDetail?.patrol_points" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="card-wrap" v-else-if="recordType === 'pest'">
|
|
|
+ <div class="card-wrap">
|
|
|
<div class="card-item">
|
|
|
- <span class="item-label">{{ t('recordDetails.scienceLabel') }}</span>
|
|
|
- <text-ellipsis class="item-value" :expand-text="expandCollapse.expand"
|
|
|
- :collapse-text="expandCollapse.collapse" rows="3"
|
|
|
- :content="currentPestDetail?.kepu" />
|
|
|
+ <span class="item-label">{{ t(`recordDetails.${leadDetailField.labelKey}`) }}</span>
|
|
|
+ <text-ellipsis class="item-value" v-bind="textEllipsisBind"
|
|
|
+ :content="leadDetailField.content" />
|
|
|
</div>
|
|
|
- <div class="phenology-tip-banner" v-if="recordType !== 'phenology'">
|
|
|
+ <div v-if="recordType === 'pest'" class="phenology-tip-banner">
|
|
|
<div class="banner__left">
|
|
|
<div class="banner__title">
|
|
|
- <el-icon size="17">
|
|
|
- <WarningFilled />
|
|
|
- </el-icon>
|
|
|
<span>{{ t('recordDetails.abnormalBanner') }}</span>
|
|
|
</div>
|
|
|
- <span class="banner__desc">
|
|
|
- {{ t('recordDetails.abnormalBannerDesc') }}
|
|
|
- </span>
|
|
|
+ <span class="banner__desc">{{ t('recordDetails.abnormalBannerDesc') }}</span>
|
|
|
</div>
|
|
|
- <!-- <div class="banner__btn" @click="goPartitionManage">
|
|
|
- 分区管理
|
|
|
- </div> -->
|
|
|
<div class="banner__btn" @click="handleAbnormalRecord">
|
|
|
- {{ t('recordDetails.abnormalRecord') }}
|
|
|
+ <el-icon size="17">
|
|
|
+ <CameraFilled />
|
|
|
+ </el-icon>
|
|
|
+ <span>{{ t('recordDetails.abnormalRecord') }}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="pest-classify-picker">
|
|
|
- <div class="pest-classify-picker__row pest-classify-picker__row--top aaa">
|
|
|
- <div v-for="(label, i) in pestTopLabels" :key="'top-' + i"
|
|
|
- class="pest-classify-picker__top-btn"
|
|
|
- :class="{ 'pest-classify-picker__top-btn--active': pestTopIndex === i }"
|
|
|
- @click="handlePestTopClick(i)">{{ label }}</div>
|
|
|
+ <div v-if="recordType === 'growth' && !showMap" class="tabs-list">
|
|
|
+ <div v-for="(item, index) in growthAnomalyTabs" :key="index" class="item-tab"
|
|
|
+ :class="{ 'item-tab--active': activeGrowthAnomalyIndex === index }"
|
|
|
+ @click="handleGrowthAnomalyTabClick(index)">{{ item.label }}</div>
|
|
|
+ </div>
|
|
|
+ <template v-if="recordType !== 'pest'">
|
|
|
+ <div v-for="field in trailDetailFields" :key="field.labelKey" class="card-item">
|
|
|
+ <span class="item-label">{{ t(`recordDetails.${field.labelKey}`) }}</span>
|
|
|
+ <text-ellipsis class="item-value" v-bind="textEllipsisBind" :content="field.content" />
|
|
|
+ </div>
|
|
|
+ <div v-if="recordType === 'phenology'" class="phenology-tip-banner blue">
|
|
|
+ <div class="banner__left">
|
|
|
+ <div class="banner__title">{{ t('recordDetails.partitionBannerTitle') }}</div>
|
|
|
+ <span class="banner__desc">{{ t('recordDetails.partitionBannerDesc') }}</span>
|
|
|
+ </div>
|
|
|
+ <div class="banner__btn" @click="goPartitionManage">
|
|
|
+ {{ t('recordDetails.partitionManage') }}
|
|
|
+ </div>
|
|
|
</div>
|
|
|
- <div class="pest-classify-picker__row pest-classify-picker__row--grid4">
|
|
|
+ </template>
|
|
|
+ </div>
|
|
|
+ <div v-if="recordType === 'pest'" class="pest-classify-picker">
|
|
|
+ <div class="pest-classify-picker__tabs" ref="pestTabsRef">
|
|
|
+ <div v-for="(label, i) in pestTopLabels" :key="'top-' + i" :ref="(el) => setPestTabRef(el, i)"
|
|
|
+ class="pest-classify-picker__tab"
|
|
|
+ :class="{ 'pest-classify-picker__tab--active': pestTopIndex === i }"
|
|
|
+ @click="handlePestTopClick(i)">{{ label }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="pest-classify-picker__panel" ref="pestPanelRef"
|
|
|
+ :style="{ '--arrow-left': `${pestPanelArrowLeft}px` }">
|
|
|
+ <div class="pest-classify-picker__categories">
|
|
|
<div v-for="(item, i) in pestCategoryLabels" :key="'cat-' + item.value"
|
|
|
- class="pest-classify-picker__chip pest-classify-picker__chip--solid"
|
|
|
- :class="{ 'pest-classify-picker__chip--solid-active': pestCategoryIndex === i }"
|
|
|
+ class="pest-classify-picker__category"
|
|
|
+ :class="{ 'pest-classify-picker__category--active': pestCategoryIndex === i }"
|
|
|
@click="handlePestCategoryClick(i)">{{ item.label }}</div>
|
|
|
</div>
|
|
|
- <div class="pest-classify-picker__row pest-classify-picker__row--grid4 bbb">
|
|
|
+ <div class="pest-classify-picker__details">
|
|
|
<div v-for="(item, i) in pestDetailLabels" :key="'det-' + item.value"
|
|
|
- class="pest-classify-picker__chip pest-classify-picker__chip--soft"
|
|
|
- :class="{ 'pest-classify-picker__chip--soft-active': pestDetailIndex === i }"
|
|
|
- @click="handlePestDetailClick(i)">{{ item.label }}</div>
|
|
|
+ class="pest-classify-picker__detail"
|
|
|
+ :class="{ 'pest-classify-picker__detail--active': pestDetailIndex === i }"
|
|
|
+ @click="handlePestDetailClick(i)">
|
|
|
+ <span v-if="item.risk_level > 0" class="pest-classify-picker__badge"
|
|
|
+ :class="`pest-classify-picker__badge--${item.risk_level}`">
|
|
|
+ {{ t('agriRecord.riskLevel', { level: item.risk_level }) }}
|
|
|
+ </span>
|
|
|
+ <span class="pest-classify-picker__detail-text">{{ item.label }}</span>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="card-item">
|
|
|
- <span class="item-label">{{ t('recordDetails.phenotypeLabel') }}</span>
|
|
|
- <text-ellipsis class="item-value" :expand-text="expandCollapse.expand"
|
|
|
- :collapse-text="expandCollapse.collapse" rows="3" :content="currentPestDetail?.phenotype" />
|
|
|
- </div>
|
|
|
- <div class="card-item">
|
|
|
- <span class="item-label">{{ t('recordDetails.highRiskLabel') }}</span>
|
|
|
- <text-ellipsis class="item-value" :expand-text="expandCollapse.expand"
|
|
|
- :collapse-text="expandCollapse.collapse" rows="3"
|
|
|
- :content="currentPestDetail?.patrol_points" />
|
|
|
- </div>
|
|
|
</div>
|
|
|
- <div class="card-wrap" v-else>
|
|
|
- <div class="card-item">
|
|
|
- <span class="item-label">{{ t('recordDetails.farmAnalysisLabel') }}</span>
|
|
|
- <text-ellipsis class="item-value" :expand-text="expandCollapse.expand"
|
|
|
- :collapse-text="expandCollapse.collapse" rows="3"
|
|
|
- :content="workDetail.crop_condition_analysis" />
|
|
|
- </div>
|
|
|
- <div class="card-item">
|
|
|
- <span class="item-label">{{ t('recordDetails.patrolLabel') }}</span>
|
|
|
- <text-ellipsis class="item-value" :expand-text="expandCollapse.expand"
|
|
|
- :collapse-text="expandCollapse.collapse" rows="3"
|
|
|
- :content="workDetail.inspection_keypoints" />
|
|
|
- </div>
|
|
|
- <div class="card-item">
|
|
|
- <span class="item-label">{{ t('recordDetails.phenotypeLabel') }}</span>
|
|
|
- <text-ellipsis class="item-value" :expand-text="expandCollapse.expand"
|
|
|
- :collapse-text="expandCollapse.collapse" rows="3"
|
|
|
- :content="workDetail.phenotypic_characteristics" />
|
|
|
- </div>
|
|
|
- <div class="phenology-tip-banner blue" v-if="recordType === 'phenology'">
|
|
|
- <div class="banner__left">
|
|
|
- <div class="banner__title">{{ $t('物候不整齐?') }}</div>
|
|
|
- <span class="banner__desc">
|
|
|
- 如果区域长势不同,会降低病虫害防治功效,
|
|
|
- 建议根据长势拆分区域,进行分区精细管理,
|
|
|
- 达到减药减肥的目的
|
|
|
- </span>
|
|
|
- </div>
|
|
|
- <div class="banner__btn" @click="goPartitionManage">
|
|
|
- 分区管理
|
|
|
+ <div v-if="recordType === 'pest'" class="card-wrap pest-detail-card">
|
|
|
+ <div v-for="field in trailDetailFields" :key="field.labelKey" class="card-item"
|
|
|
+ :class="{ 'card-item--phenotype': field.image }">
|
|
|
+ <div v-if="field.image" class="card-item__phenotype">
|
|
|
+ <div class="card-item__phenotype-content">
|
|
|
+ <span class="item-label">{{ t(`recordDetails.${field.labelKey}`) }}</span>
|
|
|
+ <text-ellipsis class="item-value" v-bind="textEllipsisBind" :content="field.content" />
|
|
|
+ </div>
|
|
|
+ <img class="card-item__phenotype-image" :src="field.image" alt=""
|
|
|
+ @click="handlePhenotypeImagePreview(field.image)" />
|
|
|
</div>
|
|
|
+ <template v-else>
|
|
|
+ <span class="item-label">{{ t(`recordDetails.${field.labelKey}`) }}</span>
|
|
|
+ <text-ellipsis class="item-value" v-bind="textEllipsisBind" :content="field.content" />
|
|
|
+ </template>
|
|
|
</div>
|
|
|
</div>
|
|
|
<!-- <div class="tabs-list" v-if="showMap">
|
|
|
@@ -164,20 +126,17 @@
|
|
|
<div class="current-status">{{ currentStatusText }}</div>
|
|
|
</div>
|
|
|
<div class="time-line">
|
|
|
- <GrowthStageTimeline
|
|
|
- :key="phenologyTimelineKey"
|
|
|
- v-model="growthStageIndex"
|
|
|
- :stages="growthStages"
|
|
|
- @scroll-settled="onStageScrollSettled"
|
|
|
- @locale-change="getFindPhenologyInfo"
|
|
|
- />
|
|
|
+ <GrowthStageTimeline :key="phenologyTimelineKey" v-model="growthStageIndex"
|
|
|
+ :stages="growthStages" @scroll-settled="onStageScrollSettled"
|
|
|
+ @locale-change="getFindPhenologyInfo" />
|
|
|
</div>
|
|
|
<div class="confirm-btn-wrap">
|
|
|
<div class="confirm-btn" @click="hanldeSubmit">{{ t('recordDetails.confirmInfo') }}</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="phenology-track-section">
|
|
|
- <PhenologyTrackTimelineItem ref="phenologyTrackTimelineRef" :abnormalType="recordTypeObj[recordType]" />
|
|
|
+ <PhenologyTrackTimelineItem ref="phenologyTrackTimelineRef"
|
|
|
+ :abnormalType="recordTypeObj[recordType]" />
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -188,6 +147,9 @@
|
|
|
|
|
|
<RiskAssessPopup v-model:show="showRiskAssessPopup" />
|
|
|
|
|
|
+ <!-- 表型特征图片大图预览 -->
|
|
|
+ <ImagePreviewPopup v-model:show="showPhenotypeImagePreview" :images="phenotypePreviewImages" />
|
|
|
+
|
|
|
<!-- 物候 上传弹窗 -->
|
|
|
<UploadProgressPopup ref="phenologyUploadPopupRef" v-model:show="showPhenologyUploadPopup"
|
|
|
@cancel="handleCancelPhenologyUploadPopup" :upload-required="false" @confirm="handleConfirmPhenologyUpload">
|
|
|
@@ -203,7 +165,8 @@
|
|
|
<UploadProgressPopup ref="pestUploadPopupRef" v-model:show="showPestUploadPopup"
|
|
|
:popup-image-upload-loading="pestPopupImageUploadLoading" :init-img-arr="pestInitImgArr"
|
|
|
:confirm-text="t('recordDetails.confirmUpload')" :upload-required="false"
|
|
|
- @reset="handlePestUploadPopupReset" @cancel="handleCancelPestUploadPopup" @confirm="handleConfirmPestUpload">
|
|
|
+ @reset="handlePestUploadPopupReset" @cancel="handleCancelPestUploadPopup"
|
|
|
+ @confirm="handleConfirmPestUpload">
|
|
|
<template #header>
|
|
|
<div class="upload-form">
|
|
|
<div class="form-item special-input">
|
|
|
@@ -240,6 +203,7 @@ import customHeader from "@/components/customHeader.vue";
|
|
|
import PhenologyTrackTimelineItem from "@/components/pageComponents/PhenologyTrackTimelineItem.vue";
|
|
|
import GrowthStageTimeline from "@/components/pageComponents/GrowthStageTimeline.vue";
|
|
|
import UploadProgressPopup from "@/components/popup/UploadProgressPopup.vue";
|
|
|
+import ImagePreviewPopup from "@/components/popup/ImagePreviewPopup.vue";
|
|
|
import RiskAssessPopup from "./components/RiskAssessPopup.vue";
|
|
|
import { ref, onActivated, watch, nextTick, computed } from 'vue';
|
|
|
import { useRouter, useRoute } from 'vue-router';
|
|
|
@@ -249,6 +213,16 @@ import { RECORD_KEY_MAP } from '@/i18n/recordTextMap';
|
|
|
import { TextEllipsis } from "vant";
|
|
|
import { ElMessage } from "element-plus";
|
|
|
import IndexMap from "./map/index.js";
|
|
|
+import pestPhenotypePlaceholder from '@/assets/img/common/sd-1.jpg';
|
|
|
+import pestPreviewImg2 from '@/assets/img/common/sd-2.jpg';
|
|
|
+import pestPreviewImg3 from '@/assets/img/common/sd-3.jpg';
|
|
|
+
|
|
|
+/** 表型大图预览 mock 多图(联调后可删) */
|
|
|
+const PHENOTYPE_PREVIEW_MOCK_IMAGES = [
|
|
|
+ pestPhenotypePlaceholder,
|
|
|
+ pestPreviewImg2,
|
|
|
+ pestPreviewImg3,
|
|
|
+];
|
|
|
|
|
|
const router = useRouter();
|
|
|
const route = useRoute();
|
|
|
@@ -271,12 +245,28 @@ const expandCollapse = computed(() => ({
|
|
|
collapse: t('recordDetails.collapse'),
|
|
|
}));
|
|
|
|
|
|
+const textEllipsisBind = computed(() => ({
|
|
|
+ expandText: expandCollapse.value.expand,
|
|
|
+ collapseText: expandCollapse.value.collapse,
|
|
|
+ rows: 3,
|
|
|
+}));
|
|
|
+
|
|
|
function goPartitionManage() {
|
|
|
router.push({ name: 'MapManage' });
|
|
|
}
|
|
|
|
|
|
const showMap = ref(false);
|
|
|
const showRiskAssessPopup = ref(false);
|
|
|
+/** 表型特征图片预览弹窗 */
|
|
|
+const showPhenotypeImagePreview = ref(false);
|
|
|
+const phenotypePreviewImages = ref([]);
|
|
|
+
|
|
|
+/** 点击表型缩略图,打开大图预览 */
|
|
|
+function handlePhenotypeImagePreview(image) {
|
|
|
+ if (!image) return;
|
|
|
+ phenotypePreviewImages.value = PHENOTYPE_PREVIEW_MOCK_IMAGES;
|
|
|
+ showPhenotypeImagePreview.value = true;
|
|
|
+}
|
|
|
|
|
|
/** 病虫害态势监控:分类选择(接入接口后可绑定 workDetail) */
|
|
|
const pestTopIndex = ref(0);
|
|
|
@@ -309,10 +299,13 @@ const pestCategoryLabels = computed(() => {
|
|
|
}));
|
|
|
});
|
|
|
|
|
|
+const PEST_MOCK_RISK_LEVELS = [3, 2, 1, 0];
|
|
|
+
|
|
|
const pestDetailLabels = computed(() =>
|
|
|
- pestData.value.map((item) => ({
|
|
|
+ pestData.value.map((item, index) => ({
|
|
|
label: item.label ?? item.name ?? '',
|
|
|
value: item.value ?? item.fourth_type ?? item.id,
|
|
|
+ risk_level: PEST_MOCK_RISK_LEVELS[index % PEST_MOCK_RISK_LEVELS.length],
|
|
|
}))
|
|
|
);
|
|
|
|
|
|
@@ -345,6 +338,7 @@ const handlePestTopClick = async (index) => {
|
|
|
pestCategoryIndex.value = 0;
|
|
|
pestDetailIndex.value = 0;
|
|
|
await getAbnormalPlan();
|
|
|
+ syncPestPanelArrow();
|
|
|
};
|
|
|
|
|
|
const handlePestCategoryClick = async (index) => {
|
|
|
@@ -357,6 +351,37 @@ const handlePestDetailClick = (index) => {
|
|
|
pestDetailIndex.value = index;
|
|
|
};
|
|
|
|
|
|
+const pestTabsRef = ref(null);
|
|
|
+const pestTabRefs = ref([]);
|
|
|
+const pestPanelRef = ref(null);
|
|
|
+const pestPanelArrowLeft = ref(0);
|
|
|
+
|
|
|
+const setPestTabRef = (el, index) => {
|
|
|
+ if (el) {
|
|
|
+ pestTabRefs.value[index] = el;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const syncPestPanelArrow = () => {
|
|
|
+ nextTick(() => {
|
|
|
+ requestAnimationFrame(() => {
|
|
|
+ const activeTab = pestTabRefs.value[pestTopIndex.value];
|
|
|
+ const panel = pestPanelRef.value;
|
|
|
+ if (!activeTab || !panel) return;
|
|
|
+ const panelRect = panel.getBoundingClientRect();
|
|
|
+ const tabRect = activeTab.getBoundingClientRect();
|
|
|
+ pestPanelArrowLeft.value = tabRect.left + tabRect.width / 2 - panelRect.left;
|
|
|
+ });
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+watch(pestTopIndex, syncPestPanelArrow);
|
|
|
+watch(recordType, (type) => {
|
|
|
+ if (type === 'pest') {
|
|
|
+ syncPestPanelArrow();
|
|
|
+ }
|
|
|
+});
|
|
|
+
|
|
|
const indexMap = new IndexMap();
|
|
|
const recordMapContainer = ref(null);
|
|
|
const uploadMapContainer = ref(null);
|
|
|
@@ -613,6 +638,72 @@ const handleTabClick = (index) => {
|
|
|
|
|
|
const workDetail = ref({});
|
|
|
|
|
|
+const recordHeaderInfo = computed(() => {
|
|
|
+ if (recordType.value === 'growth') {
|
|
|
+ return {
|
|
|
+ titleKey: 'agriRecord.growthWorkName',
|
|
|
+ question: currentGrowthAnomalyDetail.value?.interact_question,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ if (recordType.value === 'pest') {
|
|
|
+ return {
|
|
|
+ titleKey: 'agriRecord.pestWorkName',
|
|
|
+ question: currentPestDetail.value?.interaction_reason,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ titleKey: 'agriRecord.phenologyWorkName',
|
|
|
+ question: workDetail.value.interaction_issue,
|
|
|
+ };
|
|
|
+});
|
|
|
+
|
|
|
+const leadDetailField = computed(() => {
|
|
|
+ if (recordType.value === 'growth') {
|
|
|
+ return {
|
|
|
+ labelKey: 'scienceLabel',
|
|
|
+ content: currentGrowthAnomalyDetail.value?.agri_judgment,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ if (recordType.value === 'pest') {
|
|
|
+ return {
|
|
|
+ labelKey: 'scienceLabel',
|
|
|
+ content: currentPestDetail.value?.kepu,
|
|
|
+ };
|
|
|
+ }
|
|
|
+ return {
|
|
|
+ labelKey: 'farmAnalysisLabel',
|
|
|
+ content: workDetail.value.crop_condition_analysis,
|
|
|
+ };
|
|
|
+});
|
|
|
+
|
|
|
+const trailDetailFields = computed(() => {
|
|
|
+ if (recordType.value === 'growth') {
|
|
|
+ return [
|
|
|
+ { labelKey: 'phenotypeLabel', content: currentGrowthAnomalyDetail.value?.phenotype },
|
|
|
+ { labelKey: 'highRiskLabel', content: currentGrowthAnomalyDetail.value?.patrol_points },
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ if (recordType.value === 'pest') {
|
|
|
+ const detail = currentPestDetail.value;
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ labelKey: 'harmLevelLabel',
|
|
|
+ content: detail?.harm ?? detail?.harm_desc ?? detail?.harm_level ?? detail?.damage,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ labelKey: 'phenotypeLabel',
|
|
|
+ content: detail?.phenotype,
|
|
|
+ image: pestPhenotypePlaceholder,
|
|
|
+ },
|
|
|
+ { labelKey: 'highRiskLabel', content: detail?.patrol_points },
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ return [
|
|
|
+ { labelKey: 'patrolLabel', content: workDetail.value.inspection_keypoints },
|
|
|
+ { labelKey: 'phenotypeLabel', content: workDetail.value.phenotypic_characteristics },
|
|
|
+ ];
|
|
|
+});
|
|
|
+
|
|
|
const growthStageIndex = ref();
|
|
|
const growthStages = ref([]);
|
|
|
const phenologyRawList = ref([]);
|
|
|
@@ -746,7 +837,8 @@ onActivated(async () => {
|
|
|
await getWorkDetail();
|
|
|
}
|
|
|
if (route.query.type === 'pest') {
|
|
|
- getAbnormalPlan();
|
|
|
+ await getAbnormalPlan();
|
|
|
+ syncPestPanelArrow();
|
|
|
}
|
|
|
if (route.query.type === 'growth') {
|
|
|
getGrowthAnomalyInfo();
|
|
|
@@ -892,83 +984,29 @@ const getFindPhenologyInfo = async () => {
|
|
|
.item-value {
|
|
|
display: inline;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- .card-item+.card-item {
|
|
|
- margin-top: 8px;
|
|
|
- }
|
|
|
-
|
|
|
- .pest-classify-picker {
|
|
|
- margin: 8px -10px;
|
|
|
- padding: 10px;
|
|
|
- // border-radius: 8px;
|
|
|
- background: #f2f3f5;
|
|
|
- display: flex;
|
|
|
- flex-direction: column;
|
|
|
- align-items: center;
|
|
|
- .aaa{
|
|
|
- background: #E9E9E9;
|
|
|
- width: fit-content;
|
|
|
- padding: 3px;
|
|
|
- border-radius: 4px;
|
|
|
- }
|
|
|
- .bbb{
|
|
|
- background: #fff;
|
|
|
- width: stretch;
|
|
|
- padding: 3px;
|
|
|
- border-radius: 4px;
|
|
|
- }
|
|
|
-
|
|
|
- &__row {
|
|
|
+ &__phenotype {
|
|
|
display: flex;
|
|
|
- justify-content: center;
|
|
|
- gap: 8px;
|
|
|
- width: stretch;
|
|
|
-
|
|
|
- &--top {
|
|
|
- .pest-classify-picker__top-btn {
|
|
|
- padding: 6px 30px;
|
|
|
- border-radius: 6px;
|
|
|
- background: #E9E9E9;
|
|
|
- color: #767676;
|
|
|
- }
|
|
|
-
|
|
|
- .pest-classify-picker__top-btn--active {
|
|
|
- background: #ffffff;
|
|
|
- color: #1a1a1a;
|
|
|
- }
|
|
|
- }
|
|
|
+ align-items: flex-start;
|
|
|
+ gap: 6px;
|
|
|
|
|
|
- &--grid4 {
|
|
|
- margin-top: 10px;
|
|
|
- display: grid;
|
|
|
- grid-template-columns: repeat(4, 1fr);
|
|
|
- gap: 8px;
|
|
|
+ &-content {
|
|
|
+ flex: 1;
|
|
|
+ min-width: 0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- &__chip {
|
|
|
- border: none;
|
|
|
- padding: 6px 4px;
|
|
|
- border-radius: 6px;
|
|
|
- font-size: 13px;
|
|
|
- text-align: center;
|
|
|
- white-space: nowrap;
|
|
|
- overflow: hidden;
|
|
|
- text-overflow: ellipsis;
|
|
|
- background: #ffffff;
|
|
|
- color: #909090;
|
|
|
- }
|
|
|
-
|
|
|
- &__chip--solid-active {
|
|
|
- background: #2199f8;
|
|
|
- color: #ffffff;
|
|
|
+ &__phenotype-image {
|
|
|
+ width: 70px;
|
|
|
+ height: 63px;
|
|
|
+ object-fit: cover;
|
|
|
+ border-radius: 5px;
|
|
|
+ cursor: pointer;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- &__chip--soft-active {
|
|
|
- background: rgba(33, 153, 248, 0.14);
|
|
|
- color: #2199f8;
|
|
|
- }
|
|
|
+ .card-item+.card-item {
|
|
|
+ margin-top: 8px;
|
|
|
}
|
|
|
|
|
|
.border-wrap {
|
|
|
@@ -1041,6 +1079,149 @@ const getFindPhenologyInfo = async () => {
|
|
|
margin-top: 10px;
|
|
|
}
|
|
|
|
|
|
+ .pest-classify-picker {
|
|
|
+ padding: 10px;
|
|
|
+ background: #f2f3f5;
|
|
|
+ border-radius: 8px;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ &__tabs {
|
|
|
+ position: relative;
|
|
|
+ z-index: 2;
|
|
|
+ display: inline-flex;
|
|
|
+ width: fit-content;
|
|
|
+ padding: 3px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: #fff;
|
|
|
+ box-sizing: border-box;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__tab {
|
|
|
+ position: relative;
|
|
|
+ padding: 6px 28px;
|
|
|
+ border-radius: 4px;
|
|
|
+ font-size: 13px;
|
|
|
+ line-height: 18px;
|
|
|
+ color: #767676;
|
|
|
+ text-align: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ &--active {
|
|
|
+ background: #2199f8;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &__panel {
|
|
|
+ position: relative;
|
|
|
+ align-self: stretch;
|
|
|
+ width: 100%;
|
|
|
+ margin-top: 10px;
|
|
|
+ padding: 12px 10px 10px;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: #fff;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ &::before {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ top: -7px;
|
|
|
+ left: var(--arrow-left, 50%);
|
|
|
+ transform: translateX(-50%);
|
|
|
+ width: 0;
|
|
|
+ height: 0;
|
|
|
+ border-left: 8px solid transparent;
|
|
|
+ border-right: 8px solid transparent;
|
|
|
+ border-bottom: 8px solid #fff;
|
|
|
+ z-index: 3;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &__categories {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ gap: 2px;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ overflow-x: auto;
|
|
|
+ -webkit-overflow-scrolling: touch;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__category {
|
|
|
+ position: relative;
|
|
|
+ flex: 1;
|
|
|
+ padding-bottom: 5px;
|
|
|
+ font-size: 13px;
|
|
|
+ color: #909090;
|
|
|
+ text-align: center;
|
|
|
+
|
|
|
+ &--active {
|
|
|
+ color: #333;
|
|
|
+ border-bottom: 2px solid #3A3A3A;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &__details {
|
|
|
+ display: grid;
|
|
|
+ grid-template-columns: repeat(4, 1fr);
|
|
|
+ gap: 10px;
|
|
|
+ padding-top: 6px;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__detail {
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: center;
|
|
|
+ padding: 5px 6px;
|
|
|
+ border: 1px solid transparent;
|
|
|
+ border-radius: 4px;
|
|
|
+ background: #f5f5f5;
|
|
|
+ color: #909090;
|
|
|
+ font-size: 12px;
|
|
|
+ text-align: center;
|
|
|
+ box-sizing: border-box;
|
|
|
+
|
|
|
+ &--active {
|
|
|
+ border-color: #2199f8;
|
|
|
+ background: rgba(33, 153, 248, 0.1);
|
|
|
+ color: #2199f8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ &__detail-text {
|
|
|
+ display: block;
|
|
|
+ width: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ white-space: nowrap;
|
|
|
+ }
|
|
|
+
|
|
|
+ &__badge {
|
|
|
+ position: absolute;
|
|
|
+ top: -9px;
|
|
|
+ right: -8px;
|
|
|
+ padding: 0 5px;
|
|
|
+ border-radius: 2px;
|
|
|
+ font-size: 10px;
|
|
|
+ color: #fff;
|
|
|
+ z-index: 1;
|
|
|
+
|
|
|
+ &--1 {
|
|
|
+ background: rgba(33, 153, 248, 0.35);
|
|
|
+ }
|
|
|
+
|
|
|
+ &--2 {
|
|
|
+ background: rgba(33, 153, 248, 0.65);
|
|
|
+ }
|
|
|
+
|
|
|
+ &--3 {
|
|
|
+ background: #2199f8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
.phenology-track-section {
|
|
|
margin-top: 15px;
|
|
|
display: flex;
|
|
|
@@ -1057,16 +1238,14 @@ const getFindPhenologyInfo = async () => {
|
|
|
gap: 8px;
|
|
|
padding: 10px;
|
|
|
border-radius: 8px;
|
|
|
- background: linear-gradient(180deg, #FFDFC5 -12.59%, #FFFFFF 38.15%);
|
|
|
- margin-top: 8px;
|
|
|
+ background: rgba(255, 149, 61, 0.1);
|
|
|
+ border: 1px solid rgba(255, 149, 61, 0.5);
|
|
|
+ margin-top: 10px;
|
|
|
|
|
|
.banner__left {
|
|
|
flex: 1;
|
|
|
|
|
|
.banner__title {
|
|
|
- display: flex;
|
|
|
- align-items: center;
|
|
|
- gap: 4px;
|
|
|
font-size: 16px;
|
|
|
font-weight: 600;
|
|
|
color: #FF953D;
|
|
|
@@ -1079,18 +1258,23 @@ const getFindPhenologyInfo = async () => {
|
|
|
}
|
|
|
|
|
|
.banner__btn {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ gap: 4px;
|
|
|
padding: 7px 16px;
|
|
|
border-radius: 25px;
|
|
|
color: #ffffff;
|
|
|
background: linear-gradient(180deg, #FFB273 0%, #FF953D 100%);
|
|
|
}
|
|
|
|
|
|
- &.blue{
|
|
|
+ &.blue {
|
|
|
background: #F1F8FE;
|
|
|
border: 1px solid rgba(33, 153, 248, 0.5);
|
|
|
+
|
|
|
.banner__title {
|
|
|
color: #2199F8;
|
|
|
}
|
|
|
+
|
|
|
.banner__btn {
|
|
|
background: linear-gradient(180deg, #8ACBFF 0%, #2199F8 100%);
|
|
|
}
|