home.vue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634
  1. <template>
  2. <!-- 开启顶部安全区适配 -->
  3. <van-nav-bar
  4. :border="false"
  5. safe-area-inset-top
  6. style="background-color: #5c8fff"
  7. />
  8. <div class="page_info">
  9. <div
  10. class="info_title"
  11. :style="{
  12. 'margin-bottom': role != 'Maintenance' ? '54px' : '12px',
  13. 'padding-bottom': role != 'Maintenance' ? '58px' : '',
  14. }"
  15. >
  16. <van-row align="center" class="position_pannel">
  17. <template v-if="role == 'Tenant'">
  18. <van-row justify="center" style="flex: 1">
  19. <van-col>首页</van-col>
  20. </van-row>
  21. </template>
  22. <template v-else>
  23. <van-col>
  24. <van-image
  25. :src="require('@/assets/position.svg')"
  26. width="16"
  27. height="16"
  28. fit="contain"
  29. />
  30. <van-col>{{ name }}</van-col>
  31. <van-image
  32. :src="require('@/assets/arrow-right.svg')"
  33. width="24"
  34. height="24"
  35. fit="contain"
  36. />
  37. </van-col>
  38. </template>
  39. <van-col
  40. @click="
  41. () => {
  42. $router.push({ path: '/userInfo', query: { type: 'password' } });
  43. }
  44. "
  45. >
  46. <van-image
  47. :src="require('@/assets/user.svg')"
  48. width="16"
  49. height="16"
  50. fit="contain"
  51. />
  52. </van-col>
  53. </van-row>
  54. </div>
  55. <!-- 维修工没有此块功能 -->
  56. <template v-if="role && role != 'Maintenance'">
  57. <div class="info_function">
  58. <div
  59. class="function_item"
  60. v-for="(item, index) in functionList"
  61. :key="index"
  62. :style="{ display: !item.role.includes(role) ? 'none' : '' }"
  63. @click="toPath(item.path, item.activeTab)"
  64. >
  65. <template v-if="item.role.includes(role)">
  66. <van-image :src="item.src" width="36" height="36" fit="contain" />
  67. <van-col>{{ item.label }}</van-col>
  68. </template>
  69. </div>
  70. </div>
  71. </template>
  72. <div class="info_list">
  73. <!-- 实时巡检begin -->
  74. <template v-if="role == 'Inspection'">
  75. <van-row align="center" justify="space-between" class="sub_title">
  76. <van-col class="title">实时巡检</van-col>
  77. <van-col
  78. class="function_btn"
  79. @click="
  80. () => {
  81. $router.push({ path: '/review/clock' });
  82. }
  83. "
  84. >
  85. <van-col>立即巡检</van-col>
  86. <van-image
  87. :src="require('@/assets/btn-arrow-right.svg')"
  88. width="24"
  89. height="24"
  90. fit="contain"
  91. />
  92. </van-col>
  93. </van-row>
  94. <van-row align="center" justify="space-around" class="list_item">
  95. <van-row
  96. align="center"
  97. justify="center"
  98. style="flex-direction: column"
  99. v-for="(item, index) in reviewList"
  100. :key="item + '_' + index"
  101. >
  102. <van-col>{{ item.dictLabel }}</van-col>
  103. <v-count-up
  104. :end-val="Number(item['count'])"
  105. class="count_up"
  106. :options="item['options']"
  107. />
  108. </van-row>
  109. </van-row>
  110. </template>
  111. <!-- 实时巡检end -->
  112. <!-- 工单待办begin -->
  113. <template v-if="role && role != 'Inspection'">
  114. <van-row align="center" justify="space-between" class="sub_title">
  115. <van-col class="title">{{
  116. role == "admin" ? "工单待办" : "实时报修"
  117. }}</van-col>
  118. <van-col
  119. class="function_btn"
  120. @click="
  121. () => {
  122. $router.push({ path: '/repair/list' });
  123. }
  124. "
  125. >
  126. <van-col>{{ role == "admin" ? "立即处理" : "立即查看" }}</van-col>
  127. <van-image
  128. :src="require('@/assets/btn-arrow-right.svg')"
  129. width="24"
  130. height="24"
  131. fit="contain"
  132. />
  133. </van-col>
  134. </van-row>
  135. <van-row align="center" justify="space-around" class="list_item">
  136. <van-row
  137. align="center"
  138. justify="center"
  139. style="flex-direction: column"
  140. v-for="(item, index) in workList"
  141. :key="item + '_' + index"
  142. :style="{ display: !item.role.includes(role) ? 'none' : '' }"
  143. >
  144. <van-col>{{ item.label }}</van-col>
  145. <v-count-up
  146. :end-val="Number(item['count'])"
  147. class="count_up"
  148. :options="item['options']"
  149. />
  150. </van-row>
  151. </van-row>
  152. </template>
  153. <!-- 工单待办end -->
  154. <!-- 设备异常begin -->
  155. <template v-if="role && role != 'Tenant'">
  156. <van-row align="center" justify="space-between" class="sub_title">
  157. <van-col class="title">设备异常</van-col>
  158. <van-col
  159. class="function_btn"
  160. @click="
  161. () => {
  162. $router.push({ path: '/device/list' });
  163. }
  164. "
  165. >
  166. <van-col>立即查看</van-col>
  167. <van-image
  168. :src="require('@/assets/btn-arrow-right.svg')"
  169. width="24"
  170. height="24"
  171. fit="contain"
  172. />
  173. </van-col>
  174. </van-row>
  175. <van-row align="center" justify="space-around" class="list_item">
  176. <van-row
  177. align="center"
  178. justify="space-between"
  179. style="flex-direction: column"
  180. v-for="(item, index) in deviceAlarmList"
  181. :key="item + '_' + index"
  182. >
  183. <van-col>{{ item.dictLabel }}</van-col>
  184. <v-count-up :end-val="Number(item['count'])" class="count_up" />
  185. </van-row>
  186. </van-row>
  187. </template>
  188. <!-- 设备异常end -->
  189. <!-- 欠费待收begin -->
  190. <template v-if="role == 'admin'">
  191. <van-row align="center" justify="space-between" class="sub_title">
  192. <van-col class="title">欠费待收</van-col>
  193. <van-col
  194. class="function_btn"
  195. @click="
  196. () => {
  197. $router.push({ path: '/pay/fee' });
  198. }
  199. "
  200. >
  201. <van-col>立即催收</van-col>
  202. <van-image
  203. :src="require('@/assets/btn-arrow-right.svg')"
  204. width="24"
  205. height="24"
  206. fit="contain"
  207. />
  208. </van-col>
  209. </van-row>
  210. <div class="list_item list_table">
  211. <van-row class="table_header">
  212. <van-col span="8">欠费类型</van-col>
  213. <van-col span="8">欠费租户数</van-col>
  214. <van-col span="8">累计欠费(元)</van-col>
  215. </van-row>
  216. <div class="table_body" :class="{ loading_info: loading }">
  217. <template v-if="!loading">
  218. <template v-if="billPaymentList.length > 0">
  219. <van-row v-for="(item, index) in billPaymentList" :key="index">
  220. <van-col span="8" style="color: #999999; font-size: 12px">{{
  221. `${dict_filter(item.payType, "payTypeList")["dictLabel"]}`
  222. }}</van-col>
  223. <van-col span="8">{{
  224. (parseInt(item.arrearageNum * 100) / 100).toFixed(2)
  225. }}</van-col>
  226. <van-col span="8">{{
  227. (parseInt(item.arrearageAmount * 100) / 100).toFixed(2)
  228. }}</van-col>
  229. </van-row>
  230. </template>
  231. <template v-else>
  232. <van-empty image-size="60" description="暂无数据" />
  233. </template>
  234. </template>
  235. <template v-if="loading">
  236. <van-loading size="24px">加载中...</van-loading>
  237. </template>
  238. </div>
  239. </div>
  240. </template>
  241. <!-- 欠费待收end -->
  242. <!-- 账单待缴begin -->
  243. <template v-if="role == 'Tenant'">
  244. <van-row align="center" justify="space-between" class="sub_title">
  245. <van-col class="title">账单待缴</van-col>
  246. <van-col
  247. class="function_btn"
  248. @click="
  249. () => {
  250. $router.push({
  251. path: '/bill/detail',
  252. query: {
  253. activeTab: 'bill',
  254. },
  255. });
  256. }
  257. "
  258. >
  259. <van-col>立即缴费</van-col>
  260. <van-image
  261. :src="require('@/assets/btn-arrow-right.svg')"
  262. width="24"
  263. height="24"
  264. fit="contain"
  265. />
  266. </van-col>
  267. </van-row>
  268. <div class="list_item list_table">
  269. <van-row class="table_header">
  270. <van-col span="8">缴费类型</van-col>
  271. <van-col span="8">本期待缴金额(元)</van-col>
  272. <van-col span="8">累计待缴金额(元)</van-col>
  273. </van-row>
  274. <div class="table_body" :class="{ loading_info: loading }">
  275. <template v-if="!loading">
  276. <template v-if="billPaymentList.length > 0">
  277. <van-row v-for="(item, index) in billPaymentList" :key="index">
  278. <van-col span="8" style="color: #999999; font-size: 12px">{{
  279. `${dict_filter(item.payType, "payTypeList")["dictLabel"]}`
  280. }}</van-col>
  281. <van-col span="8">{{
  282. (parseInt(item.currentAmount * 100) / 100).toFixed(2)
  283. }}</van-col>
  284. <van-col span="8">{{
  285. (parseInt(item.cumulativeAmount * 100) / 100).toFixed(2)
  286. }}</van-col>
  287. </van-row>
  288. </template>
  289. <template v-else>
  290. <van-empty image-size="60" description="暂无数据" />
  291. </template>
  292. </template>
  293. <template v-if="loading">
  294. <van-loading size="24px">加载中...</van-loading>
  295. </template>
  296. </div>
  297. </div>
  298. </template>
  299. <!-- 账单待缴end -->
  300. </div>
  301. </div>
  302. <!-- 底部tabbar -->
  303. <template v-if="role == 'admin'">
  304. <van-tabbar
  305. v-model="activeTabBar"
  306. active-color="#2E69EB"
  307. inactive-color="#0c1935"
  308. >
  309. <van-tabbar-item
  310. name="home"
  311. :icon="
  312. activeTabBar == 'home'
  313. ? require('@/assets/home-active.svg')
  314. : require('@/assets/home.svg')
  315. "
  316. to="/home"
  317. >首页</van-tabbar-item
  318. >
  319. <van-tabbar-item
  320. name="rentBill"
  321. :icon="
  322. activeTabBar == 'bill'
  323. ? require('@/assets/rent-bill-active.svg')
  324. : require('@/assets/rent-bill.svg')
  325. "
  326. to="/bill/list"
  327. >租户账单</van-tabbar-item
  328. >
  329. <van-tabbar-item
  330. name="remoteControl"
  331. :icon="
  332. activeTabBar == 'remoteControl'
  333. ? require('@/assets/remote-control-active.svg')
  334. : require('@/assets/remote-control.svg')
  335. "
  336. to="/remoteControl"
  337. >远程管控</van-tabbar-item
  338. >
  339. </van-tabbar>
  340. </template>
  341. </template>
  342. <script>
  343. import { isEmpty, getDictDataList } from "@/utils/index.js";
  344. import api from "../utils/api";
  345. import VCountUp from "./CountUp";
  346. export default {
  347. components: {
  348. "v-count-up": VCountUp,
  349. },
  350. data() {
  351. return {
  352. role: "",
  353. tenantInfo: {}, //角色为Tenant时有值
  354. name: "电商园四期-B座",
  355. activeTabBar: "home",
  356. functionList: [
  357. {
  358. path: "/repair/create",
  359. src: require("@/assets/repair-online.svg"),
  360. label: "线上报修",
  361. role: ["admin", "Inspection", "Tenant"],
  362. },
  363. {
  364. path: "/review/list",
  365. src: require("@/assets/check-review.svg"),
  366. label: "巡检记录",
  367. role: ["admin", "Inspection"],
  368. },
  369. {
  370. path: "/pay/record",
  371. src: require("@/assets/reduce-record.svg"),
  372. label: "扣缴记录",
  373. role: ["admin", "Tenant"],
  374. activeTab: "record",
  375. },
  376. ],
  377. workList: [
  378. {
  379. label: "待指派",
  380. count: 0,
  381. role: ["admin"],
  382. },
  383. {
  384. label: "待维修",
  385. count: 0,
  386. role: ["admin", "Maintenance", "Tenant"],
  387. },
  388. {
  389. label: "已维修",
  390. count: 0,
  391. role: ["admin", "Maintenance", "Tenant"],
  392. },
  393. ],
  394. reviewList: [],
  395. deviceAlarmList: [],
  396. payTypeList: [],
  397. billPaymentList: [],
  398. loading: true,
  399. };
  400. },
  401. async mounted() {
  402. this.role = localStorage.getItem("role");
  403. await this.getPayTypeList();
  404. await this.getDeviceAlarmList();
  405. await this.getReviewList();
  406. this.getHomeData();
  407. if (this.role == "Tenant") {
  408. this.tenantInfo = JSON.parse(localStorage.getItem("tenantInfo"));
  409. } else {
  410. this.tenantInfo = {};
  411. }
  412. },
  413. methods: {
  414. getPayTypeList() {
  415. this.payTypeList = getDictDataList("PayType");
  416. },
  417. getDeviceAlarmList() {
  418. this.deviceAlarmList = getDictDataList("DeviceAlarm");
  419. },
  420. getReviewList() {
  421. this.reviewList = getDictDataList("Review");
  422. },
  423. dict_filter(val, list) {
  424. if (isEmpty(val)) {
  425. return {};
  426. }
  427. return this[list].find((item) => item.dictValue == val);
  428. },
  429. getHomeData() {
  430. api.homedata().then((res) => {
  431. if (res.code == 0) {
  432. //工单代办数据
  433. for (let k in res.data.workOrder) {
  434. this.workList[k - 1].count = res.data.workOrder[k];
  435. }
  436. //设备异常数据
  437. let deviceArr = [];
  438. for (let key in res.data.equip.maps) {
  439. if (key != "Relay") {
  440. deviceArr.push({
  441. dictValue: key,
  442. count: res.data.equip.maps[key],
  443. });
  444. }
  445. }
  446. //赋值异常总数
  447. deviceArr.unshift({
  448. dictValue: "abnormalNum",
  449. count: res.data.equip.abnormalNum,
  450. });
  451. this.deviceAlarmList.forEach((item) => {
  452. item.count = deviceArr.find(
  453. (ele) => ele.dictValue == item.dictValue
  454. ).count;
  455. });
  456. //实时巡检数据
  457. let reviewArr = [];
  458. for (let key in res.data.inspectionInfo) {
  459. reviewArr.push({
  460. dictValue: key,
  461. count: res.data.inspectionInfo[key],
  462. });
  463. }
  464. this.reviewList.forEach((item) => {
  465. item.count = reviewArr.find(
  466. (ele) => ele.dictValue == item.dictValue
  467. ).count;
  468. });
  469. //欠费待收数据
  470. this.billPaymentList = res.data.billPaymentList;
  471. }
  472. this.loading = false;
  473. });
  474. },
  475. toPath(path, val) {
  476. let params = {};
  477. if (this.role == "Tenant") {
  478. params = {
  479. tenantId: this.tenantInfo.tenantId,
  480. tenantName: this.tenantInfo.tenantName,
  481. activeTab: val,
  482. };
  483. path = "/bill/detail";
  484. }
  485. this.$router.push({
  486. path: path,
  487. query: params,
  488. });
  489. },
  490. },
  491. };
  492. </script>
  493. <style lang="scss" scoped>
  494. .page_info {
  495. position: relative;
  496. .info_title {
  497. width: 100%;
  498. background: #5c8fff;
  499. border-radius: 0px 0px 16px 16px;
  500. box-sizing: border-box;
  501. .position_pannel {
  502. display: flex;
  503. align-items: center;
  504. justify-content: space-between;
  505. padding: 0 16px;
  506. .van-col {
  507. height: 44px;
  508. font-weight: 600;
  509. font-size: 16px;
  510. color: #ffffff;
  511. line-height: 24px;
  512. text-indent: 4px;
  513. text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.04);
  514. display: flex;
  515. align-items: center;
  516. letter-spacing: 2px;
  517. }
  518. }
  519. }
  520. .info_function {
  521. position: absolute;
  522. top: 52px;
  523. width: calc(100% - 32px);
  524. margin: 0 16px;
  525. background: #ffffff;
  526. box-shadow: 0px 0px 8px 0px rgba(51, 51, 51, 0.08);
  527. border-radius: 4px;
  528. display: flex;
  529. align-items: center;
  530. justify-content: space-around;
  531. padding: 16px 0;
  532. box-sizing: border-box;
  533. .function_item {
  534. display: flex;
  535. flex-direction: column;
  536. align-items: center;
  537. justify-content: center;
  538. .van-col {
  539. height: 20px;
  540. font-size: 14px;
  541. font-weight: 400;
  542. color: #666666;
  543. line-height: 20px;
  544. margin-top: 4px;
  545. }
  546. }
  547. }
  548. .info_list {
  549. padding: 0 16px;
  550. .sub_title {
  551. margin: 12px 0 6px 0;
  552. .title {
  553. height: 20px;
  554. font-size: 14px;
  555. font-weight: 500;
  556. color: #0c1935;
  557. line-height: 20px;
  558. }
  559. .function_btn {
  560. display: flex;
  561. align-items: center;
  562. .van-col {
  563. height: 16px;
  564. font-size: 12px;
  565. font-weight: 400;
  566. color: #2e69eb;
  567. line-height: 16px;
  568. }
  569. }
  570. }
  571. .list_item {
  572. background: #ffffff;
  573. box-shadow: 0px 0px 4px 0px rgba(51, 51, 51, 0.08);
  574. border-radius: 4px;
  575. padding: 16px 0;
  576. height: 32px;
  577. .van-col {
  578. height: 16px;
  579. font-size: 12px;
  580. font-weight: 400;
  581. color: #666666;
  582. line-height: 16px;
  583. }
  584. .count_up {
  585. margin-top: 4px;
  586. height: 22px;
  587. font-size: 16px;
  588. color: #0c1935;
  589. line-height: 22px;
  590. }
  591. }
  592. .list_table {
  593. padding: 8px 16px 4px 16px;
  594. min-height: 156px;
  595. .table_header {
  596. padding: 8px 0;
  597. border-bottom: 1px solid #eeeeee;
  598. .van-col {
  599. height: 16px;
  600. font-size: 12px;
  601. font-weight: 600;
  602. color: #999999;
  603. line-height: 16px;
  604. }
  605. }
  606. .table_body {
  607. height: calc(100% - 33px);
  608. .van-row {
  609. padding: 12px 0;
  610. border-bottom: 1px solid #eeeeee;
  611. }
  612. .van-col {
  613. height: 16px;
  614. font-size: 16px;
  615. color: #0c1935;
  616. line-height: 16px;
  617. }
  618. }
  619. .loading_info {
  620. display: flex;
  621. align-items: center;
  622. justify-content: center;
  623. }
  624. }
  625. }
  626. }
  627. </style>