|
@@ -0,0 +1,1122 @@
|
|
|
|
|
+<template>
|
|
|
|
|
+ <div class="soil-root-track-page">
|
|
|
|
|
+ <custom-header
|
|
|
|
|
+ :name="pageTitle"
|
|
|
|
|
+ :isGoBack="!isFromShare"
|
|
|
|
|
+ :isClose="isFromShare"
|
|
|
|
|
+ :showClose="false"
|
|
|
|
|
+ @goback="handleBack"
|
|
|
|
|
+ />
|
|
|
|
|
+ <div class="soil-root-track-body" v-loading="loading" element-loading-background="rgba(15, 15, 15, 0.55)">
|
|
|
|
|
+ <div class="soil-root-hero">
|
|
|
|
|
+ <div class="soil-root-hero__share" @click="handleShare">
|
|
|
|
|
+ <Icon name="share" color="rgba(255,255,255,0.85)" />
|
|
|
|
|
+ <span>{{ t("agriFile.forward") }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="soil-root-mask"></div>
|
|
|
|
|
+ <div class="soil-root-top">
|
|
|
|
|
+ <div class="soil-root-hero__tags">
|
|
|
|
|
+ <span class="soil-root-hero__tag soil-root-hero__tag--level">
|
|
|
|
|
+ <el-icon><WarningFilled /></el-icon>
|
|
|
|
|
+ {{ level }}
|
|
|
|
|
+ </span>
|
|
|
|
|
+ <span class="soil-root-hero__tag soil-root-hero__tag--zone">{{ zoneName }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="soil-root-hero__title">{{ theme }}</div>
|
|
|
|
|
+ <div class="soil-root-hero__reason">{{ reason }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="soil-root-main">
|
|
|
|
|
+ <!-- 农情研判 -->
|
|
|
|
|
+ <div class="box-wrap stage-card analysis-card">
|
|
|
|
|
+ <div class="work-info">
|
|
|
|
|
+ <div class="section-title">
|
|
|
|
|
+ <span class="title-bar"></span>
|
|
|
|
|
+ {{ t("agriFile.agriAssessment") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="analysis-card__desc">{{ assessmentDesc }}</div>
|
|
|
|
|
+ <div class="analysis-card__stats">
|
|
|
|
|
+ <div v-for="(item, index) in analysisStats" :key="index" class="analysis-card__stat">
|
|
|
|
|
+ <div class="analysis-card__stat-value" :class="{ highlight: item.highlight }">
|
|
|
|
|
+ <template v-if="item.unit">
|
|
|
|
|
+ <span class="num">{{ item.value }}</span>
|
|
|
|
|
+ <span class="unit">{{ item.unit }}</span>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ <template v-else>{{ item.value }}</template>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="analysis-card__stat-label">{{ item.label }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 根系排查互动 -->
|
|
|
|
|
+ <!-- <div class="interact-section-head">
|
|
|
|
|
+ <span class="interact-section-head__text"> 根系排查互动 · 共 {{ interactList.length }} 项 </span>
|
|
|
|
|
+ <span class="interact-section-head__line"></span>
|
|
|
|
|
+ </div> -->
|
|
|
|
|
+
|
|
|
|
|
+ <div v-for="(item, index) in interactList" :key="item.fw_code || index" class="soil-root-item">
|
|
|
|
|
+ <div class="soil-root-item__wrap">
|
|
|
|
|
+ <div class="soil-root-item__title">
|
|
|
|
|
+ <img class="soil-root-item__icon" src="@/assets/img/agricultural/gaojin.png" alt="" />
|
|
|
|
|
+ <span>{{ item.abnormal_type || t("agriFile.rootAbnormal") }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="stage-card interact-card">
|
|
|
|
|
+ <div class="work-info">
|
|
|
|
|
+ <div class="interact-card__head">
|
|
|
|
|
+ <div class="section-title interact-card__title">
|
|
|
|
|
+ <span class="title-bar"></span>
|
|
|
|
|
+ {{ t("agriFile.interactQuestion") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="interact-card__submit"
|
|
|
|
|
+ :class="{ disabled: selectedMap[item.fw_code || index] == null }"
|
|
|
|
|
+ @click="handleSubmit(item, index)"
|
|
|
|
|
+ >
|
|
|
|
|
+ 确认提交
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="interact-card__qa">
|
|
|
|
|
+ <div class="interact-card__question">{{ item.interact_problem }}</div>
|
|
|
|
|
+ <div class="interact-card__options">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="(opt, optIndex) in item.options"
|
|
|
|
|
+ :key="`${item.fw_code || index}-${optIndex}`"
|
|
|
|
|
+ class="interact-option"
|
|
|
|
|
+ :class="{
|
|
|
|
|
+ selected: selectedMap[item.fw_code || index] === optIndex,
|
|
|
|
|
+ }"
|
|
|
|
|
+ @click="selectedMap[item.fw_code || index] = optIndex"
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="interact-option__text">{{ opt }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!-- 巡园向导 -->
|
|
|
|
|
+ <div class="guide-card">
|
|
|
|
|
+ <div class="work-info">
|
|
|
|
|
+ <div class="section-title">
|
|
|
|
|
+ <img class="guide-icon" src="@/assets/img/farm/guide.png" alt="" />
|
|
|
|
|
+ {{ t("agriFile.patrolGuide") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="guide-card__img-box">
|
|
|
|
|
+ <photo-provider :photo-closable="true">
|
|
|
|
|
+ <photo-consumer :src="resolveGuideImage(item.pic_url)">
|
|
|
|
|
+ <img :src="resolveGuideImage(item.pic_url)" alt="" />
|
|
|
|
|
+ </photo-consumer>
|
|
|
|
|
+ </photo-provider>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="guide-card__upload-wrap">
|
|
|
|
|
+ <div class="guide-card__upload" @click="handleUploadClick">
|
|
|
|
|
+ <img class="guide-card__upload-icon" src="@/assets/img/common/camera.png" alt="" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <!-- 土壤条件判断 -->
|
|
|
|
|
+ <!-- <div class="interact-section-head">
|
|
|
|
|
+ <span class="interact-section-head__text"> 土壤条件判断 · 共 {{ soilSections.length }} 项 </span>
|
|
|
|
|
+ <span class="interact-section-head__line"></span>
|
|
|
|
|
+ </div> -->
|
|
|
|
|
+
|
|
|
|
|
+ <!-- <div v-for="section in soilSections" :key="section.key" class="soil-section-card">
|
|
|
|
|
+ <div class="soil-section-card__wrap">
|
|
|
|
|
+ <div class="soil-section-card__title">
|
|
|
|
|
+ <img class="soil-section-card__icon" src="@/assets/img/agricultural/gaojin.png" alt="" />
|
|
|
|
|
+ <span>{{ section.title }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="soil-section-card__question">{{ section.question }}</div>
|
|
|
|
|
+ <div class="soil-section-card__options">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="opt in section.options"
|
|
|
|
|
+ :key="`${section.key}-${opt.value}`"
|
|
|
|
|
+ class="interact-option"
|
|
|
|
|
+ :class="{ selected: isSectionSelected(section, opt.value) }"
|
|
|
|
|
+ @click="toggleSectionOption(section, opt.value)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="interact-option__text">{{ opt.label }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div v-if="section.guide && section.guide.desc" class="soil-section-card__guide">
|
|
|
|
|
+ <div class="section-title">
|
|
|
|
|
+ <img class="guide-icon" src="@/assets/img/farm/guide.png" alt="" />
|
|
|
|
|
+ {{ t("agriFile.patrolGuide") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="soil-section-card__guide-desc">{{ section.guide.desc }}</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div> -->
|
|
|
|
|
+
|
|
|
|
|
+ <div v-for="(section, index) in soilSections" :key="index" class="soil-root-item">
|
|
|
|
|
+ <div class="soil-root-item__wrap">
|
|
|
|
|
+ <div class="soil-root-item__title">
|
|
|
|
|
+ <img class="soil-root-item__icon" src="@/assets/img/agricultural/gaojin.png" alt="" />
|
|
|
|
|
+ <span>{{ section.title || t("agriFile.rootAbnormal") }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="stage-card interact-card">
|
|
|
|
|
+ <div class="work-info">
|
|
|
|
|
+ <div class="interact-card__head">
|
|
|
|
|
+ <div class="section-title interact-card__title">
|
|
|
|
|
+ <span class="title-bar"></span>
|
|
|
|
|
+ {{ t("agriFile.interactQuestion") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="interact-card__submit"
|
|
|
|
|
+ @click="handleSubmit(section, index)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <!-- :class="{ disabled: selectedMap[item.fw_code || index] == null }" -->
|
|
|
|
|
+ 确认提交
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="interact-card__qa">
|
|
|
|
|
+ <div class="interact-card__question">{{ section.question }}</div>
|
|
|
|
|
+ <div class="interact-card__options soil-section-card__options">
|
|
|
|
|
+ <div
|
|
|
|
|
+ v-for="opt in section.options"
|
|
|
|
|
+ :key="`${section.key}-${opt.value}`"
|
|
|
|
|
+ class="interact-option"
|
|
|
|
|
+ :class="{ selected: isSectionSelected(section, opt.value) }"
|
|
|
|
|
+ @click="toggleSectionOption(section, opt.value)"
|
|
|
|
|
+ >
|
|
|
|
|
+ <span class="interact-option__text">{{ opt.label }}</span>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <!-- 巡园向导 -->
|
|
|
|
|
+ <div class="guide-card">
|
|
|
|
|
+ <div class="work-info">
|
|
|
|
|
+ <div class="section-title">
|
|
|
|
|
+ <img class="guide-icon" src="@/assets/img/farm/guide.png" alt="" />
|
|
|
|
|
+ {{ t("agriFile.patrolGuide") }}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <div class="soil-section-card__guide-desc">{{ section.guide.desc }}</div>
|
|
|
|
|
+ <div class="guide-card__img-box" v-if="section.image_url">
|
|
|
|
|
+ <photo-provider :photo-closable="true">
|
|
|
|
|
+ <photo-consumer :src="base_img_url3+section.image_url">
|
|
|
|
|
+ <img :src="base_img_url3 + section.image_url" alt="" />
|
|
|
|
|
+ </photo-consumer>
|
|
|
|
|
+ </photo-provider>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+
|
|
|
|
|
+ <div class="guide-card__upload-wrap">
|
|
|
|
|
+ <div class="guide-card__upload" @click="handleUploadClick">
|
|
|
|
|
+ <img class="guide-card__upload-icon" src="@/assets/img/common/camera.png" alt="" />
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ <album-upload-popup v-model:show="showUploadPopup" @confirm="handleUploadConfirm" />
|
|
|
|
|
+ <tip-popup
|
|
|
|
|
+ v-model:show="showSuccessPopup"
|
|
|
|
|
+ type="executeSuccess"
|
|
|
|
|
+ text="您已上传成功"
|
|
|
|
|
+ text2="请等待诊断报告生成"
|
|
|
|
|
+ hideBtn
|
|
|
|
|
+ >
|
|
|
|
|
+ <template #footer>
|
|
|
|
|
+ <div class="bottom-btn-container">
|
|
|
|
|
+ <div class="bottom-btn primary-btn" @click="handleComplete">完成</div>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ </template>
|
|
|
|
|
+ </tip-popup>
|
|
|
|
|
+ </div>
|
|
|
|
|
+</template>
|
|
|
|
|
+
|
|
|
|
|
+<script setup>
|
|
|
|
|
+import { computed, nextTick, onActivated, reactive, ref } from "vue";
|
|
|
|
|
+import { useRoute, useRouter } from "vue-router";
|
|
|
|
|
+import { Icon } from "vant";
|
|
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
|
|
+import customHeader from "@/components/customHeader.vue";
|
|
|
|
|
+import albumUploadPopup from "../components/albumUploadPopup.vue";
|
|
|
|
|
+import tipPopup from "@/components/popup/tipPopup.vue";
|
|
|
|
|
+import { useI18n } from "@/i18n";
|
|
|
|
|
+import { base_img_url2, base_img_url3 } from "@/api/config";
|
|
|
|
|
+import wx from "weixin-js-sdk";
|
|
|
|
|
+
|
|
|
|
|
+const { t } = useI18n();
|
|
|
|
|
+const route = useRoute();
|
|
|
|
|
+const router = useRouter();
|
|
|
|
|
+
|
|
|
|
|
+// ---------- 常量 ----------
|
|
|
|
|
+const DEFAULT_GUIDE_IMAGE = require("@/assets/img/agricultural/patrol-guide.png");
|
|
|
|
|
+
|
|
|
|
|
+/** 农情研判底部指标:接口未接好前写死(土壤根系相关) */
|
|
|
|
|
+const analysisStats = [
|
|
|
|
|
+ { value: "126", unit: "mm", label: "累计降雨", highlight: false },
|
|
|
|
|
+ { value: "92", unit: "%", label: "土壤含水率", highlight: false },
|
|
|
|
|
+ { value: "52", unit: "h", label: "根部积水", highlight: true },
|
|
|
|
|
+];
|
|
|
|
|
+
|
|
|
|
|
+// ---------- 页面状态 ----------
|
|
|
|
|
+const loading = ref(false);
|
|
|
|
|
+const submitting = ref(false);
|
|
|
|
|
+const showUploadPopup = ref(false);
|
|
|
|
|
+const showSuccessPopup = ref(false);
|
|
|
|
|
+const needDraw = ref(true); // status≠1 时需先勾画种植范围
|
|
|
|
|
+const interactList = ref([]); // root 根系排查互动项(取 data.root)
|
|
|
|
|
+const soilSections = ref([]); // 土壤条件判断(质地/酸碱/墒情/氮磷钾/持水)
|
|
|
|
|
+const sectionSelected = reactive({}); // section.key → 选中值(多选为数组)
|
|
|
|
|
+const stressInfo = ref({}); // 胁迫等级等公共信息
|
|
|
|
|
+const selectedMap = reactive({}); // fw_code/index → 选项下标
|
|
|
|
|
+/** 与查询共用的提交上下文,保证 fw 答案与列表同源 */
|
|
|
|
|
+const queryContext = ref({
|
|
|
|
|
+ farm_id: null,
|
|
|
|
|
+ zone_id: null,
|
|
|
|
|
+ calc_date: "",
|
|
|
|
|
+ crop_type: "",
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// ---------- 计算属性 ----------
|
|
|
|
|
+const pageTitle = computed(() => route.query.pageName || t("agriFile.patrolSoilTitle"));
|
|
|
|
|
+const zoneId = computed(() => route.query.zoneId || route.query.id);
|
|
|
|
|
+
|
|
|
|
|
+const firstInteract = computed(() => interactList.value[0] || null);
|
|
|
|
|
+/** interaction_theme */
|
|
|
|
|
+const theme = computed(() => firstInteract.value?.interaction_title || t("agriFile.soilRootTheme"));
|
|
|
|
|
+/** interaction_title */
|
|
|
|
|
+const reason = computed(() => firstInteract.value?.interaction_theme || t("agriFile.soilRootReason"));
|
|
|
|
|
+/** 农情研判说明 */
|
|
|
|
|
+const assessmentDesc = computed(() => firstInteract.value?.interaction_reason || t("agriFile.soilRootAssessment"));
|
|
|
|
|
+const guideImage = computed(() => resolveGuideImage(firstInteract.value?.pic_url));
|
|
|
|
|
+/** stress_info.level */
|
|
|
|
|
+const level = computed(() => {
|
|
|
|
|
+ const lv = stressInfo.value?.level;
|
|
|
|
|
+ if (lv == null || lv === "") return t("agriFile.riskLevel2");
|
|
|
|
|
+ return `${lv}级`;
|
|
|
|
|
+});
|
|
|
|
|
+const zoneName = computed(() => {
|
|
|
|
|
+ const farm = getSelectedFarm();
|
|
|
|
|
+ return farm.variety_name || farm.zone_name || t("agriFile.zoneOne");
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+/** 通过分享进入:无返回箭头 */
|
|
|
|
|
+const isFromShare = computed(() => {
|
|
|
|
|
+ if (isTruthyFlag(route.query.fromShare)) return true;
|
|
|
|
|
+ const paramsPage = parseMaybeJson(route.query.paramsPage);
|
|
|
|
|
+ if (isTruthyFlag(paramsPage?.fromShare)) return true;
|
|
|
|
|
+ const miniJson = parseMaybeJson(route.query.miniJson);
|
|
|
|
|
+ if (isTruthyFlag(miniJson?.fromShare)) return true;
|
|
|
|
|
+ if (isTruthyFlag(parseMaybeJson(miniJson?.paramsPage)?.fromShare)) return true;
|
|
|
|
|
+ return false;
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+// ---------- 工具函数 ----------
|
|
|
|
|
+function isTruthyFlag(value) {
|
|
|
|
|
+ return value === 1 || value === "1" || value === true || value === "true";
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function parseMaybeJson(value) {
|
|
|
|
|
+ if (value == null || value === "") return null;
|
|
|
|
|
+ if (typeof value === "object") return value;
|
|
|
|
|
+ try {
|
|
|
|
|
+ return JSON.parse(value);
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getSelectedFarm() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ return JSON.parse(localStorage.getItem("selectedFarmData") || "{}");
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ return {};
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function getSelectedFarmId() {
|
|
|
|
|
+ const stored = localStorage.getItem("selectedFarmId");
|
|
|
|
|
+ if (stored != null && stored !== "") return Number(stored);
|
|
|
|
|
+ const farm = getSelectedFarm();
|
|
|
|
|
+ const id = farm.farm_id ?? farm.id;
|
|
|
|
|
+ return id != null && id !== "" ? Number(id) : null;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** 农场品类编码,接口 crop_type */
|
|
|
|
|
+const resolveCropType = (farm = getSelectedFarm()) =>
|
|
|
|
|
+ farm.category_code || farm.categorycode || farm.crop_code || farm.crop_type || "";
|
|
|
|
|
+
|
|
|
|
|
+function resolveImageUrl(path) {
|
|
|
|
|
+ if (!path) return "";
|
|
|
|
|
+ const text = String(path).trim();
|
|
|
|
|
+ if (!text) return "";
|
|
|
|
|
+ if (/^https?:\/\//i.test(text)) return text;
|
|
|
|
|
+ return base_img_url2 + text.replace(/^\//, "");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function resolveGuideImage(picUrl) {
|
|
|
|
|
+ return resolveImageUrl(picUrl) || DEFAULT_GUIDE_IMAGE;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/** interact_options 可能是 JSON 字符串 */
|
|
|
|
|
+function parseInteractOptions(value) {
|
|
|
|
|
+ if (Array.isArray(value)) return value.map((name) => String(name));
|
|
|
|
|
+ const parsed = parseMaybeJson(value);
|
|
|
|
|
+ if (Array.isArray(parsed)) return parsed.map((name) => String(name));
|
|
|
|
|
+ return [];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function mapInteractItem(raw) {
|
|
|
|
|
+ return {
|
|
|
|
|
+ ...raw,
|
|
|
|
|
+ options: parseInteractOptions(raw?.interact_options),
|
|
|
|
|
+ };
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+const formatLocalDate = (date) => {
|
|
|
|
|
+ const y = date.getFullYear();
|
|
|
|
|
+ const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
|
|
|
+ const d = String(date.getDate()).padStart(2, "0");
|
|
|
|
|
+ return `${y}-${m}-${d}`;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// ---------- 业务逻辑 ----------
|
|
|
|
|
+// 土壤根系感知:GET VE_API.pheno.getSoilTasks({ zone_id }),返回 data.root(根系排查互动)
|
|
|
|
|
+// 与 data.sections(土壤条件判断:质地/酸碱/墒情/氮磷钾/持水)
|
|
|
|
|
+const fetchSoilRootInteract = async () => {
|
|
|
|
|
+ const farm = getSelectedFarm();
|
|
|
|
|
+ const zId = zoneId.value || farm.zone_id || farm.zoneId;
|
|
|
|
|
+ if (zId == null || zId === "") {
|
|
|
|
|
+ interactList.value = [];
|
|
|
|
|
+ stressInfo.value = {};
|
|
|
|
|
+ soilSections.value = [];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // 提交上下文:confirmAbnormalInteract 需完整参数,取本地农场信息补全
|
|
|
|
|
+ queryContext.value = {
|
|
|
|
|
+ farm_id: farm.farm_id ?? farm.id ?? "",
|
|
|
|
|
+ zone_id: zId,
|
|
|
|
|
+ calc_date: formatLocalDate(new Date()),
|
|
|
|
|
+ crop_type: resolveCropType(farm),
|
|
|
|
|
+ };
|
|
|
|
|
+ loading.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await VE_API.pheno.getSoilTasks({ zone_id: zId });
|
|
|
|
|
+ if (res?.code !== 200) {
|
|
|
|
|
+ interactList.value = [];
|
|
|
|
|
+ stressInfo.value = {};
|
|
|
|
|
+ soilSections.value = [];
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ const data = res?.data || {};
|
|
|
|
|
+ const root = data.root || {};
|
|
|
|
|
+ interactList.value = Object.keys(root).length ? [mapInteractItem(root)] : [];
|
|
|
|
|
+ // hero 等级取 root.level_num(如 2),level 计算属性会拼成「2级」
|
|
|
|
|
+ stressInfo.value = { level: root.level_num ?? null };
|
|
|
|
|
+ soilSections.value = Array.isArray(data.sections) ? data.sections : [];
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.warn("[soilRootTrack] getSoilTasks failed", e);
|
|
|
|
|
+ interactList.value = [];
|
|
|
|
|
+ stressInfo.value = {};
|
|
|
|
|
+ soilSections.value = [];
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ loading.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** status=1 有范围无需勾画;status=0 无范围需要勾画 */
|
|
|
|
|
+const fetchZoneRangeStatus = async () => {
|
|
|
|
|
+ const farm = getSelectedFarm();
|
|
|
|
|
+ const farmId = farm.farm_id ?? farm.id;
|
|
|
|
|
+ const zId = zoneId.value || farm.zone_id || farm.zoneId;
|
|
|
|
|
+ if (farmId == null || farmId === "" || zId == null || zId === "") {
|
|
|
|
|
+ needDraw.value = true;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await VE_API.questionnaire.checkZoneRange({
|
|
|
|
|
+ farm_id: farmId,
|
|
|
|
|
+ zone_id: zId,
|
|
|
|
|
+ });
|
|
|
|
|
+ needDraw.value = Number(res?.data?.status) !== 1;
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.warn("[soilRootTrack] checkZoneRange failed", e);
|
|
|
|
|
+ needDraw.value = true;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// ---------- 事件处理 / 生命周期 ----------
|
|
|
|
|
+const handleShare = () => {
|
|
|
|
|
+ const query = {
|
|
|
|
|
+ askInfo: { title: "转发巡园要点", content: "是否分享给好友" },
|
|
|
|
|
+ shareText: theme.value || "连阴雨泡根,根系发黑缺氧,赶紧排水护根!",
|
|
|
|
|
+ targetUrl: "soil_root_track",
|
|
|
|
|
+ paramsPage: JSON.stringify({
|
|
|
|
|
+ id: route.query.id,
|
|
|
|
|
+ zoneId: zoneId.value,
|
|
|
|
|
+ fromShare: 1,
|
|
|
|
|
+ ...(route.query.pageName ? { pageName: route.query.pageName } : {}),
|
|
|
|
|
+ }),
|
|
|
|
|
+ imageUrl: "https://birdseye-img.sysuimars.com/farm-h5/field.png",
|
|
|
|
|
+ };
|
|
|
|
|
+ wx.miniProgram.navigateTo({
|
|
|
|
|
+ url: `/pages/subPages/share_page/index?pageParams=${JSON.stringify(query)}&type=sharePage`,
|
|
|
|
|
+ });
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+/** 需勾画则先画范围;否则直接上传(同 abnormalTrack) */
|
|
|
|
|
+const handleUploadClick = () => {
|
|
|
|
|
+ if (needDraw.value) {
|
|
|
|
|
+ router.push({
|
|
|
|
|
+ path: "/add_zone",
|
|
|
|
|
+ query: {
|
|
|
|
|
+ type: "farm",
|
|
|
|
|
+ targetUrl: "/soil_root_track",
|
|
|
|
|
+ ...(zoneId.value ? { trackId: zoneId.value } : {}),
|
|
|
|
|
+ },
|
|
|
|
|
+ });
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ showUploadPopup.value = true;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleUploadConfirm = async ({ images, date } = {}) => {
|
|
|
|
|
+ const cloud_url = Array.isArray(images) ? images : [];
|
|
|
|
|
+ if (!cloud_url.length) {
|
|
|
|
|
+ ElMessage.warning("请先上传照片");
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ const farm = getSelectedFarm();
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await VE_API.questionnaire.uploadImages({
|
|
|
|
|
+ cloud_url,
|
|
|
|
|
+ farm_id: farm.farm_id ?? farm.id ?? "",
|
|
|
|
|
+ zone_id: zoneId.value || "",
|
|
|
|
|
+ category_code: farm.category_code || "",
|
|
|
|
|
+ zone_name: farm.variety_name || "",
|
|
|
|
|
+ create_time: date,
|
|
|
|
|
+ });
|
|
|
|
|
+ if (res?.code === 200) {
|
|
|
|
|
+ showSuccessPopup.value = true;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ ElMessage.error(res?.msg || "上传失败,请稍后再试");
|
|
|
|
|
+ } catch {
|
|
|
|
|
+ ElMessage.error("上传失败,请稍后再试");
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleComplete = () => {
|
|
|
|
|
+ showSuccessPopup.value = false;
|
|
|
|
|
+ router.replace("/agri_file");
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleSubmit = async (item, index) => {
|
|
|
|
|
+ const key = item?.fw_code || index;
|
|
|
|
|
+ const optIndex = selectedMap[key];
|
|
|
|
|
+ if (optIndex == null) {
|
|
|
|
|
+ ElMessage.warning(t("agriFile.pleaseSelectOption"));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ const optionText = item?.options?.[optIndex];
|
|
|
|
|
+ if (!optionText || !item?.fw_code) {
|
|
|
|
|
+ ElMessage.warning(t("agriFile.pleaseSelectOption"));
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (submitting.value) return;
|
|
|
|
|
+ submitting.value = true;
|
|
|
|
|
+ try {
|
|
|
|
|
+ const res = await VE_API.questionnaire.confirmAbnormalInteract({
|
|
|
|
|
+ ...queryContext.value,
|
|
|
|
|
+ fw_code: item.fw_code,
|
|
|
|
|
+ options: String(optionText),
|
|
|
|
|
+ });
|
|
|
|
|
+ if (res?.code === 200) {
|
|
|
|
|
+ ElMessage.success(t("agriFile.submitSuccess"));
|
|
|
|
|
+ await fetchSoilRootInteract();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ ElMessage.error(res?.msg || "提交失败,请稍后再试");
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ console.warn("[soilRootTrack] confirmAbnormalInteract failed", e);
|
|
|
|
|
+ ElMessage.error("提交失败,请稍后再试");
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ submitting.value = false;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const handleBack = () => {
|
|
|
|
|
+ router.back();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 土壤条件判断:单选 / 多选选项切换
|
|
|
|
|
+const isSectionSelected = (section, value) => {
|
|
|
|
|
+ const sel = sectionSelected[section.key];
|
|
|
|
|
+ if (section.multiple) return Array.isArray(sel) && sel.includes(value);
|
|
|
|
|
+ return sel === value;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+const toggleSectionOption = (section, value) => {
|
|
|
|
|
+ if (section.multiple) {
|
|
|
|
|
+ const cur = Array.isArray(sectionSelected[section.key])
|
|
|
|
|
+ ? sectionSelected[section.key]
|
|
|
|
|
+ : [];
|
|
|
|
|
+ sectionSelected[section.key] = cur.includes(value)
|
|
|
|
|
+ ? cur.filter((v) => v !== value)
|
|
|
|
|
+ : [...cur, value];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ sectionSelected[section.key] =
|
|
|
|
|
+ sectionSelected[section.key] === value ? null : value;
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+onActivated(() => {
|
|
|
|
|
+ fetchZoneRangeStatus();
|
|
|
|
|
+ fetchSoilRootInteract();
|
|
|
|
|
+ if (route.query.showUpload !== "1") return;
|
|
|
|
|
+ nextTick(() => {
|
|
|
|
|
+ showUploadPopup.value = true;
|
|
|
|
|
+ const { showUpload, ...restQuery } = route.query;
|
|
|
|
|
+ router.replace({ path: route.path, query: restQuery });
|
|
|
|
|
+ });
|
|
|
|
|
+});
|
|
|
|
|
+</script>
|
|
|
|
|
+
|
|
|
|
|
+<style lang="scss" scoped>
|
|
|
|
|
+.soil-root-track-page {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-direction: column;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 100vh;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ background: #0b0b0b;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+
|
|
|
|
|
+ .soil-root-track-body {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ overflow-y: auto;
|
|
|
|
|
+ -webkit-overflow-scrolling: touch;
|
|
|
|
|
+ padding-bottom: 10px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .soil-root-hero {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ padding: 106px 70px 16px 12px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ z-index: 2;
|
|
|
|
|
+ // min-height: 240px;
|
|
|
|
|
+ background: linear-gradient(
|
|
|
|
|
+ 180deg,
|
|
|
|
|
+ rgba(11, 11, 11, 0) 8.51%,
|
|
|
|
|
+ rgba(11, 11, 11, 0.416) 42.95%,
|
|
|
|
|
+ rgba(11, 11, 11, 0.468) 56.49%,
|
|
|
|
|
+ rgba(11, 11, 11, 0.52) 80.47%
|
|
|
|
|
+ ),
|
|
|
|
|
+ url("@/assets/img/agricultural/soil-detail-bg.png") right bottom / cover no-repeat;
|
|
|
|
|
+
|
|
|
|
|
+ .soil-root-mask {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ bottom: 0;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ height: 107px;
|
|
|
|
|
+ background: linear-gradient(
|
|
|
|
|
+ 180deg,
|
|
|
|
|
+ rgba(11, 11, 11, 0) 8.47%,
|
|
|
|
|
+ rgba(11, 11, 11, 0.8) 26.93%,
|
|
|
|
|
+ rgba(11, 11, 11, 0.9) 37.74%,
|
|
|
|
|
+ #0b0b0b 56.89%
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .soil-root-top {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ z-index: 2;
|
|
|
|
|
+ // padding-bottom: 40px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__share {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ top: 16px;
|
|
|
|
|
+ right: 16px;
|
|
|
|
|
+ z-index: 2;
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 4px;
|
|
|
|
|
+ height: 28px;
|
|
|
|
|
+ padding: 0 12px;
|
|
|
|
|
+ border-radius: 14px;
|
|
|
|
|
+ background: rgba(0, 0, 0, 0.45);
|
|
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.12);
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.85);
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__tags {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ padding-right: 88px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__tag {
|
|
|
|
|
+ display: inline-flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 3px;
|
|
|
|
|
+ height: 20px;
|
|
|
|
|
+ padding: 0 7px;
|
|
|
|
|
+ border-radius: 24px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ line-height: 20px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ border: 1px solid rgba(138, 106, 46, 1);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__tag--level {
|
|
|
|
|
+ background: linear-gradient(90deg, #7e2321 0%, #350302 100%);
|
|
|
|
|
+ color: #ff7d7b;
|
|
|
|
|
+ border-color: rgba(201, 53, 50, 0.41);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__tag--zone {
|
|
|
|
|
+ color: #e8c27a;
|
|
|
|
|
+ background: #2a2418;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__title {
|
|
|
|
|
+ font-family: "PangMenZhengDao", sans-serif;
|
|
|
|
|
+ font-size: 26px;
|
|
|
|
|
+ line-height: 34px;
|
|
|
|
|
+ background: linear-gradient(180deg, #ffffff 0%, #fecd76 100%);
|
|
|
|
|
+ -webkit-background-clip: text;
|
|
|
|
|
+ background-clip: text;
|
|
|
|
|
+ color: transparent;
|
|
|
|
|
+ margin-bottom: 6px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__reason {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ line-height: 22px;
|
|
|
|
|
+ padding: 4px;
|
|
|
|
|
+ border-radius: 4px;
|
|
|
|
|
+ background: linear-gradient(90deg, rgba(255, 212, 137, 0.1) 0%, rgba(255, 212, 137, 0) 100%);
|
|
|
|
|
+ color: rgba(255, 255, 255, 1);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .soil-root-main {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ z-index: 3;
|
|
|
|
|
+ // margin-top: -38px;
|
|
|
|
|
+ padding: 0 12px 12px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .box-wrap {
|
|
|
|
|
+ padding: 1px;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 72.15%);
|
|
|
|
|
+
|
|
|
|
|
+ .work-info {
|
|
|
|
|
+ background: linear-gradient(180deg, #1a191d 0%, #121216 100%);
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ padding: 12px 13px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .stage-card + .stage-card {
|
|
|
|
|
+ margin-top: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .section-title {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ color: #f2e9d8;
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ &.interact-card__title {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .title-bar {
|
|
|
|
|
+ width: 4px;
|
|
|
|
|
+ height: 16px;
|
|
|
|
|
+ border-radius: 2px;
|
|
|
|
|
+ background: #ffd489;
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .analysis-card {
|
|
|
|
|
+ .analysis-card__desc {
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ line-height: 22px;
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
|
|
+ margin-bottom: 10px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .analysis-card__stats {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: stretch;
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.05);
|
|
|
|
|
+ border-radius: 10px;
|
|
|
|
|
+ padding: 8px 0 6px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .analysis-card__stat {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+
|
|
|
|
|
+ & + .analysis-card__stat::before {
|
|
|
|
|
+ content: "";
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ left: 0;
|
|
|
|
|
+ top: 50%;
|
|
|
|
|
+ transform: translateY(-50%);
|
|
|
|
|
+ width: 1px;
|
|
|
|
|
+ height: 32px;
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.06);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .analysis-card__stat-value {
|
|
|
|
|
+ font-size: 22px;
|
|
|
|
|
+ line-height: 27px;
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ margin-bottom: 2px;
|
|
|
|
|
+ height: 27px;
|
|
|
|
|
+
|
|
|
|
|
+ &.highlight {
|
|
|
|
|
+ color: #ff9f5a;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .num {
|
|
|
|
|
+ font-size: 22px;
|
|
|
|
|
+ font-weight: 600;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .unit {
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.5);
|
|
|
|
|
+ margin-left: 1px;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .analysis-card__stat-label {
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ line-height: 18px;
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.5);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .interact-section-head {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ margin: 16px 0 12px;
|
|
|
|
|
+
|
|
|
|
|
+ &__text {
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ line-height: 18px;
|
|
|
|
|
+ color: #727272;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__line {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ height: 1px;
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.08);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .soil-root-item {
|
|
|
|
|
+ margin-top: 12px;
|
|
|
|
|
+ padding: 1px;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 25%),
|
|
|
|
|
+ linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 25%);
|
|
|
|
|
+
|
|
|
|
|
+ &__wrap {
|
|
|
|
|
+ padding: 11px 13px;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ background: linear-gradient(180deg, #1A191D 0%, #121216 100%);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ & + .soil-root-item {
|
|
|
|
|
+ margin-top: 16px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__title {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ color: #FFD489;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__icon {
|
|
|
|
|
+ width: 18px;
|
|
|
|
|
+ height: 23px;
|
|
|
|
|
+ object-fit: contain;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .soil-section-card {
|
|
|
|
|
+ padding: 1px;
|
|
|
|
|
+ margin-top: 12px;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 25%),
|
|
|
|
|
+ linear-gradient(180deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0) 25%);
|
|
|
|
|
+
|
|
|
|
|
+ &__wrap {
|
|
|
|
|
+ padding: 11px 13px;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ background: linear-gradient(180deg, #1A191D 0%, #121216 100%);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__title {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ gap: 10px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ color: #FFD489;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__icon {
|
|
|
|
|
+ width: 18px;
|
|
|
|
|
+ height: 23px;
|
|
|
|
|
+ object-fit: contain;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__question {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-family: "PangMenZhengDao";
|
|
|
|
|
+ line-height: 20px;
|
|
|
|
|
+ color: #FFD489;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__options {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ &.soil-section-card__options {
|
|
|
|
|
+ display: grid;
|
|
|
|
|
+ grid-template-columns: repeat(3, 1fr);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__guide {
|
|
|
|
|
+ margin-top: 12px;
|
|
|
|
|
+ background: rgba(75, 74, 70, 0.2);
|
|
|
|
|
+ border-radius: 10px;
|
|
|
|
|
+ padding: 10px;
|
|
|
|
|
+
|
|
|
|
|
+ .section-title {
|
|
|
|
|
+ gap: 6px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .guide-icon {
|
|
|
|
|
+ width: 14px;
|
|
|
|
|
+ height: 14px;
|
|
|
|
|
+ object-fit: contain;
|
|
|
|
|
+ filter: grayscale(100%);
|
|
|
|
|
+ -webkit-filter: grayscale(100%);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &-desc {
|
|
|
|
|
+ margin: 8px 0;
|
|
|
|
|
+ font-size: 13px;
|
|
|
|
|
+ line-height: 20px;
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.55);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .interact-card {
|
|
|
|
|
+ padding: 10px 12px;
|
|
|
|
|
+ border-radius: 12px;
|
|
|
|
|
+ border: 1px solid rgba(255, 241, 217, 0.2);
|
|
|
|
|
+ background: linear-gradient(180deg, #1A191D 0%, #121216 100%);
|
|
|
|
|
+
|
|
|
|
|
+ &__head {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ gap: 8px;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+
|
|
|
|
|
+ .section-title {
|
|
|
|
|
+ margin-bottom: 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__submit {
|
|
|
|
|
+ flex-shrink: 0;
|
|
|
|
|
+ height: 27px;
|
|
|
|
|
+ padding: 0 15px;
|
|
|
|
|
+ border-radius: 24px;
|
|
|
|
|
+ background: rgba(255, 212, 137, 0.1);
|
|
|
|
|
+ border: 1px solid rgba(255, 212, 137, 0.4);
|
|
|
|
|
+ color: #FFD489;
|
|
|
|
|
+ font-size: 12px;
|
|
|
|
|
+ line-height: 27px;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+
|
|
|
|
|
+ &.disabled {
|
|
|
|
|
+ opacity: 0.35;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__question {
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ font-family: "PangMenZhengDao";
|
|
|
|
|
+ line-height: 20px;
|
|
|
|
|
+ color: #FFD489;
|
|
|
|
|
+ margin-bottom: 12px;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &__options {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ flex-wrap: wrap;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .interact-option {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ flex: auto;
|
|
|
|
|
+ min-width: 0;
|
|
|
|
|
+ min-height: 41px;
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.05);
|
|
|
|
|
+ border: 1px solid rgba(255, 255, 255, 0.12);
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ cursor: pointer;
|
|
|
|
|
+
|
|
|
|
|
+ &__text {
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ padding: 0 6px;
|
|
|
|
|
+ overflow: hidden;
|
|
|
|
|
+ text-overflow: ellipsis;
|
|
|
|
|
+ white-space: nowrap;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.7);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ &.selected {
|
|
|
|
|
+ border-color: rgba(255, 255, 255, 0.5);
|
|
|
|
|
+ background: rgba(255, 255, 255, 0.1);
|
|
|
|
|
+
|
|
|
|
|
+ .interact-option__text {
|
|
|
|
|
+ color: #fff;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .guide-card {
|
|
|
|
|
+ position: relative;
|
|
|
|
|
+ margin-top: 12px;
|
|
|
|
|
+ background: rgba(75, 74, 70, 0.2);
|
|
|
|
|
+ border-radius: 10px;
|
|
|
|
|
+ padding: 10px;
|
|
|
|
|
+
|
|
|
|
|
+ &__img {
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ }
|
|
|
|
|
+ .guide-card__img-box {
|
|
|
|
|
+ img {
|
|
|
|
|
+ display: block;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .section-title {
|
|
|
|
|
+ gap: 6px;
|
|
|
|
|
+ font-size: 14px;
|
|
|
|
|
+ color: rgba(255, 255, 255, 0.6);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .guide-icon {
|
|
|
|
|
+ width: 14px;
|
|
|
|
|
+ height: 14px;
|
|
|
|
|
+ object-fit: contain;
|
|
|
|
|
+ filter: grayscale(100%);
|
|
|
|
|
+ -webkit-filter: grayscale(100%);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .guide-card__upload-wrap {
|
|
|
|
|
+ position: absolute;
|
|
|
|
|
+ right: 25px;
|
|
|
|
|
+ bottom: 27px;
|
|
|
|
|
+ z-index: 10;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .guide-card__upload {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ align-items: center;
|
|
|
|
|
+ justify-content: center;
|
|
|
|
|
+ width: 52px;
|
|
|
|
|
+ height: 52px;
|
|
|
|
|
+ border-radius: 50%;
|
|
|
|
|
+ background: linear-gradient(90deg, #ffebc9 0%, #ffca6d 100%);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ .guide-card__upload-icon {
|
|
|
|
|
+ width: 18px;
|
|
|
|
|
+ height: 16px;
|
|
|
|
|
+ object-fit: contain;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+.bottom-btn-container {
|
|
|
|
|
+ display: flex;
|
|
|
|
|
+ justify-content: space-between;
|
|
|
|
|
+ gap: 12px;
|
|
|
|
|
+ width: 100%;
|
|
|
|
|
+
|
|
|
|
|
+ .bottom-btn {
|
|
|
|
|
+ padding: 0 25px;
|
|
|
|
|
+ border-radius: 8px;
|
|
|
|
|
+ font-size: 16px;
|
|
|
|
|
+ height: 40px;
|
|
|
|
|
+ line-height: 40px;
|
|
|
|
|
+ box-sizing: border-box;
|
|
|
|
|
+ font-weight: 500;
|
|
|
|
|
+ text-align: center;
|
|
|
|
|
+
|
|
|
|
|
+ &.primary-btn {
|
|
|
|
|
+ flex: 1;
|
|
|
|
|
+ background: linear-gradient(90deg, #ffebc9 0%, #ffca6d 100%);
|
|
|
|
|
+ color: #1a1408;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+</style>
|