index.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  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. getExpertBySubjectId();
  162. getReport();
  163. };
  164. const expertInfo = ref({});
  165. const getExpertBySubjectId = () => {
  166. VE_API.home.getExpertBySubjectId({ subjectId: gardenId.value }).then(({ data, code }) => {
  167. if(code === 0) {
  168. expertInfo.value = data || {};
  169. sessionStorage.setItem("expertId", data.appUserId);
  170. }
  171. });
  172. };
  173. const showReportPopup = ref(false);
  174. const getReport = () => {
  175. if (!gardenId.value) return;
  176. VE_API.farm.growthReportBySubject({ subjectId: gardenId.value, limit: 20, isRead: 0 ,generateStatus:1}).then(({ data }) => {
  177. if (data && data.length > 0) {
  178. showReportPopup.value = true;
  179. } else {
  180. showReportPopup.value = false;
  181. }
  182. });
  183. }
  184. // 监测卡片数据
  185. const monitorCards = ref({
  186. left: {
  187. title: "农情采集",
  188. content: "精准监测 科学决策",
  189. route: "/pest",
  190. },
  191. right: [
  192. {
  193. title: "病虫识别",
  194. content: "智能识别 快速诊断",
  195. route: "/pest",
  196. },
  197. // {
  198. // title: "新增客户",
  199. // content: "农情先知 高效管理",
  200. // route: "/create_farm?type=client&isReload=true&from=home",
  201. // },
  202. ],
  203. });
  204. // 卡片点击事件
  205. const handleCardClick = (card) => {
  206. const dropdownGardenItem = ref({
  207. organId: 766,
  208. periodId: 1,
  209. name: "荔博园",
  210. });
  211. if (card.title === "农情采集") {
  212. dropdownGardenItem.value.page = "create_farm";
  213. wx.miniProgram.navigateTo({
  214. url: `/pages/subPages/new_recognize/index?gardenData=${JSON.stringify(dropdownGardenItem.value)}`,
  215. });
  216. } else if (card.title === "病虫识别") {
  217. dropdownGardenItem.value.page = "album_recognize";
  218. wx.miniProgram.navigateTo({
  219. url: `/pages/subPages/new_recognize/index?gardenData=${JSON.stringify(dropdownGardenItem.value)}`,
  220. });
  221. } else {
  222. router.push(card.route);
  223. }
  224. };
  225. onActivated(() => {
  226. getManagerList();
  227. // if (userType.value != 2) {
  228. // checkExistsEnabledScheme()
  229. // }
  230. getBannerList();
  231. // 检测是否从创建农场页面成功返回
  232. if (route.query.showSuccess === "true") {
  233. // 清除URL参数,避免刷新页面时再次显示弹窗
  234. router.replace({
  235. path: "/home",
  236. query: { reload: route.query.reload },
  237. });
  238. }
  239. sessionStorage.removeItem('interactionListScrollTop');
  240. });
  241. const userType = ref(localStorage.getItem("USER_TYPE"));
  242. onMounted(() => {
  243. if (userType.value != 2) {
  244. monitorCards.value.right.push({
  245. title: "新增客户",
  246. content: "农情先知 高效管理",
  247. route: "/create_farm?type=client&isReload=true&from=home",
  248. });
  249. }
  250. });
  251. // 查询当前农资店的成员列表(只保留有"任务接单"权限的成员)
  252. const getManagerList = async () => {
  253. const { data } = await VE_API.mine.listManagerList({ onlyExecutor: true });
  254. if (data && data.length > 0) {
  255. // 过滤 permissionList 中包含"任务接单"的成员,并过滤掉超管(role为1)
  256. const executorList = data.filter((item) => item.role !== 1);
  257. sessionStorage.setItem("executorList", JSON.stringify(executorList));
  258. }
  259. };
  260. const bannerObj = ref({});
  261. const getBannerList = () => {
  262. const params = {
  263. page: 1,
  264. limit: 1,
  265. topicId: 5,
  266. };
  267. VE_API.home.warningPageList(params).then(({ data }) => {
  268. bannerObj.value = data[0] || {};
  269. });
  270. };
  271. const isExpanded = ref(false);
  272. const weatherInfoRef = ref(null);
  273. const weatherExpanded = (isExpandedValue) => {
  274. isExpanded.value = isExpandedValue;
  275. };
  276. // 点击遮罩时收起天气
  277. const handleMaskClick = () => {
  278. if (weatherInfoRef.value && weatherInfoRef.value.toggleExpand) {
  279. weatherInfoRef.value.toggleExpand();
  280. }
  281. };
  282. const handleExpertBannerClick = () => {
  283. // router.push("/consult?userId=81881");
  284. router.push("/interaction_list?expertMiniUserId=81881");
  285. };
  286. const handleBannerClick = () => {
  287. router.push(`/warning_detail?id=${bannerObj.value.id}`);
  288. };
  289. </script>
  290. <style scoped lang="scss">
  291. .home-index {
  292. width: 100%;
  293. height: 100vh;
  294. overflow: auto;
  295. position: relative;
  296. // background: linear-gradient(180deg, #f4f9fd 0%, #f9f9f9 100%);
  297. background: linear-gradient(180deg, #F9F9F9 0%, #F0F8FF 31.47%, #F9F9F9 46.81%, #F9F9F9 100%);
  298. .banner-wrap {
  299. width: 100%;
  300. height: 200px;
  301. position: relative;
  302. z-index: 1;
  303. .banner-img {
  304. width: 100%;
  305. height: 100%;
  306. object-fit: cover;
  307. }
  308. .banner-title {
  309. position: absolute;
  310. bottom: 0;
  311. left: 0;
  312. width: 100%;
  313. padding: 10px 12px 34px 12px;
  314. box-sizing: border-box;
  315. background: linear-gradient(180deg,
  316. rgba(102, 102, 102, 0) -64.3%,
  317. rgba(0, 0, 0, 0.0074) -1.43%,
  318. rgba(0, 0, 0, 0.684747) 39.67%,
  319. rgba(0, 0, 0, 0.74) 40.09%,
  320. rgba(0, 0, 0, 0.74) 83.2%);
  321. color: #fff;
  322. font-weight: bold;
  323. backdrop-filter: blur(2px);
  324. }
  325. }
  326. .weather-mask {
  327. position: fixed;
  328. top: 0;
  329. left: 0;
  330. width: 100%;
  331. height: 100%;
  332. background-color: rgba(0, 0, 0, 0.52);
  333. z-index: 2;
  334. }
  335. .weather-info {
  336. width: calc(100% - 20px);
  337. position: absolute;
  338. // top: calc(200px - 28px);
  339. top: 8px;
  340. left: 10px;
  341. z-index: 3;
  342. }
  343. .expert-home {
  344. padding: 90px 10px 10px 10px;
  345. .expert-banner {
  346. position: relative;
  347. .expert-banner-img {
  348. width: 100%;
  349. }
  350. .expert-desc {
  351. position: absolute;
  352. bottom: 0;
  353. left: 0;
  354. width: 100%;
  355. border-radius: 0 0 8px 8px;
  356. padding: 6px 8px;
  357. box-sizing: border-box;
  358. background: rgba(0, 0, 0, 0.5);
  359. color: #fff;
  360. backdrop-filter: blur(4px);
  361. display: flex;
  362. align-items: center;
  363. justify-content: space-between;
  364. .expert-desc-icon {
  365. width: 91px;
  366. }
  367. .desc-text {
  368. font-family: "PangMenZhengDao";
  369. font-size: 14px;
  370. color: #fff;
  371. display: flex;
  372. align-items: center;
  373. justify-content: center;
  374. gap: 6px;
  375. .dotted {
  376. width: 5px;
  377. height: 5px;
  378. background: #fff;
  379. border-radius: 50%;
  380. }
  381. }
  382. }
  383. }
  384. }
  385. .task-list {
  386. padding: 0 10px 10px;
  387. .task-title {
  388. color: #000;
  389. margin: 6px 0 14px 0;
  390. font-weight: 500;
  391. font-size: 16px;
  392. line-height: 22px;
  393. position: relative;
  394. padding-left: 9px;
  395. &::after {
  396. content: "";
  397. position: absolute;
  398. left: 0;
  399. top: 50%;
  400. transform: translateY(-50%);
  401. width: 3px;
  402. height: 15px;
  403. background: #2199f8;
  404. border-radius: 20px;
  405. }
  406. }
  407. .bottom-tag {
  408. display: flex;
  409. gap: 4px;
  410. .tag-card {
  411. flex: 1;
  412. border-radius: 6px;
  413. padding: 8px 4px;
  414. box-sizing: border-box;
  415. background: rgba(201, 201, 201, 0.1);
  416. border: 0.5px solid transparent;
  417. .card-content {
  418. display: flex;
  419. flex-direction: column;
  420. align-items: center;
  421. justify-content: center;
  422. text-align: center;
  423. height: 100%;
  424. .card-main-text {
  425. font-size: 18px;
  426. line-height: 28px;
  427. font-weight: 400;
  428. color: #1D2129;
  429. margin-bottom: 2px;
  430. }
  431. .card-sub-text {
  432. font-size: 14px;
  433. line-height: 22px;
  434. color: #4E5969;
  435. display: flex;
  436. align-items: center;
  437. gap: 4px;
  438. .card-icon {
  439. display: inline-flex;
  440. align-items: center;
  441. justify-content: center;
  442. width: 12px;
  443. height: 12px;
  444. color: #2199f8;
  445. }
  446. }
  447. }
  448. &.active {
  449. background: rgba(33, 153, 248, 0.1);
  450. border-color: #2199f8;
  451. .card-content {
  452. .card-main-text {
  453. color: #2199f8;
  454. }
  455. .card-sub-text {
  456. color: #2199f8;
  457. }
  458. }
  459. }
  460. }
  461. }
  462. }
  463. }
  464. .report-text {
  465. font-size: 20px;
  466. }
  467. </style>