index.vue 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. <template>
  2. <div class="base-container no-events">
  3. <div class="content">
  4. <!-- <navigation @handleTab="handleTab"></navigation> -->
  5. <div class="left yes-events">
  6. <component :is="components[currentComponent]" @backHome="backHome" />
  7. </div>
  8. <div class="right yes-events">
  9. <div class="list adopt-list-wrap">
  10. <chart-box name="果树管理" arrow="" color="yellow">
  11. <el-tabs v-model="activeName" class="demo-tabs">
  12. <el-tab-pane label="果树列表" name="果树列表">
  13. <adopt-list></adopt-list>
  14. </el-tab-pane>
  15. <el-tab-pane label="待分配" name="待分配">
  16. <client-list></client-list>
  17. </el-tab-pane>
  18. <el-tab-pane label="已分配" name="已分配">
  19. <apply-list></apply-list>
  20. </el-tab-pane>
  21. <!-- <el-tab-pane label="确认地址" name="确认地址">
  22. <address-list></address-list>
  23. </el-tab-pane> -->
  24. </el-tabs>
  25. </chart-box>
  26. </div>
  27. </div>
  28. <!-- 图例 -->
  29. <div v-if="legendArr && legendArr.length" class="map-bg map-legend yes-events">
  30. <div class="item" v-for="(legend, legendI) in legendArr" :key="legendI">
  31. <span class="legend-block" :style="{ background: legend.color }"></span>
  32. {{ legend.name }}
  33. </div>
  34. </div>
  35. <div v-else class="map-bg map-legend yes-events">
  36. <div class="item" v-if="ROLE == 1">
  37. <img src="@/assets/images/map/status/wry.png" alt="" />
  38. 未开放
  39. </div>
  40. <div class="item" v-if="ROLE == 2">
  41. <img src="@/assets/images/map/status/other.png" alt="" />
  42. 其他树
  43. </div>
  44. <div class="item" v-show="!checkShow">
  45. <img src="@/assets/images/map/status/dry.png" alt="" />
  46. 待守护
  47. </div>
  48. <div class="item" v-show="!checkShow">
  49. <img src="@/assets/images/map/status/yry.png" alt="" />
  50. 已守护
  51. </div>
  52. <div class="item selected-item" v-show="checkShow">
  53. <img src="@/assets/images/map/status/selected.png" alt="" />
  54. 已选择
  55. </div>
  56. </div>
  57. <div class="tips" v-show="checkShow">
  58. <div class="text">
  59. <span>提示:</span>请在底图上点选 <span>可守护的果树</span>,或按住 Ctrl 框选 <span>守护的区域</span>
  60. </div>
  61. </div>
  62. <div v-show="!checkShow && ROLE == 1" class="right-button yes-events" @click="hanldeCheck">
  63. 新增守护区域
  64. </div>
  65. <div v-show="checkShow" class="center-button">
  66. <div class="cancel yes-events" @click="handleCancel">取消</div>
  67. <div class="yes-events" @click="handleCancel">确认开放守护权限</div>
  68. </div>
  69. </div>
  70. </div>
  71. <custom-map class="bottom-map" ref="mapRef"></custom-map>
  72. <!-- 图片弹窗 -->
  73. <PicturePreview :imageUrl="urls" :curIndex="urlsIndex"></PicturePreview>
  74. <PdfDialog title="果园报告"></PdfDialog>
  75. </template>
  76. <script setup>
  77. import { nextTick, onMounted, onUnmounted, ref } from "vue";
  78. import config from "@/api/config.js";
  79. import timeLine from "@/components/timeLine.vue";
  80. import PicturePreview from "@/components/PicturePreview.vue";
  81. import navigation from "@/components/navigation.vue";
  82. import chartBox from "@/components/chartBox.vue";
  83. import leftTabs from "./components/leftTabs/index.vue";
  84. import treeDetail from "./components/treeDetail.vue";
  85. import adoptList from "./components/adoptList.vue";
  86. import clientList from "./components/clientList.vue";
  87. import customMap from "./homeMap.vue";
  88. import applyList from "./components/applyList.vue";
  89. import addressList from "./components/addressList.vue";
  90. import { convertPointToArray } from "@/utils/index";
  91. import { useRouter } from "vue-router";
  92. import { useStore } from "vuex";
  93. import eventBus from "@/api/eventBus";
  94. import PdfDialog from "../../components/PdfDialog";
  95. let store = useStore();
  96. const components = {
  97. leftTabs,
  98. treeDetail,
  99. };
  100. const router = useRouter();
  101. const mapRef = ref(null);
  102. const activeName = ref("果树列表");
  103. // 用户角色
  104. store.commit("home/SET_USER_ROLE", 1);
  105. let ROLE = ref(null);
  106. onMounted(() => {
  107. //区域切换监听事件
  108. eventBus.on("area:id", areaId);
  109. ROLE.value = store.state.home.userRole;
  110. // 柏桥村
  111. areaId({ areaId: 0, farmId: 80865 });
  112. });
  113. onUnmounted(() => {
  114. if (mapRef.value) {
  115. mapRef.value.destroy(); // 确保在自定义地图组件中实现了destroy方法
  116. }
  117. eventBus.off("area:id", areaId);
  118. eventBus.off("changePointLegend", toggleLegend);
  119. eventBus.off("clickMapPoint", toggleLeftComponet);
  120. });
  121. const getPointList = () => {
  122. let selectAll = undefined;
  123. if (regionId.value === 0) {
  124. selectAll = 1;
  125. }
  126. const areaId = selectAll ? undefined : regionId.value;
  127. VE_API.variety.pointList({ farmId: organId.value, regionId: areaId, selectAll }).then(({ data }) => {
  128. // const arr = data.map(item =>{
  129. // return{
  130. // ...item,
  131. // color: item.fosterStatus === 0 ? "transprent" : (item.fosterStatus === 1 ? "#EEEEEE" : (item.fosterStatus === 2 ? "#F0AC37" : "transprent")),
  132. // lnglat:convertPointToArray(item.point)
  133. // }
  134. // })
  135. if (mapRef.value) {
  136. nextTick(() => {
  137. data[0].icon = "1";
  138. data[1].icon = "1";
  139. data[10].icon = "2";
  140. data[20].icon = "2";
  141. data[30].icon = "2";
  142. data[35].icon = "1";
  143. data[40].icon = "1";
  144. data[50].icon = "2";
  145. // 设置前50个对象的fosterStatus为1
  146. for (let i = 0; i < 50 && i < data.length; i++) {
  147. data[i].fosterStatus = 1;
  148. }
  149. mapRef.value.addCluster(data);
  150. // mapRef.value.initData(arr)
  151. // mapRef.value.initMap(arr, () => mapRef.value.getRegionList(organId.value))
  152. });
  153. }
  154. });
  155. };
  156. const regionData = ref([]);
  157. function getBlueRegionList() {
  158. VE_API.region.list({ farmId: organId.value }).then(({ data }) => {
  159. regionData.value = data;
  160. mapRef.value.initAreaMap(data);
  161. });
  162. }
  163. const checkShow = ref(false);
  164. const hanldeCheck = () => {
  165. checkShow.value = true;
  166. mapRef.value.enableBoxSelect();
  167. };
  168. const handleCancel = () => {
  169. checkShow.value = false;
  170. // mapRef.value.clearSelection()
  171. mapRef.value.stopBoxSelect();
  172. };
  173. // 图例
  174. const legendArr = ref([]);
  175. const organId = ref("");
  176. const regionId = ref(null);
  177. const tabName = ref("");
  178. const tabId = ref(0);
  179. eventBus.off("changePointLegend", toggleLegend);
  180. eventBus.on("changePointLegend", toggleLegend);
  181. function toggleLegend({ colorObj }) {
  182. legendArr.value = colorObj?.list;
  183. }
  184. //选项卡事件监听
  185. const handleTab = async ({ name, id, isUpdate, params, legend, colorObj }) => {
  186. eventBus.emit("changePointType", { legend, colorObj });
  187. legendArr.value = colorObj?.list;
  188. tabName.value = name;
  189. tabId.value = id;
  190. // if (id === 0) {
  191. // }
  192. };
  193. //区域切换监听事件
  194. function areaId({ areaId, farmId }) {
  195. organId.value = farmId;
  196. regionId.value = areaId;
  197. // 树点位
  198. getPointList();
  199. // 分区
  200. if (!regionData.value.length) {
  201. // 全部区域
  202. getBlueRegionList();
  203. }
  204. }
  205. const urls = ref([]);
  206. const urlsIndex = ref(0);
  207. const currentComponent = ref("leftTabs");
  208. eventBus.on("clickMapPoint", toggleLeftComponet);
  209. function toggleLeftComponet() {
  210. currentComponent.value = "treeDetail";
  211. }
  212. function backHome() {
  213. currentComponent.value = "leftTabs";
  214. mapRef.value.resetCurrentTree();
  215. }
  216. </script>
  217. <style lang="scss" scoped>
  218. .base-container {
  219. width: 100%;
  220. height: 100%;
  221. position: absolute;
  222. box-sizing: border-box;
  223. z-index: 1;
  224. color: #FFFFFF;
  225. .content {
  226. width: 100%;
  227. height: calc(100% - 36px);
  228. display: flex;
  229. justify-content: space-between;
  230. box-sizing: border-box;
  231. .left,
  232. .right {
  233. width: 376px;
  234. height: calc(100% - 10px);
  235. margin-top: 10px;
  236. box-sizing: border-box;
  237. display: flex;
  238. position: relative;
  239. }
  240. .left {
  241. background: #fff;
  242. border-radius: 8px;
  243. margin-left: 25px;
  244. padding: 0 10px 10px;
  245. .arrow {
  246. position: absolute;
  247. right: -16px;
  248. top: calc(50% - 40px);
  249. background: #fff;
  250. width: 16px;
  251. height: 80px;
  252. line-height: 80px;
  253. border-radius: 0 5px 5px 0;
  254. text-align: center;
  255. cursor: pointer;
  256. }
  257. ::v-deep {
  258. .el-tabs__item {
  259. outline: none;
  260. }
  261. }
  262. }
  263. .right {
  264. width: 376px;
  265. margin-right: 25px;
  266. .adopt-list-wrap {
  267. ::v-deep {
  268. .el-tabs {
  269. height: 100%;
  270. }
  271. .el-tabs__content {
  272. height: calc(100% - 40px - 15px);
  273. position: static;
  274. }
  275. .el-tabs__item {
  276. color: #727272;
  277. width: 100px;
  278. }
  279. .el-tabs__active-bar {
  280. background-color: #2199f8;
  281. height: 1px;
  282. }
  283. .el-tabs__item.is-active {
  284. color: #2199f8;
  285. }
  286. .el-tabs__nav-wrap:after {
  287. height: 1px;
  288. background-color: rgba(127, 127, 127, 0.1);
  289. }
  290. .el-tabs__nav {
  291. left: 50%;
  292. transform: translateX(-50%) !important;
  293. }
  294. .el-tab-pane {
  295. height: 100%;
  296. }
  297. }
  298. }
  299. .list {
  300. width: 100%;
  301. height: 100%;
  302. overflow: auto;
  303. .btn-wrap {
  304. width: 100%;
  305. height: 25px;
  306. line-height: 25px;
  307. margin: 10px 0;
  308. display: flex;
  309. align-items: center;
  310. justify-content: space-between;
  311. div {
  312. width: 48%;
  313. height: 100%;
  314. color: #ffd489;
  315. border: 1px solid rgba(255, 213, 137, 0.6);
  316. border-radius: 2px;
  317. text-align: center;
  318. font-size: 12px;
  319. cursor: pointer;
  320. &.active {
  321. background: #ffd489;
  322. color: #000;
  323. }
  324. }
  325. }
  326. .img-box {
  327. width: 100%;
  328. height: calc(100% - 35px);
  329. overflow: auto;
  330. }
  331. .img-box1 {
  332. width: 100%;
  333. height: calc(100% - 10px);
  334. overflow: auto;
  335. margin-top: 10px;
  336. }
  337. .img-box2 {
  338. width: 100%;
  339. height: calc(100% - 45px);
  340. overflow: auto;
  341. margin-top: 10px;
  342. }
  343. img {
  344. width: 100%;
  345. height: auto;
  346. object-fit: cover;
  347. margin-bottom: 12px;
  348. cursor: pointer;
  349. }
  350. .mt {
  351. margin-top: -12px;
  352. }
  353. }
  354. }
  355. .overflow {
  356. overflow: auto;
  357. }
  358. .legend {
  359. position: fixed;
  360. bottom: 8px;
  361. right: 64px;
  362. height: 20px;
  363. }
  364. .map-bg {
  365. position: fixed;
  366. z-index: 2;
  367. background: rgba(35, 35, 35, 0.8);
  368. border-radius: 18px;
  369. padding: 7px 16px;
  370. left: 460px;
  371. }
  372. .tips {
  373. position: fixed;
  374. z-index: 2;
  375. top: 105px;
  376. width: 100%;
  377. display: flex;
  378. justify-content: center;
  379. .text {
  380. font-size: 20px;
  381. padding: 6px 16px;
  382. font-family: "PangMenZhengDao";
  383. background: rgba(4, 3, 0, 0.6);
  384. border-radius: 20px;
  385. span {
  386. color: #ffd489;
  387. }
  388. }
  389. }
  390. .right-button {
  391. position: fixed;
  392. z-index: 2;
  393. right: 460px;
  394. bottom: 36px;
  395. font-size: 24px;
  396. font-family: "PangMenZhengDao";
  397. padding: 16px 32px 20px 32px;
  398. cursor: pointer;
  399. background: url("@/assets/images/foster-home/btn-bg.png") no-repeat center center / 100% 100%;
  400. }
  401. .center-button {
  402. position: fixed;
  403. z-index: 2;
  404. width: 100%;
  405. display: flex;
  406. align-items: center;
  407. justify-content: center;
  408. bottom: 116px;
  409. div {
  410. cursor: pointer;
  411. width: 248px;
  412. text-align: center;
  413. padding: 15px;
  414. font-family: "PangMenZhengDao";
  415. color: #000;
  416. font-size: 20px;
  417. background: linear-gradient(0deg, #ffd887, #ed9e1e);
  418. border: 2px solid rgba(255, 255, 255, 0.61);
  419. border-radius: 12px;
  420. }
  421. .cancel {
  422. margin-right: 20px;
  423. background: #eeeeee;
  424. }
  425. }
  426. .map-btn {
  427. top: 19px;
  428. cursor: pointer;
  429. }
  430. .map-legend {
  431. bottom: 36px;
  432. display: flex;
  433. align-items: center;
  434. .item {
  435. display: flex;
  436. align-items: center;
  437. font-size: 14px;
  438. img {
  439. width: 16px;
  440. margin-right: 6px;
  441. }
  442. .legend-block {
  443. width: 16px;
  444. height: 16px;
  445. box-sizing: border-box;
  446. border-radius: 50%;
  447. border: 2px solid #fff;
  448. margin-right: 6px;
  449. }
  450. }
  451. .selected-item {
  452. img {
  453. width: 24px;
  454. }
  455. }
  456. .legend-title {
  457. border-bottom: 1px solid rgba(102, 102, 102, 0.35);
  458. }
  459. .item + .item {
  460. padding-left: 12px;
  461. }
  462. }
  463. }
  464. }
  465. .bottom-map {
  466. width: 100%;
  467. height: 100%;
  468. position: absolute;
  469. z-index: 0;
  470. }
  471. .compare-start-btn {
  472. position: absolute;
  473. z-index: 2;
  474. left: 50%;
  475. transform: translateX(-50%);
  476. cursor: pointer;
  477. bottom: 106px;
  478. // right: 445px;
  479. img {
  480. height: 55px;
  481. }
  482. }
  483. </style>
  484. <style lang="less">
  485. .file-wrap {
  486. &.map-file {
  487. width: 367px;
  488. position: relative;
  489. background: url("@/assets/images/home/file-bg.png") no-repeat top center / 100% 100%;
  490. margin-left: 12px;
  491. padding: 12px;
  492. .file-title {
  493. font-size: 20px;
  494. color: #ffd489;
  495. .tag {
  496. border: 1px solid #ffd489;
  497. border-radius: 4px;
  498. font-size: 12px;
  499. display: inline-block;
  500. width: 44px;
  501. height: 20px;
  502. text-align: center;
  503. line-height: 18px;
  504. margin-left: 8px;
  505. padding: 1px 4px;
  506. }
  507. }
  508. .overview-file {
  509. padding-top: 20px;
  510. .box-title {
  511. font-size: 16px;
  512. padding-left: 13px;
  513. margin-bottom: 16px;
  514. position: relative;
  515. display: flex;
  516. justify-content: space-between;
  517. color: #fff;
  518. &::before {
  519. content: "";
  520. position: absolute;
  521. left: 0;
  522. top: 3px;
  523. width: 3px;
  524. height: 16px;
  525. background: #fff;
  526. border-radius: 11px;
  527. }
  528. }
  529. .title {
  530. color: #f3c11d;
  531. font-size: 16px;
  532. font-family: "PangMenZhengDao";
  533. margin-bottom: 20px;
  534. .big {
  535. width: 13px;
  536. height: 13px;
  537. margin: -10px 0 0 4px;
  538. }
  539. .small {
  540. width: 7px;
  541. height: 7px;
  542. margin-left: -3px;
  543. }
  544. }
  545. .base-data {
  546. background: rgba(207, 207, 207, 0.1);
  547. border-radius: 4px;
  548. padding: 6px 0;
  549. display: flex;
  550. .base-item {
  551. flex: 1;
  552. text-align: center;
  553. .label {
  554. font-size: 12px;
  555. color: #666666;
  556. }
  557. .value {
  558. padding-top: 2px;
  559. font-size: 16px;
  560. color: #ffffff;
  561. }
  562. }
  563. .base-item + .base-item {
  564. border-left: 1px solid rgba(102, 102, 102, 0.42);
  565. }
  566. }
  567. .list {
  568. margin-top: 15px;
  569. width: max-content;
  570. font-size: 14px;
  571. .list-item {
  572. color: #bbbbbb;
  573. display: flex;
  574. margin-bottom: 8px;
  575. .list-name {
  576. color: #f3c11d;
  577. margin-right: 6px;
  578. img {
  579. width: 17px;
  580. height: 13px;
  581. }
  582. }
  583. }
  584. }
  585. }
  586. .overview-file + .overview-file {
  587. margin-top: 8px;
  588. }
  589. .box-wrap {
  590. display: flex;
  591. .box-item {
  592. // flex: 1;
  593. min-width: 109px;
  594. display: flex;
  595. flex-direction: column;
  596. justify-content: center;
  597. align-items: center;
  598. padding: 6px;
  599. box-sizing: border-box;
  600. background: rgba(207, 207, 207, 0.1);
  601. border-radius: 4px;
  602. border: 1px solid rgba(207, 207, 207, 0.1);
  603. cursor: pointer;
  604. .item-name {
  605. font-size: 12px;
  606. color: #666666;
  607. width: max-content;
  608. }
  609. .item-val {
  610. font-size: 18px;
  611. color: #fff;
  612. width: max-content;
  613. padding-top: 3px;
  614. }
  615. &.active {
  616. background: rgba(255, 212, 137, 0.16);
  617. border: 1px solid #ffd489;
  618. .item-name {
  619. color: #bbbbbb;
  620. }
  621. }
  622. }
  623. .box-item + .box-item {
  624. margin-left: 8px;
  625. }
  626. }
  627. }
  628. }
  629. </style>