Kaynağa Gözat

fix: 增加报告返回结果前的loading

lxf 4 gün önce
ebeveyn
işleme
4f998d32d8

+ 5 - 0
src/api/modules/questionnaire.js

@@ -106,4 +106,9 @@ module.exports = {
         url: config.base_new_url + "report/query_tmp_image",
         type: "get",
     },
+    // 查询气象报告是否生成
+    checkWeatherReportGenerated: {
+        url: config.base_new_url + "report/check_stress_report",
+        type: "get",
+    },
 }

+ 61 - 23
src/views/old_mini/growth_report/components/CropAlertPanel.vue

@@ -65,31 +65,40 @@
 
                     <div class="alert-list" v-show="!isBackground">
                         <div
-                            v-for="(item, index) in alertCards"
-                            :key="index"
-                            class="alert-card"
-                        >
-                            <div class="alert-card__header">
-                                <div class="alert-card__title-wrap">
-                                    <img class="alert-card__icon" :src="item.icon" alt="" />
-                                    <span class="alert-card__title">{{ item.title }}</span>
+                            v-if="reportGenerating"
+                            class="alert-generating"
+                            v-loading="true"
+                            element-loading-text="报告生成中,请稍后..."
+                            element-loading-background="rgba(255, 255, 255, 0.9)"
+                        ></div>
+                        <template v-else>
+                            <div
+                                v-for="(item, index) in alertCards"
+                                :key="index"
+                                class="alert-card"
+                            >
+                                <div class="alert-card__header">
+                                    <div class="alert-card__title-wrap">
+                                        <img class="alert-card__icon" :src="item.icon" alt="" />
+                                        <span class="alert-card__title">{{ item.title }}</span>
+                                    </div>
+                                    <span class="alert-card__link" @click="handleViewDetail(item)">
+                                        查看详情
+                                    </span>
+                                </div>
+                                <div class="alert-card__content-wrap">
+                                    <span class="alert-card__content">{{ item.content }}</span>
+                                    <span
+                                        v-if="item.patrolTip"
+                                        class="alert-card__patrol"
+                                        @click="handlePatrolTip(item)"
+                                    >
+                                        <el-icon class="alert-card__patrol-icon"><Link /></el-icon>
+                                        <span>{{ item.patrolTip }}</span>
+                                    </span>
                                 </div>
-                                <span class="alert-card__link" @click="handleViewDetail(item)">
-                                    查看详情
-                                </span>
-                            </div>
-                            <div class="alert-card__content-wrap">
-                                <span class="alert-card__content">{{ item.content }}</span>
-                                <span
-                                    v-if="item.patrolTip"
-                                    class="alert-card__patrol"
-                                    @click="handlePatrolTip(item)"
-                                >
-                                    <el-icon class="alert-card__patrol-icon"><Link /></el-icon>
-                                    <span>{{ item.patrolTip }}</span>
-                                </span>
                             </div>
-                        </div>
+                        </template>
                     </div>
                 </div>
             </div>
@@ -142,6 +151,11 @@ const props = defineProps({
         type: String,
         default: "",
     },
+    /** 气象报告生成中(stress 为空且 check 返回 status=0) */
+    reportGenerating: {
+        type: Boolean,
+        default: false,
+    },
 });
 
 const emit = defineEmits(["switchCategory", "viewDetail", "heightChange"]);
@@ -267,6 +281,13 @@ watch(
     }
 );
 
