index.vue 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. <template>
  2. <custom-header v-if="isHeaderShow" name="农场详情"></custom-header>
  3. <div class="monitor-index" :style="{ height: `calc(100vh - ${tabBarHeight}px)` }">
  4. <!-- 天气遮罩 -->
  5. <div class="weather-mask" v-show="isExpanded" @click="handleMaskClick"></div>
  6. <!-- 天气 -->
  7. <weather-info ref="weatherInfoRef" from="agri_record" class="weather-info" @weatherExpanded="weatherExpanded"
  8. @changeGarden="changeGarden" @changeGardenTab="changeGardenTab" :isGarden="true"
  9. :gardenId="defaultGardenId"></weather-info>
  10. <!-- 农场列表 -->
  11. <div v-show="activeGardenTab === 'list'">
  12. <garden-list ref="gardenListRef" :garden-id="selectedGardenId" @loaded="handleGardenLoaded"
  13. @selectGarden="handleGardenSelected" />
  14. </div>
  15. <!-- 作物档案 -->
  16. <div class="archives-time-line" v-show="activeGardenTab === 'current'">
  17. <div class="trend-monitor-list">
  18. <div class="trend-monitor-card" @click="handleTrendMonitorCardClick(item)"
  19. v-for="(item, index) in trendMonitorMockList" :key="index">
  20. <div class="card-header">
  21. <div class="header-left">
  22. <span class="title">{{ item?.first_work?.work_name }}</span>
  23. <span class="level-tag">二级</span>
  24. </div>
  25. <div class="status-tag" v-if="item?.risk_level">待记录</div>
  26. </div>
  27. <div class="card-row">
  28. <div class="reason-text">{{ item?.first_work?.work_reason_short }}</div>
  29. <div class="question-tag">{{ item?.first_work?.interaction_issue }}</div>
  30. </div>
  31. <!-- <div class="record-list">
  32. <div class="record-item" v-for="(record, recordIndex) in item.records" :key="recordIndex">
  33. {{ record }}
  34. </div>
  35. </div> -->
  36. </div>
  37. </div>
  38. <div class="archives-time-line-content">
  39. <archives-farm-time-line :farmId="gardenId"></archives-farm-time-line>
  40. </div>
  41. </div>
  42. </div>
  43. </template>
  44. <script setup>
  45. import customHeader from "@/components/customHeader.vue";
  46. import { ref, computed, onActivated, onMounted } from "vue";
  47. import { useStore } from "vuex";
  48. import weatherInfo from "@/components/weatherInfo.vue";
  49. import { useRoute, useRouter } from "vue-router";
  50. import ArchivesFarmTimeLine from "@/components/pageComponents/ArchivesFarmTimeLine.vue";
  51. import gardenList from "@/components/gardenList.vue";
  52. const router = useRouter();
  53. const defaultGardenId = ref(null);
  54. const selectedGardenId = ref(null);
  55. const gardenListRef = ref(null);
  56. const activeGardenTab = ref('current');
  57. const trendMonitorMockList = ref([]);
  58. const changeGardenTab = (tab) => {
  59. activeGardenTab.value = tab;
  60. };
  61. const getFarmRiskAndTracking = async () => {
  62. trendMonitorMockList.value = [];
  63. const res = await VE_API.monitor.getFarmRiskAndTracking({
  64. farm_id: gardenId.value,
  65. crop_type: JSON.parse(localStorage.getItem("selectedFarmData")).farm_variety,
  66. });
  67. if (res.code === 200) {
  68. trendMonitorMockList.value.push(res.data?.growth_abnormal_tracking);
  69. trendMonitorMockList.value.push(res.data?.pest_risk_assessment);
  70. if (res.data?.phenology_tracking) {
  71. trendMonitorMockList.value.push(res.data?.phenology_tracking);
  72. }
  73. }
  74. }
  75. const handleGardenLoaded = ({ hasFarm }) => {
  76. weatherInfoRef.value?.setGardenLoaded?.(hasFarm);
  77. };
  78. const handleGardenSelected = (garden) => {
  79. selectedGardenId.value = garden?.id ?? null;
  80. weatherInfoRef.value?.setSelectedGarden?.(garden);
  81. };
  82. const isHeaderShow = ref(false);
  83. const weatherInfoRef = ref(null);
  84. onActivated(() => {
  85. // 用来接收我的农场跳转过来的农场详情逻辑
  86. if (route.query.isHeaderShow) {
  87. isHeaderShow.value = true;
  88. defaultGardenId.value = route.query.farmId;
  89. }
  90. const savedFarmId = localStorage.getItem("selectedFarmId");
  91. selectedGardenId.value = savedFarmId ? Number(savedFarmId) : null;
  92. gardenListRef.value?.refreshFarmList?.();
  93. });
  94. const store = useStore();
  95. const tabBarHeight = computed(() => store.state.home.tabBarHeight);
  96. const route = useRoute();
  97. const isExpanded = ref(false);
  98. const weatherExpanded = (isExpandedValue) => {
  99. isExpanded.value = isExpandedValue;
  100. };
  101. // 点击遮罩时收起天气
  102. const handleMaskClick = () => {
  103. if (weatherInfoRef.value && weatherInfoRef.value.toggleExpand) {
  104. weatherInfoRef.value.toggleExpand();
  105. }
  106. };
  107. const gardenId = ref(store.state.home.gardenId);
  108. // 初始化加载数据
  109. // onMounted(() => {
  110. // if (gardenId.value) {
  111. // getFarmRiskAndTracking();
  112. // }
  113. // });
  114. const changeGarden = ({ id }) => {
  115. gardenId.value = id;
  116. getFarmRiskAndTracking();
  117. // 更新 store 中的状态
  118. store.commit("home/SET_GARDEN_ID", id);
  119. };
  120. const handleTrendMonitorCardClick = (item) => {
  121. router.push({
  122. path: "/record_details",
  123. query: { workId: item.work_id, type: item.first_work.work_name },
  124. });
  125. }
  126. </script>
  127. <style scoped lang="scss">
  128. .monitor-index {
  129. width: 100%;
  130. height: 100%;
  131. box-sizing: border-box;
  132. background: linear-gradient(180deg, #2199F8 8%, #F5F5F5 19%, #F5F5F5 73%, #F5F5F5 100%);
  133. .weather-mask {
  134. position: fixed;
  135. top: 0;
  136. left: 0;
  137. width: 100%;
  138. height: 100%;
  139. background-color: rgba(0, 0, 0, 0.52);
  140. z-index: 11;
  141. }
  142. .weather-info {
  143. width: calc(100% - 20px);
  144. position: absolute;
  145. top: 10px;
  146. left: 10px;
  147. z-index: 12;
  148. }
  149. .trend-monitor-list {
  150. display: flex;
  151. flex-direction: column;
  152. gap: 12px;
  153. background: #fff;
  154. border: 1px solid #2199F8;
  155. border-radius: 8px;
  156. padding: 10px;
  157. .trend-monitor-card {
  158. border: 0.5px solid rgba(33, 153, 248, 0.5);
  159. border-radius: 4px;
  160. padding: 6px 8px;
  161. position: relative;
  162. .card-header {
  163. display: flex;
  164. align-items: center;
  165. margin-bottom: 6px;
  166. .header-left {
  167. display: flex;
  168. align-items: center;
  169. gap: 5px;
  170. .title {
  171. font-size: 16px;
  172. }
  173. .level-tag {
  174. padding: 1px 8px;
  175. border-radius: 2px;
  176. background: rgba(255, 78, 78, 0.1);
  177. color: #FF4E4E;
  178. font-size: 12px;
  179. }
  180. }
  181. .status-tag {
  182. background: #FF953D;
  183. color: #ffffff;
  184. font-size: 12px;
  185. border-radius: 0 4px 0 4px;
  186. padding: 2px 5px;
  187. position: absolute;
  188. top: 0;
  189. right: 0;
  190. }
  191. }
  192. .card-row {
  193. background: #F7F7F7;
  194. border-radius: 5px;
  195. padding: 5px;
  196. display: flex;
  197. align-items: center;
  198. justify-content: space-between;
  199. margin-bottom: 6px;
  200. font-size: 12px;
  201. color: #626262;
  202. .question-tag {
  203. background: #2b9af6;
  204. color: #ffffff;
  205. border-radius: 2px;
  206. padding: 2px 6px;
  207. }
  208. }
  209. .record-list {
  210. display: flex;
  211. gap: 6px;
  212. .record-item {
  213. border: 1px solid #2199F8;
  214. border-radius: 2px;
  215. color: #2199F8;
  216. text-align: center;
  217. font-size: 12px;
  218. padding: 0 5px;
  219. }
  220. }
  221. }
  222. }
  223. .archives-time-line {
  224. position: relative;
  225. height: calc(100% - 160px);
  226. padding: 12px;
  227. display: flex;
  228. flex-direction: column;
  229. min-height: 0;
  230. padding-top: 150px;
  231. overflow-y: auto;
  232. -webkit-overflow-scrolling: touch;
  233. .archives-time-line-content {
  234. margin-top: 10px;
  235. flex: none;
  236. min-height: 0;
  237. background: #fff;
  238. border-radius: 8px;
  239. padding: 10px;
  240. box-sizing: border-box;
  241. display: flex;
  242. flex-direction: column;
  243. }
  244. }
  245. }
  246. </style>