index.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. <template>
  2. <div class="monitor-index" :style="{ height: `calc(100vh - ${tabBarHeight}px)` }">
  3. <!-- 天气遮罩 -->
  4. <div class="weather-mask" v-show="isExpanded"></div>
  5. <!-- 天气 -->
  6. <weather-info class="weather-info" @weatherExpanded="weatherExpanded" :isGarden="true"></weather-info>
  7. <!-- 操作按钮 -->
  8. <div class="operation-button">
  9. <div class="button-group">
  10. <div class="button-item" @click="toFarmInfo">
  11. <img class="button-icon" src="@/assets/img/tab_bar/home-active.png" alt="" />
  12. <span>基本信息</span>
  13. </div>
  14. <div class="button-item" @click="toFarmPhoto">
  15. <img class="button-icon" src="@/assets/img/home/photo-icon.png" alt="" />
  16. <span>农场相册</span>
  17. </div>
  18. </div>
  19. <badge dot :offset="[-4, 5]">
  20. <div class="add-farm-button">
  21. <img class="icon" src="@/assets/img/monitor/notice.png" alt="" />
  22. <span>农场消息</span>
  23. </div>
  24. </badge>
  25. </div>
  26. <!-- 功能卡片网格 -->
  27. <div class="function-cards">
  28. <div
  29. v-for="(card, index) in functionCards"
  30. :key="index"
  31. class="function-card"
  32. @click="handleCardClick(card)"
  33. >
  34. <img :src="require(`@/assets/img/monitor/grid-${index + 1}.png`)" :alt="card.title" />
  35. <div class="card-title">{{ card.title }}</div>
  36. <div class="card-status">
  37. {{ card.status }}
  38. </div>
  39. </div>
  40. </div>
  41. <!-- 实时播报 -->
  42. <div class="realtime-broadcast">
  43. <div class="broadcast-header">
  44. <div class="header-left">
  45. <span class="broadcast-title">实时播报</span>
  46. <div class="broadcast-action" @click="handleBroadcast">
  47. <img class="speaker-icon" src="@/assets/img/monitor/speaker.png" alt="播报" />
  48. <span class="broadcast-text">点击播报</span>
  49. </div>
  50. </div>
  51. <div class="more-link" @click="handleMoreBroadcast">
  52. <span>更多</span>
  53. <el-icon size="12"><ArrowRightBold /></el-icon>
  54. </div>
  55. </div>
  56. <div class="broadcast-list">
  57. <div
  58. v-for="(item, index) in broadcastList"
  59. :key="index"
  60. class="broadcast-item"
  61. @click="handleBroadcastItem(item)"
  62. >
  63. <div class="item-content">
  64. <div class="content-top">
  65. <div class="item-icon">
  66. <img src="@/assets/img/monitor/bell.png" alt="通知" />
  67. </div>
  68. <div class="item-title">{{ item.title }}</div>
  69. </div>
  70. <div class="item-status">
  71. 距离执行还差 <span class="countdown">{{ item.daysLeft }}</span> 天
  72. </div>
  73. </div>
  74. <div class="item-zone">
  75. <div class="point"></div>
  76. <span>{{ item.zone }}</span>
  77. </div>
  78. </div>
  79. </div>
  80. </div>
  81. </div>
  82. </template>
  83. <script setup>
  84. import { ref, computed, onMounted } from "vue";
  85. import { useStore } from "vuex";
  86. import { Badge } from "vant";
  87. import weatherInfo from "@/components/weatherInfo.vue";
  88. import { useRouter } from "vue-router";
  89. const store = useStore();
  90. const tabBarHeight = computed(() => store.state.home.tabBarHeight);
  91. const router = useRouter();
  92. // 功能卡片数据
  93. const functionCards = ref([
  94. {
  95. title: "农事规划",
  96. status: "2 待执行",
  97. route: "/agricultural-planning",
  98. },
  99. {
  100. title: "农场报告",
  101. status: "最新",
  102. route: "/farm-report",
  103. },
  104. {
  105. title: "农事方案",
  106. status: "2 待执行",
  107. route: "/agricultural-scheme",
  108. },
  109. {
  110. title: "复核成效",
  111. status: "最新",
  112. route: "/review-results",
  113. },
  114. ]);
  115. // 实时播报数据
  116. const broadcastList = ref([
  117. {
  118. title: "某莫普农事未执行未执行",
  119. daysLeft: 3,
  120. zone: "2区",
  121. },
  122. {
  123. title: "某莫普农事未执行未执行",
  124. daysLeft: 3,
  125. zone: "2区",
  126. },
  127. {
  128. title: "某莫普农事未执行未执行",
  129. daysLeft: 3,
  130. zone: "2区",
  131. },
  132. {
  133. title: "某莫普农事未执行未执行",
  134. daysLeft: 3,
  135. zone: "2区",
  136. },
  137. ]);
  138. // 卡片点击事件
  139. const handleCardClick = (card) => {
  140. console.log("卡片点击:", card);
  141. // router.push(card.route);
  142. };
  143. // 播报相关事件
  144. const handleBroadcast = () => {
  145. console.log("点击播报");
  146. // TODO: 实现播报功能
  147. };
  148. const handleMoreBroadcast = () => {
  149. console.log("查看更多播报");
  150. // TODO: 跳转到播报列表页面
  151. };
  152. const handleBroadcastItem = (item) => {
  153. console.log("播报项点击:", item);
  154. // TODO: 处理播报项点击事件
  155. };
  156. onMounted(() => {});
  157. const isExpanded = ref(false);
  158. const weatherExpanded = (isExpandedValue) => {
  159. isExpanded.value = isExpandedValue;
  160. };
  161. function toSubPage() {
  162. router.push("/create_farm?isFromHome=true");
  163. }
  164. function toFarmPhoto() {
  165. router.push({
  166. path: "/farm_photo",
  167. });
  168. }
  169. function toFarmInfo() {
  170. // farmInfoRef.value.handleShow();
  171. }
  172. </script>
  173. <style scoped lang="scss">
  174. .monitor-index {
  175. width: 100%;
  176. height: 100%;
  177. padding: 13px 10px;
  178. box-sizing: border-box;
  179. background-image: linear-gradient(250deg, #CBEBFF 0% ,#dceffd 50%,#e7f3fd 100%);
  180. .weather-mask {
  181. position: fixed;
  182. top: 0;
  183. left: 0;
  184. width: 100%;
  185. height: 100%;
  186. background-color: rgba(0, 0, 0, 0.52);
  187. z-index: 2;
  188. }
  189. .weather-info {
  190. width: calc(100% - 20px);
  191. position: absolute;
  192. z-index: 3;
  193. }
  194. .operation-button {
  195. position: absolute;
  196. top: 117px;
  197. left: 12px;
  198. width: calc(100% - 24px);
  199. z-index: 1;
  200. display: flex;
  201. align-items: center;
  202. justify-content: space-between;
  203. font-size: 12px;
  204. font-weight: 500;
  205. .button-group {
  206. display: flex;
  207. align-items: center;
  208. justify-content: space-between;
  209. .button-item {
  210. display: flex;
  211. align-items: center;
  212. justify-content: center;
  213. gap: 4px;
  214. color: rgba(0, 0, 0, 0.8);
  215. background-color: #fff;
  216. border: 1px solid #f2f2f2;
  217. .button-icon {
  218. width: 13px;
  219. height: 13px;
  220. }
  221. }
  222. .button-item:first-child {
  223. margin-right: 10px;
  224. }
  225. }
  226. .add-farm-button {
  227. display: flex;
  228. align-items: center;
  229. justify-content: center;
  230. gap: 4px;
  231. background: rgba(33, 153, 248, 0.1);
  232. border: 1px solid #fff;
  233. .icon {
  234. width: 14px;
  235. height: 14px;
  236. }
  237. }
  238. .button-item,
  239. .add-farm-button {
  240. border-radius: 25px;
  241. padding: 8px 12px;
  242. }
  243. }
  244. .function-cards {
  245. display: grid;
  246. grid-template-columns: 1fr 1fr;
  247. gap: 10px;
  248. margin-top: 155px;
  249. .function-card {
  250. background: #fff;
  251. border-radius: 12px;
  252. padding: 25px 0;
  253. box-shadow: 0 1px 6px rgba(0, 0, 0, 0.05);
  254. position: relative;
  255. display: flex;
  256. align-items: center;
  257. justify-content: center;
  258. gap: 10px;
  259. img {
  260. width: 30px;
  261. height: 30px;
  262. }
  263. .card-title {
  264. font-size: 14px;
  265. font-weight: 500;
  266. color: #1d2129;
  267. }
  268. .card-status {
  269. position: absolute;
  270. top: 0;
  271. right: 0;
  272. padding: 1px 4px;
  273. border-radius: 6px 8px 8px 2px;
  274. font-size: 10px;
  275. background: #2199f8;
  276. color: #fff;
  277. }
  278. }
  279. }
  280. .realtime-broadcast {
  281. margin-top: 10px;
  282. background: #fff;
  283. border-radius: 8px;
  284. box-sizing: border-box;
  285. padding: 12px;
  286. .broadcast-header {
  287. display: flex;
  288. align-items: center;
  289. justify-content: space-between;
  290. margin-bottom: 4px;
  291. .header-left {
  292. display: flex;
  293. align-items: center;
  294. gap: 12px;
  295. .broadcast-title {
  296. font-size: 16px;
  297. font-weight: 600;
  298. color: #1d2129;
  299. }
  300. .broadcast-action {
  301. display: flex;
  302. align-items: center;
  303. gap: 4px;
  304. .speaker-icon {
  305. width: 16px;
  306. height: 14px;
  307. }
  308. .broadcast-text {
  309. color: #2199f8;
  310. }
  311. }
  312. }
  313. .more-link {
  314. display: flex;
  315. align-items: center;
  316. color: #4e5969;
  317. }
  318. }
  319. .broadcast-list {
  320. overflow: auto;
  321. .broadcast-item {
  322. display: flex;
  323. align-items: center;
  324. justify-content: space-between;
  325. padding: 12px 0;
  326. border-bottom: 1px solid rgba(0, 0, 0, 0.1);
  327. &:last-child {
  328. border-bottom: none;
  329. }
  330. .item-content {
  331. .content-top{
  332. display: flex;
  333. align-items: center;
  334. }
  335. .item-icon {
  336. margin-right: 8px;
  337. background: rgba(255, 0, 0, 0.05);
  338. width: 26px;
  339. height: 26px;
  340. border-radius: 50%;
  341. display: flex;
  342. align-items: center;
  343. justify-content: center;
  344. img {
  345. width: 18px;
  346. height: 12px;
  347. }
  348. }
  349. .item-title {
  350. color: #1d2129;
  351. }
  352. .item-status {
  353. margin-top: 3px;
  354. font-size: 13px;
  355. color: rgba(29, 33, 41, 0.5);
  356. .countdown {
  357. color: #ff7254;
  358. }
  359. }
  360. }
  361. .item-zone {
  362. background: rgba(241, 243, 246, 0.5);
  363. color: #7c7e81;
  364. font-size: 12px;
  365. padding: 3px 11px;
  366. border-radius: 25px;
  367. display: flex;
  368. align-items: center;
  369. gap: 8px;
  370. .point {
  371. width: 6px;
  372. height: 6px;
  373. border-radius: 50%;
  374. background: rgba(124, 126, 129, 0.5);
  375. }
  376. }
  377. }
  378. }
  379. }
  380. }
  381. </style>