+watch(
+    () => props.reportGenerating,
+    () => {
+        nextTick(() => syncMidAnchor());
+    }
+);
+
 const alertCards = computed(() => [
     {
         id: "warning",
@@ -495,6 +516,23 @@ onBeforeUnmount(() => {
         display: flex;
         flex-direction: column;
         gap: 10px;
+        :deep(.el-loading-spinner) {
+            top: 38%;
+        }
+    }
+
+    .alert-generating {
+        min-height: 120px;
+        padding: 14px 12px;
+        border-radius: 12px;
+        background: #fff;
+        box-sizing: border-box;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        font-size: 14px;
+        color: #86909c;
+        text-align: center;
     }
 
     .alert-card {

+ 89 - 6
src/views/old_mini/growth_report/index.vue

@@ -45,6 +45,7 @@
             :weather-stress="weatherStress"
             :weather-risk-explain="weatherRiskExplain"
             :weather-stress-explain="weatherStressExplain"
+            :report-generating="reportGenerating"
             @switch-category="handleSwitchCategory"
             @view-detail="handleViewDetail"
             @patrol-tip="handlePatrolTip"
@@ -64,7 +65,7 @@
 </template>
 
 <script setup>
-import { computed, nextTick, onActivated, onMounted, ref } from "vue";
+import { computed, nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref } from "vue";
 import { useRoute, useRouter } from "vue-router";
 import { useStore } from "vuex";
 import { Close, LocationFilled } from "@element-plus/icons-vue";
@@ -131,6 +132,8 @@ const weatherStress = ref(entryFarmData?.weatherStress || "某某胁迫");
 const weatherRiskExplain = ref("");
 /** 当下胁迫正文:stress_report.explain_simple */
 const weatherStressExplain = ref("");
+/** stress_report 为空时,气象报告生成中 */
+const reportGenerating = ref(false);
 const activeMenuKey = ref("hot-drought-2");
 const panelHeight = ref(280);
 const inviteBottom = computed(() => panelHeight.value);
@@ -139,6 +142,9 @@ const invitePopupRef = ref(null);
 const showInteractCard = ref(false);
 const interactQuestionText = ref("");
 
+const CHECK_REPORT_INTERVAL_MS = 3000;
+let checkWeatherReportTimer = null;
+
 function resolveUserTel() {
     const entry = readEntryFarmData();
     if (entry?.phone) return String(entry.phone).trim();
@@ -150,9 +156,55 @@ function resolveUserTel() {
     }
 }
 
+function stopCheckWeatherReport() {
+    if (checkWeatherReportTimer) {
+        clearTimeout(checkWeatherReportTimer);
+        checkWeatherReportTimer = null;
+    }
+}
+
+/** stress 为空时轮询 check_stress_report,status=1 后再拉 risk */
+async function pollWeatherReportGenerated() {
+    const tel = resolveUserTel();
+    if (!tel) {
+        reportGenerating.value = false;
+        stopCheckWeatherReport();
+        return;
+    }
+    try {
+        const raw = await VE_API.questionnaire.checkWeatherReportGenerated({ tel });
+        const res = Array.isArray(raw) ? raw[0] : raw;
+        const status = Number(res?.data?.status);
+        if (status === 0) {
+            reportGenerating.value = true;
+            stopCheckWeatherReport();
+            checkWeatherReportTimer = setTimeout(pollWeatherReportGenerated, CHECK_REPORT_INTERVAL_MS);
+            return;
+        }
+        if (status === 1) {
+            stopCheckWeatherReport();
+            reportGenerating.value = false;
+            await fetchRiskReport();
+            // 生成完成后补拉胁迫正文(避免仍显示空)
+            await fetchStressReportAfterReady(tel);
+            return;
+        }
+        reportGenerating.value = false;
+        stopCheckWeatherReport();
+    } catch {
+        reportGenerating.value = false;
+        stopCheckWeatherReport();
+    }
+}
+
+function startCheckWeatherReport() {
+    reportGenerating.value = true;
+    stopCheckWeatherReport();
+    pollWeatherReportGenerated();
+}
+
 /** 未来预警卡片:risk_report → explain_simple */
 async function fetchRiskReport() {
-    // TODO: 接口有正式数据后改回 resolveUserTel()
     const tel = resolveUserTel();
     if (!tel) {
         weatherRiskExplain.value = "";
@@ -174,12 +226,13 @@ async function fetchRiskReport() {
     }
 }
 
-/** 当下胁迫卡片:stress_report → explain_simple */
+/** 当下胁迫卡片:stress_report → explain_simple;空数组则轮询是否生成中 */
 async function fetchStressReport() {
-    // TODO: 接口有正式数据后改回 resolveUserTel()
     const tel = resolveUserTel();
     if (!tel) {
         weatherStressExplain.value = "";
+        reportGenerating.value = false;
+        stopCheckWeatherReport();
         return;
     }
     try {
@@ -190,6 +243,32 @@ async function fetchStressReport() {
             return;
         }
         const data = res.data;
+        // 报告尚未落库:空数组 → 查生成状态
+        if (Array.isArray(data) && data.length === 0) {
+            weatherStressExplain.value = "";
+            startCheckWeatherReport();
+            return;
+        }
+        stopCheckWeatherReport();
+        reportGenerating.value = false;
+        const item = Array.isArray(data) ? data[0] : data;
+        weatherStressExplain.value =
+            item?.explain_simple || item?.interact_explain || "";
+    } catch {
+        weatherStressExplain.value = "";
+    }
+}
+
+/** 生成完成后只取正文,不再触发轮询 */
+async function fetchStressReportAfterReady(tel) {
+    try {
+        const raw = await VE_API.questionnaire.stressReport({ tel });
+        const res = Array.isArray(raw) ? raw[0] : raw;
+        if (Number(res?.code) !== 200 || !res.data) {
+            weatherStressExplain.value = "";
+            return;
+        }
+        const data = res.data;
         const item = Array.isArray(data) ? data[0] : data;
         weatherStressExplain.value =
             item?.explain_simple || item?.interact_explain || "";
@@ -456,8 +535,6 @@ onMounted(() => {
     initMap();
     tryOpenInviteEntryPopup();
     fetchAbnormalContent();
-    fetchRiskReport();
-    fetchStressReport();
 });
 onActivated(() => {
     syncEntryFarmData();
@@ -469,6 +546,12 @@ onActivated(() => {
     fetchRiskReport();
     fetchStressReport();
 });
+onDeactivated(() => {
+    stopCheckWeatherReport();
+});
+onBeforeUnmount(() => {
+    stopCheckWeatherReport();
+});
 </script>
 
 <style lang="scss" scoped>