reportPanel.vue 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. <template>
  2. <div class="report-panel">
  3. <div v-for="item in reportList" :key="item.id" class="report-card" @click="handleReportClick(item)">
  4. <div class="report-card__cover">
  5. <img :src="item.cover" alt="" />
  6. <span class="report-card__date">{{ item.date }}</span>
  7. <span class="report-card__status">
  8. <i class="report-card__dot"></i>
  9. {{ t("agriFile.reportUpdate") }}
  10. </span>
  11. </div>
  12. <div class="report-card__body">
  13. <div class="report-card__title">{{ item.title }}</div>
  14. <div class="report-card__desc">{{ item.desc }}</div>
  15. </div>
  16. </div>
  17. </div>
  18. </template>
  19. <script setup>
  20. import { onActivated, onMounted, ref } from "vue";
  21. import { useI18n } from "@/i18n";
  22. import { useRouter } from "vue-router";
  23. const router = useRouter();
  24. const { t } = useI18n();
  25. // ---------- 常量 ----------
  26. const reportCover = require("@/assets/img/common/sd-1.jpg");
  27. // ---------- 页面状态 ----------
  28. const reportList = ref([]);
  29. // ---------- 工具函数 ----------
  30. const getSelectedFarm = () => {
  31. try {
  32. return JSON.parse(localStorage.getItem("selectedFarmData") || "{}");
  33. } catch {
  34. return {};
  35. }
  36. };
  37. const mapReportItem = (item, index) => ({
  38. id: item.id ?? `${item.time || ""}-${index}`,
  39. title: item.title || "",
  40. type: item.type || "",
  41. desc: item.content || "",
  42. date: item.time || "",
  43. cover: reportCover,
  44. });
  45. const handleReportClick = (item) => {
  46. router.push({
  47. path: "/alert_detail",
  48. query: {
  49. title: item?.title || "具体预警",
  50. type: item?.type || "warning",
  51. },
  52. });
  53. };
  54. // ---------- 业务逻辑:加载 ----------
  55. const fetchReportList = async () => {
  56. const farm = getSelectedFarm();
  57. const farmId = farm.farm_id ?? farm.id;
  58. const zoneId = farm.zone_id ?? farm.zoneId;
  59. if (farmId == null || farmId === "" || zoneId == null || zoneId === "") {
  60. reportList.value = [];
  61. return;
  62. }
  63. try {
  64. const res = await VE_API.questionnaire.getReportList({
  65. farm_id: farmId,
  66. zone_id: zoneId,
  67. });
  68. const reports = Array.isArray(res?.data?.reports) ? res.data.reports : [];
  69. reportList.value = reports.map(mapReportItem);
  70. } catch {
  71. reportList.value = [];
  72. }
  73. };
  74. // ---------- 生命周期 ----------
  75. onMounted(fetchReportList);
  76. onActivated(fetchReportList);
  77. </script>
  78. <style lang="scss" scoped>
  79. .report-panel {
  80. .report-card {
  81. margin-bottom: 10px;
  82. border-radius: 8px;
  83. background: #fff;
  84. &:last-child {
  85. margin-bottom: 0;
  86. }
  87. &__cover {
  88. position: relative;
  89. width: 100%;
  90. height: 158px;
  91. img {
  92. display: block;
  93. width: 100%;
  94. height: 100%;
  95. object-fit: cover;
  96. border-radius: 5px;
  97. }
  98. }
  99. &__date {
  100. position: absolute;
  101. top: 0;
  102. padding: 5px 12px;
  103. border-radius: 4px;
  104. background: rgba(0, 0, 0, 0.45);
  105. backdrop-filter: blur(4px);
  106. color: #fff;
  107. font-size: 16px;
  108. border-radius: 5px 0 5px 0;
  109. }
  110. &__status {
  111. position: absolute;
  112. top: 10px;
  113. right: 0;
  114. display: flex;
  115. align-items: center;
  116. gap: 4px;
  117. padding: 2px 13px;
  118. border-radius: 20px 0 0 20px;
  119. background: #ff5454;
  120. color: #fff;
  121. font-size: 12px;
  122. }
  123. &__dot {
  124. width: 6px;
  125. height: 6px;
  126. border-radius: 50%;
  127. background: #fff;
  128. }
  129. &__body {
  130. padding: 10px;
  131. margin-top: 4px;
  132. }
  133. &__title {
  134. font-size: 16px;
  135. font-weight: 500;
  136. }
  137. &__desc {
  138. margin-top: 4px;
  139. color: #9e9b9b;
  140. }
  141. }
  142. }
  143. </style>