index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. <template>
  2. <div class="home-index" :style="{ height: `calc(100vh - ${tabBarHeight}px)` }">
  3. <!-- <div class="banner-wrap" @click="handleBannerClick">
  4. <img class="banner-img" :src="bannerObj?.media?.[0]" alt="" />
  5. <div class="banner-title">
  6. <span class="van-multi-ellipsis--l2">{{ bannerObj?.title }}</span>
  7. </div>
  8. </div> -->
  9. <!-- 天气遮罩 -->
  10. <div class="weather-mask" v-show="isExpanded" @click="handleMaskClick"></div>
  11. <!-- 天气 -->
  12. <weather-info ref="weatherInfoRef" class="weather-info" @weatherExpanded="weatherExpanded" :isGarden="false"
  13. @changeGarden="changeGarden"></weather-info>
  14. <div class="expert-home">
  15. <div class="expert-banner" @click="handleExpertBannerClick">
  16. <img class="expert-banner-img" src="@/assets/img/home/banner.png" alt="">
  17. <div class="expert-desc">
  18. <img class="expert-desc-icon" src="@/assets/img/home/expert-text.png" alt="">
  19. <!-- <div class="desc-text"><span class="dotted"></span>您有一条长势报告,请查看</div> -->
  20. <div class="desc-text"><span class="dotted"></span>点击查看农情互动采集</div>
  21. </div>
  22. </div>
  23. </div>
  24. <!-- <div class="task-list">
  25. <div class="task-title">待办任务</div>
  26. <div class="bottom-tag">
  27. <div class="tag-card">
  28. <div class="card-content">
  29. <div class="card-main-text">干旱风险</div>
  30. <div class="card-sub-text">
  31. 气象风险
  32. </div>
  33. </div>
  34. </div>
  35. <div class="tag-card active">
  36. <div class="card-content">
  37. <div class="card-main-text">当天</div>
  38. <div class="card-sub-text">新梢长势评估</div>
  39. </div>
  40. </div>
  41. <div class="tag-card">
  42. <div class="card-content">
  43. <div class="card-main-text">3天后</div>
  44. <div class="card-sub-text">白点催醒</div>
  45. </div>
  46. </div>
  47. </div>
  48. </div> -->
  49. <knowledge-card />
  50. <!-- <template v-if="userType == 2">
  51. </template> -->
  52. <!-- <template v-else>
  53. <AgriculturalDynamics />
  54. </template> -->
  55. </div>
  56. <tip-popup v-model:show="showTipPopup" type="warning" text="请设置" highlightText="种植方案" buttonText="去设置"
  57. @confirm="handleBtn" :closeOnClickOverlay="false" :zIndex="9999" />
  58. <tip-popup v-model:show="showDronePhotoPopup" font type="success" text="无人机照片已上传完毕请您确认" buttonText="去确认"
  59. @confirm="hanldeDrone" :zIndex="9999" />
  60. <!-- 农事执行弹窗 -->
  61. <agri-execute-popup v-model:show="showAgriExecutePopup" :popupData="agriExecuteData" @later="handleAgriLater"
  62. @executed="handleAgriExecuted" />
  63. <!-- 提醒时间选择弹窗 -->
  64. <reminder-time-popup v-model:show="showReminderTimePopup" @confirm="handleReminderTimeConfirm" />
  65. <!-- 执行轨迹弹窗 -->
  66. <execute-trace-popup v-model:show="showExecuteTracePopup" @later="handleTraceLater" @confirm="handleTraceConfirm" />
  67. <tip-popup v-model:show="showReportPopup" type="success" text="请查看" buttonText="去查看" @confirm="handleReportBtn"
  68. :zIndex="9999">
  69. <template #default>
  70. <div class="report-text">您的农情报告已生成</div>
  71. </template>
  72. </tip-popup>
  73. </template>
  74. <script setup>
  75. import { ref, computed, onActivated, onMounted } from "vue";
  76. import { useStore } from "vuex";
  77. import weatherInfo from "@/components/weatherInfo.vue";
  78. import AgriculturalDynamics from "./components/AgriculturalDynamics.vue";
  79. import { useRouter, useRoute } from "vue-router";
  80. import wx from "weixin-js-sdk";
  81. import tipPopup from "@/components/popup/tipPopup.vue";
  82. import agriExecutePopup from "@/components/popup/agriExecutePopup.vue";
  83. import reminderTimePopup from "@/components/popup/reminderTimePopup.vue";
  84. import executeTracePopup from "@/components/popup/executeTracePopup.vue";
  85. import knowledgeCard from "./components/knowledgeCard.vue";
  86. const store = useStore();
  87. const tabBarHeight = computed(() => store.state.home.tabBarHeight);
  88. const router = useRouter();
  89. const route = useRoute();
  90. const showDronePhotoPopup = ref(false)
  91. const hanldeDrone = () => {
  92. console.log('111')
  93. }
  94. const showTipPopup = ref(false);
  95. const handleBtn = () => {
  96. router.push("/plan?pageType=plant&headerTitle=请设置您的种植方案");
  97. };
  98. const handleReportBtn = () => {
  99. router.push({
  100. path: "/growth_report",
  101. query: { farmId: gardenId.value },
  102. });
  103. }
  104. // 农事执行弹窗相关
  105. const showAgriExecutePopup = ref(false); // 农事执行弹窗
  106. const agriExecuteData = ref({
  107. expertName: "韦帮稳",
  108. title: "梢期杀虫 农事执行",
  109. abnormalText: "由于***异常的出现,由于***异常的出现,由于***异常的出现,由于***异常的出现,",
  110. imageUrl: "",
  111. laterBtn: true,
  112. });
  113. // 农事执行弹窗相关方法
  114. const handleAgriLater = () => {
  115. console.log("稍后执行");
  116. // 可以在这里添加稍后执行的逻辑
  117. // 关闭当前弹窗
  118. showAgriExecutePopup.value = false;
  119. // 显示提醒时间选择弹窗
  120. showReminderTimePopup.value = true;
  121. };
  122. const handleAgriExecuted = () => {
  123. if (agriExecuteData.value.executedButtonText === '开始采集') {
  124. router.push("/interaction_list?expertMiniUserId=81881&oldUser=true");
  125. } else {
  126. // 显示执行轨迹弹窗
  127. showExecuteTracePopup.value = true;
  128. }
  129. // 关闭当前弹窗
  130. showAgriExecutePopup.value = false;
  131. };
  132. // 提醒时间选择弹窗相关
  133. const showReminderTimePopup = ref(false);
  134. // 确认提醒时间
  135. const handleReminderTimeConfirm = (time) => {
  136. console.log("选择的提醒时间:", time);
  137. // 可以在这里添加提交提醒时间的逻辑
  138. };
  139. // 执行轨迹弹窗相关
  140. const showExecuteTracePopup = ref(false);
  141. // 稍后上传
  142. const handleTraceLater = () => {
  143. console.log("稍后上传");
  144. // 可以在这里添加稍后上传的逻辑
  145. };
  146. // 确认上传
  147. const handleTraceConfirm = () => {
  148. console.log("确认上传");
  149. // 可以在这里添加确认上传的逻辑
  150. };
  151. //判断是否存在可用方案
  152. async function checkExistsEnabledScheme() {
  153. const { data } = await VE_API.home.existsEnabledScheme({ containerId: null });
  154. if (!data && localStorage.getItem("SET_USER_CUR_ROLE") == 2) {
  155. showTipPopup.value = true;
  156. }
  157. }
  158. const gardenId = ref(null);
  159. const changeGarden = ({ id }) => {
  160. gardenId.value = id;
  161. getExpertByFarmId();
  162. getReport();
  163. };
  164. const expertInfo = ref({});
  165. const getExpertByFarmId = () => {
  166. VE_API.home.getExpertByFarmId({ farmId: gardenId.value }).then(({ data }) => {
  167. expertInfo.value = data || {};
  168. sessionStorage.setItem("expertId", data.appUserId);
  169. });
  170. };
  171. const showReportPopup = ref(false);
  172. const getReport = () => {
  173. if (!gardenId.value) return;
  174. VE_API.farm.growthReportByFarm({ farmId: gardenId.value, limit: 20, isRead: 0 ,generateStatus:1}).then(({ data }) => {
  175. if (data && data.length > 0) {
  176. showReportPopup.value = true;
  177. } else {
  178. showReportPopup.value = false;
  179. }
  180. });
  181. }
  182. // 监测卡片数据
  183. const monitorCards = ref({
  184. left: {
  185. title: "农情采集",
  186. content: "精准监测 科学决策",
  187. route: "/pest",
  188. },
  189. right: [
  190. {
  191. title: "病虫识别",
  192. content: "智能识别 快速诊断",
  193. route: "/pest",
  194. },
  195. // {
  196. // title: "新增客户",
  197. // content: "农情先知 高效管理",
  198. // route: "/create_farm?type=client&isReload=true&from=home",
  199. // },
  200. ],
  201. });
  202. // 卡片点击事件
  203. const handleCardClick = (card) => {
  204. const dropdownGardenItem = ref({
  205. organId: 766,
  206. periodId: 1,
  207. name: "荔博园",
  208. });
  209. if (card.title === "农情采集") {
  210. dropdownGardenItem.value.page = "create_farm";
  211. wx.miniProgram.navigateTo({
  212. url: `/pages/subPages/new_recognize/index?gardenData=${JSON.stringify(dropdownGardenItem.value)}`,
  213. });
  214. } else if (card.title === "病虫识别") {
  215. dropdownGardenItem.value.page = "album_recognize";
  216. wx.miniProgram.navigateTo({
  217. url: `/pages/subPages/new_recognize/index?gardenData=${JSON.stringify(dropdownGardenItem.value)}`,
  218. });
  219. } else {
  220. router.push(card.route);
  221. }
  222. };
  223. onActivated(() => {
  224. getManagerList();
  225. if (userType.value != 2) {
  226. checkExistsEnabledScheme()
  227. }
  228. getBannerList();
  229. // 检测是否从创建农场页面成功返回
  230. if (route.query.showSuccess === "true") {
  231. // 清除URL参数,避免刷新页面时再次显示弹窗
  232. router.replace({
  233. path: "/home",
  234. query: { reload: route.query.reload },
  235. });
  236. }
  237. });
  238. const userType = ref(localStorage.getItem("USER_TYPE"));
  239. onMounted(() => {
  240. if (userType.value != 2) {
  241. monitorCards.value.right.push({
  242. title: "新增客户",
  243. content: "农情先知 高效管理",
  244. route: "/create_farm?type=client&isReload=true&from=home",
  245. });
  246. }
  247. });
  248. // 查询当前农资店的成员列表(只保留有"任务接单"权限的成员)
  249. const getManagerList = async () => {
  250. const { data } = await VE_API.mine.listManagerList({ onlyExecutor: true });
  251. if (data && data.length > 0) {
  252. // 过滤 permissionList 中包含"任务接单"的成员,并过滤掉超管(role为1)
  253. const executorList = data.filter((item) => item.role !== 1);
  254. sessionStorage.setItem("executorList", JSON.stringify(executorList));
  255. }
  256. };
  257. const bannerObj = ref({});
  258. const getBannerList = () => {
  259. const params = {
  260. page: 1,
  261. limit: 1,
  262. topicId: 5,
  263. };
  264. VE_API.home.warningPageList(params).then(({ data }) => {
  265. bannerObj.value = data[0] || {};
  266. });
  267. };
  268. const isExpanded = ref(false);
  269. const weatherInfoRef = ref(null);
  270. const weatherExpanded = (isExpandedValue) => {
  271. isExpanded.value = isExpandedValue;
  272. };
  273. // 点击遮罩时收起天气
  274. const handleMaskClick = () => {
  275. if (weatherInfoRef.value && weatherInfoRef.value.toggleExpand) {
  276. weatherInfoRef.value.toggleExpand();
  277. }
  278. };
  279. const handleExpertBannerClick = () => {
  280. // router.push("/consult?userId=81881");
  281. router.push("/interaction_list?expertMiniUserId=81881");
  282. };
  283. const handleBannerClick = () => {
  284. router.push(`/warning_detail?id=${bannerObj.value.id}`);
  285. };
  286. </script>
  287. <style scoped lang="scss">
  288. .home-index {
  289. width: 100%;
  290. height: 100vh;
  291. overflow: auto;
  292. position: relative;
  293. // background: linear-gradient(180deg, #f4f9fd 0%, #f9f9f9 100%);
  294. background: linear-gradient(180deg, #F9F9F9 0%, #F0F8FF 31.47%, #F9F9F9 46.81%, #F9F9F9 100%);
  295. .banner-wrap {
  296. width: 100%;
  297. height: 200px;
  298. position: relative;
  299. z-index: 1;
  300. .banner-img {
  301. width: 100%;
  302. height: 100%;
  303. object-fit: cover;
  304. }
  305. .banner-title {
  306. position: absolute;
  307. bottom: 0;
  308. left: 0;
  309. width: 100%;
  310. padding: 10px 12px 34px 12px;
  311. box-sizing: border-box;
  312. background: linear-gradient(180deg,
  313. rgba(102, 102, 102, 0) -64.3%,
  314. rgba(0, 0, 0, 0.0074) -1.43%,
  315. rgba(0, 0, 0, 0.684747) 39.67%,
  316. rgba(0, 0, 0, 0.74) 40.09%,
  317. rgba(0, 0, 0, 0.74) 83.2%);
  318. color: #fff;
  319. font-weight: bold;
  320. backdrop-filter: blur(2px);
  321. }
  322. }
  323. .weather-mask {
  324. position: fixed;
  325. top: 0;
  326. left: 0;
  327. width: 100%;
  328. height: 100%;
  329. background-color: rgba(0, 0, 0, 0.52);
  330. z-index: 2;
  331. }
  332. .weather-info {
  333. width: calc(100% - 20px);
  334. position: absolute;
  335. // top: calc(200px - 28px);
  336. top: 8px;
  337. left: 10px;
  338. z-index: 3;
  339. }
  340. .expert-home {
  341. padding: 90px 10px 10px 10px;
  342. .expert-banner {
  343. position: relative;
  344. .expert-banner-img {
  345. width: 100%;
  346. }
  347. .expert-desc {
  348. position: absolute;
  349. bottom: 0;
  350. left: 0;
  351. width: 100%;
  352. border-radius: 0 0 8px 8px;
  353. padding: 6px 8px;
  354. box-sizing: border-box;
  355. background: rgba(0, 0, 0, 0.5);
  356. color: #fff;
  357. backdrop-filter: blur(4px);
  358. display: flex;
  359. align-items: center;
  360. justify-content: space-between;
  361. .expert-desc-icon {
  362. width: 91px;
  363. }
  364. .desc-text {
  365. font-family: "PangMenZhengDao";
  366. font-size: 14px;
  367. color: #fff;
  368. display: flex;
  369. align-items: center;
  370. justify-content: center;
  371. gap: 6px;
  372. .dotted {
  373. width: 5px;
  374. height: 5px;
  375. background: #fff;
  376. border-radius: 50%;
  377. }
  378. }
  379. }
  380. }
  381. }
  382. .task-list {
  383. padding: 0 10px 10px;
  384. .task-title {
  385. color: #000;
  386. margin: 6px 0 14px 0;
  387. font-weight: 500;
  388. font-size: 16px;
  389. line-height: 22px;
  390. position: relative;
  391. padding-left: 9px;
  392. &::after {
  393. content: "";
  394. position: absolute;
  395. left: 0;
  396. top: 50%;
  397. transform: translateY(-50%);
  398. width: 3px;
  399. height: 15px;
  400. background: #2199f8;
  401. border-radius: 20px;
  402. }
  403. }
  404. .bottom-tag {
  405. display: flex;
  406. gap: 4px;
  407. .tag-card {
  408. flex: 1;
  409. border-radius: 6px;
  410. padding: 8px 4px;
  411. box-sizing: border-box;
  412. background: rgba(201, 201, 201, 0.1);
  413. border: 0.5px solid transparent;
  414. .card-content {
  415. display: flex;
  416. flex-direction: column;
  417. align-items: center;
  418. justify-content: center;
  419. text-align: center;
  420. height: 100%;
  421. .card-main-text {
  422. font-size: 18px;
  423. line-height: 28px;
  424. font-weight: 400;
  425. color: #1D2129;
  426. margin-bottom: 2px;
  427. }
  428. .card-sub-text {
  429. font-size: 14px;
  430. line-height: 22px;
  431. color: #4E5969;
  432. display: flex;
  433. align-items: center;
  434. gap: 4px;
  435. .card-icon {
  436. display: inline-flex;
  437. align-items: center;
  438. justify-content: center;
  439. width: 12px;
  440. height: 12px;
  441. color: #2199f8;
  442. }
  443. }
  444. }
  445. &.active {
  446. background: rgba(33, 153, 248, 0.1);
  447. border-color: #2199f8;
  448. .card-content {
  449. .card-main-text {
  450. color: #2199f8;
  451. }
  452. .card-sub-text {
  453. color: #2199f8;
  454. }
  455. }
  456. }
  457. }
  458. }
  459. }
  460. }
  461. .report-text {
  462. font-size: 20px;
  463. }
  464. </style>