|
|
@@ -3,14 +3,12 @@
|
|
|
<div class="report-content">
|
|
|
<div class="map-container" ref="mapContainer"></div>
|
|
|
<!-- Overlay 宿主:无范围时挂到地图方框下方 -->
|
|
|
- <div
|
|
|
- ref="noRangeTipRef"
|
|
|
- class="no-range-tip"
|
|
|
- :style="{ display: noFarmRange ? 'inline-flex' : 'none' }"
|
|
|
- @click.stop="goAddZone('farm')"
|
|
|
- >
|
|
|
+ <div ref="noRangeTipRef" class="no-range-tip" :style="{ display: noFarmRange ? 'inline-flex' : 'none' }"
|
|
|
+ @click.stop="goAddZone('farm')">
|
|
|
<span>勾画区域,获地块级长势报告</span>
|
|
|
- <el-icon class="no-range-tip__arrow"><ArrowRight /></el-icon>
|
|
|
+ <el-icon class="no-range-tip__arrow">
|
|
|
+ <ArrowRight />
|
|
|
+ </el-icon>
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
@@ -22,7 +20,9 @@
|
|
|
<img class="interact-card__star" src="@/assets/img/agricultural/start.png" alt="" />
|
|
|
<span>长势互动</span>
|
|
|
</div>
|
|
|
- <el-icon class="interact-card__close" @click="showInteractCard = false"><Close /></el-icon>
|
|
|
+ <el-icon class="interact-card__close" @click="showInteractCard = false">
|
|
|
+ <Close />
|
|
|
+ </el-icon>
|
|
|
</div>
|
|
|
<div class="interact-card__qa">
|
|
|
<div class="interact-card__question">{{ interactQuestionText }}</div>
|
|
|
@@ -46,24 +46,17 @@
|
|
|
|
|
|
<!-- 左上角:位置切换 -->
|
|
|
<div v-if="!showInteractCard" class="location-bar">
|
|
|
- <el-icon class="location-bar__icon"><LocationFilled /></el-icon>
|
|
|
+ <el-icon class="location-bar__icon">
|
|
|
+ <LocationFilled />
|
|
|
+ </el-icon>
|
|
|
<span class="location-bar__name van-ellipsis">{{ locationName }}</span>
|
|
|
- <span
|
|
|
- v-if="hasSelectedFarm()"
|
|
|
- class="location-bar__action"
|
|
|
- @click="handleSwitchFarm"
|
|
|
- >切换农场</span>
|
|
|
+ <span v-if="hasSelectedFarm()" class="location-bar__action" @click="handleSwitchFarm">切换农场</span>
|
|
|
</div>
|
|
|
|
|
|
<!-- 左侧:气象底图图层菜单(有农场 getHomeMapCalc / 无农场 getHomeMapCalcByCounty) -->
|
|
|
<div v-if="stressMenuItems.length" class="side-menu side-menu--left">
|
|
|
- <div
|
|
|
- v-for="item in stressMenuItems"
|
|
|
- :key="item.key"
|
|
|
- class="side-menu__item"
|
|
|
- :class="{ active: activeMenuKey === item.key }"
|
|
|
- @click="handleSelectMenu(item.key)"
|
|
|
- >
|
|
|
+ <div v-for="item in stressMenuItems" :key="item.key" class="side-menu__item"
|
|
|
+ :class="{ active: activeMenuKey === item.key }" @click="handleSelectMenu(item.key)">
|
|
|
<img class="side-menu__icon" :src="base_img_url3 + item.icon_path" alt="" />
|
|
|
<div class="side-menu__text">
|
|
|
<span>{{ item.line1 }}</span>
|
|
|
@@ -72,38 +65,31 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <div
|
|
|
- v-if="activeLegendUrl"
|
|
|
- class="map-legend map-legend--image"
|
|
|
- :style="{ bottom: `${inviteBottom}px` }"
|
|
|
- >
|
|
|
+ <div v-if="activeLegendUrl" class="map-legend map-legend--image" :style="{ bottom: `${inviteBottom}px` }">
|
|
|
<img class="map-legend__img" :src="activeLegendUrl" alt="" />
|
|
|
</div>
|
|
|
|
|
|
<div class="invite-group" :style="{ bottom: `${inviteBottom}px` }">
|
|
|
<div class="invite-btn" @click="handleInvite('service')">
|
|
|
<img class="invite-icon" src="@/assets/img/home/user-icon.png" alt="">
|
|
|
- 邀请农服</div>
|
|
|
+ 邀请农服
|
|
|
+ </div>
|
|
|
<div class="invite-btn" @click="handleInvite('farmer')">
|
|
|
<img class="invite-icon" src="@/assets/img/home/user-icon.png" alt="">
|
|
|
- 邀请农户</div>
|
|
|
+ 邀请农户
|
|
|
+ </div>
|
|
|
</div>
|
|
|
|
|
|
- <crop-alert-panel
|
|
|
- :crop-name="currentCropName"
|
|
|
- :farm-id="selectedFarmId"
|
|
|
- :county-code="countyCode"
|
|
|
- @zone-change="handleZoneChange"
|
|
|
- @height-change="handlePanelHeightChange"
|
|
|
- />
|
|
|
+ <crop-alert-panel :crop-name="currentCropName" :farm-id="selectedFarmId" :county-code="countyCode"
|
|
|
+ @zone-change="handleZoneChange" @height-change="handlePanelHeightChange" />
|
|
|
</div>
|
|
|
|
|
|
<!-- 录入信息邀请弹窗:分享链接带 showInviteEntry 时展示 -->
|
|
|
<invite-entry-popup ref="invitePopupRef" />
|
|
|
|
|
|
-
|
|
|
- <!-- 恢复种植弹窗 -->
|
|
|
- <restore-planting-popup />
|
|
|
+
|
|
|
+ <!-- 恢复种植弹窗 -->
|
|
|
+ <restore-planting-popup />
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
@@ -304,8 +290,13 @@ const showInteractCard = ref(false);
|
|
|
const interactQuestionText = ref("");
|
|
|
const interactOptions = ref([]);
|
|
|
const selectedOptionId = ref(null);
|
|
|
-const currentInteractTask = ref(null);
|
|
|
const interactSubmitting = ref(false);
|
|
|
+/** getOuterRecords 返回的 records */
|
|
|
+const outerRecords = ref([]);
|
|
|
+/** 当前展示的 records 下标 */
|
|
|
+const currentRecordIndex = ref(-1);
|
|
|
+/** 防止切换分区时旧请求回写 */
|
|
|
+let interactFetchToken = 0;
|
|
|
|
|
|
function formatToday() {
|
|
|
const d = new Date();
|
|
|
@@ -324,39 +315,62 @@ function getRequestErrorMessage(err) {
|
|
|
return "提交失败,请稍后再试";
|
|
|
}
|
|
|
|
|
|
-function buildInteractSubmitPayload(answerText) {
|
|
|
- const task = currentInteractTask.value || {};
|
|
|
- const content = task.interact_content || {};
|
|
|
- return {
|
|
|
- zone_id: Number(task.zone_id ?? panelZoneId.value ?? getSelectedZoneId()),
|
|
|
- date: formatToday(),
|
|
|
- interact_code: task.interact_code || content.interact_code || "",
|
|
|
- interact_answer: answerText,
|
|
|
- };
|
|
|
-}
|
|
|
-
|
|
|
-function mapInteractOptionsFromContent(content) {
|
|
|
- const options = content?.interact_options;
|
|
|
- if (!Array.isArray(options)) return [];
|
|
|
- return options.map((name, index) => ({
|
|
|
+/** interact_options 可能是 JSON 字符串或数组 */
|
|
|
+function parseInteractOptions(raw) {
|
|
|
+ let list = raw;
|
|
|
+ if (typeof raw === "string") {
|
|
|
+ try {
|
|
|
+ list = JSON.parse(raw);
|
|
|
+ } catch {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!Array.isArray(list)) return [];
|
|
|
+ return list.map((name, index) => ({
|
|
|
id: index + 1,
|
|
|
name: String(name),
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
-function applyFirstInteractTask(task) {
|
|
|
- currentInteractTask.value = task || null;
|
|
|
- const content = task?.interact_content || {};
|
|
|
- const question = content.interact_problem || "";
|
|
|
- const options = mapInteractOptionsFromContent(content);
|
|
|
+function clearInteractCard() {
|
|
|
+ outerRecords.value = [];
|
|
|
+ currentRecordIndex.value = -1;
|
|
|
+ interactQuestionText.value = "";
|
|
|
+ interactOptions.value = [];
|
|
|
+ selectedOptionId.value = null;
|
|
|
+ showInteractCard.value = false;
|
|
|
+}
|
|
|
+
|
|
|
+function applyOuterRecordAt(index) {
|
|
|
+ const records = outerRecords.value;
|
|
|
+ if (!records.length || index < 0 || index >= records.length) {
|
|
|
+ clearInteractCard();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ currentRecordIndex.value = index;
|
|
|
+ const record = records[index] || {};
|
|
|
+ const question = record.interact_problem || "";
|
|
|
+ const options = parseInteractOptions(record.interact_options);
|
|
|
interactQuestionText.value = question;
|
|
|
interactOptions.value = options;
|
|
|
selectedOptionId.value = null;
|
|
|
showInteractCard.value = Boolean(question || options.length);
|
|
|
}
|
|
|
|
|
|
-async function handleInteractOptionClick(item) {
|
|
|
- if (interactSubmitting.value || !item?.name || !currentInteractTask.value) return;
|
|
|
+function buildInteractSubmitPayload(optionText) {
|
|
|
+ const record = outerRecords.value[currentRecordIndex.value] || {};
|
|
|
+ const zoneId = panelZoneId.value ?? getSelectedZoneId();
|
|
|
+ return {
|
|
|
+ zone_id: Number(zoneId),
|
|
|
+ date: formatToday(),
|
|
|
+ // interact_code: record.interact_code || "",
|
|
|
+ period_code: record.period_code || "",
|
|
|
+ // interact_option: optionText,
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
+async function submitInteractOption(item) {
|
|
|
+ if (interactSubmitting.value) return;
|
|
|
selectedOptionId.value = item.id;
|
|
|
interactSubmitting.value = true;
|
|
|
try {
|
|
|
@@ -377,18 +391,69 @@ async function handleInteractOptionClick(item) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/** 首项 → 上一条;末项 → 下一条;中间项提交 */
|
|
|
+async function handleInteractOptionClick(item) {
|
|
|
+ const options = interactOptions.value;
|
|
|
+ if (interactSubmitting.value || !item?.name || !options.length || currentRecordIndex.value < 0) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const isFirst = item.id === options[0]?.id;
|
|
|
+ const isLast = item.id === options[options.length - 1]?.id;
|
|
|
+ // 仅一项时按提交处理
|
|
|
+ if (options.length === 1 || (!isFirst && !isLast)) {
|
|
|
+ await submitInteractOption(item);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ selectedOptionId.value = item.id;
|
|
|
+ if (isFirst) {
|
|
|
+ if (currentRecordIndex.value > 0) {
|
|
|
+ applyOuterRecordAt(currentRecordIndex.value - 1);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ElMessage.info("已是第一条");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (isLast) {
|
|
|
+ if (currentRecordIndex.value < outerRecords.value.length - 1) {
|
|
|
+ applyOuterRecordAt(currentRecordIndex.value + 1);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ElMessage.info("已是最后一条");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
async function fetchInteractTask() {
|
|
|
const zoneId = panelZoneId.value ?? getSelectedZoneId();
|
|
|
- if (zoneId === "" || zoneId == null) return;
|
|
|
+ if (zoneId === "" || zoneId == null) {
|
|
|
+ clearInteractCard();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const token = ++interactFetchToken;
|
|
|
try {
|
|
|
- const res = await VE_API.questionnaire.getExternalInteractTasks({
|
|
|
+ const res = await VE_API.questionnaire.getOuterRecords({
|
|
|
zone_id: zoneId,
|
|
|
});
|
|
|
- const tasks = res?.data?.interact_tasks;
|
|
|
- const first = Array.isArray(tasks) ? tasks[0] : null;
|
|
|
- applyFirstInteractTask(first);
|
|
|
+ if (token !== interactFetchToken) return;
|
|
|
+ if (res?.code !== 200) {
|
|
|
+ clearInteractCard();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const data = res?.data || {};
|
|
|
+ const records = Array.isArray(data.records) ? data.records : [];
|
|
|
+ outerRecords.value = records;
|
|
|
+ if (!records.length) {
|
|
|
+ clearInteractCard();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // 默认展示与外层 interact_code 匹配的那一项
|
|
|
+ const matchedIndex = records.findIndex(
|
|
|
+ (item) => item?.interact_code && item.interact_code === data.interact_code
|
|
|
+ );
|
|
|
+ applyOuterRecordAt(matchedIndex >= 0 ? matchedIndex : 0);
|
|
|
} catch (e) {
|
|
|
- console.warn("[growth_report] getExternalInteractTasks failed", e);
|
|
|
+ if (token !== interactFetchToken) return;
|
|
|
+ console.warn("[growth_report] getOuterRecords failed", e);
|
|
|
+ clearInteractCard();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1041,11 +1106,13 @@ onActivated(() => {
|
|
|
color: #2199F8;
|
|
|
font-weight: 500;
|
|
|
font-size: 12px;
|
|
|
+
|
|
|
.invite-icon {
|
|
|
width: 16px;
|
|
|
}
|
|
|
}
|
|
|
- .invite-btn + .invite-btn {
|
|
|
+
|
|
|
+ .invite-btn+.invite-btn {
|
|
|
margin-top: 10px;
|
|
|
}
|
|
|
}
|