detail.vue 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. <template>
  2. <van-nav-bar :title="title" safe-area-inset-top>
  3. <template #left>
  4. <van-icon
  5. :name="require('@/assets/arrow-left.svg')"
  6. size="24"
  7. @click="backPath"
  8. />
  9. </template>
  10. </van-nav-bar>
  11. <van-pull-refresh v-model="refreshing" @refresh="onRefresh">
  12. <div class="page_info">
  13. <div class="search_pannel">
  14. <van-tabs
  15. v-model:active="activeTab"
  16. title-active-color="#2E69EB"
  17. title-inactive-color="#0C1935"
  18. @change="handleChangeTab"
  19. >
  20. <van-tab name="bill" title="账单明细">
  21. <van-dropdown-menu active-color="#2E69EB">
  22. <van-dropdown-item
  23. v-model="dataForm.costCycle"
  24. @change="handelChange('costCycle', costCycle)"
  25. :title="costCycleTitle"
  26. :options="costCycleList"
  27. />
  28. <van-dropdown-item
  29. v-model="dataForm.costType"
  30. @change="handelChange('costType', dataForm.costType)"
  31. :title="costTypeTitle"
  32. :options="payTypeList"
  33. />
  34. <van-dropdown-item
  35. v-model="dataForm.status"
  36. @change="handelChange('status', dataForm.status)"
  37. :title="statusTitle"
  38. :options="payStatusList"
  39. />
  40. </van-dropdown-menu>
  41. </van-tab>
  42. <van-tab name="record" title="扣缴记录">
  43. <van-dropdown-menu active-color="#2E69EB">
  44. <van-dropdown-item
  45. v-model="dataForm.reduceDate"
  46. @change="handelChange('reduceDate', dataForm.reduceDate)"
  47. :title="reduceDateTitle"
  48. :options="reduceDateList"
  49. />
  50. <van-dropdown-item
  51. v-model="dataForm.type"
  52. @change="handelChange('type', dataForm.type)"
  53. :title="typeTitle"
  54. :options="payTypeList"
  55. />
  56. <van-dropdown-item
  57. v-model="dataForm.operator"
  58. @change="handelChange('operator', dataForm.operator)"
  59. :title="operatorTitle"
  60. :options="operatorList"
  61. />
  62. </van-dropdown-menu>
  63. </van-tab>
  64. </van-tabs>
  65. </div>
  66. <van-row align="center" class="list_total">
  67. <van-col>共有</van-col>
  68. <v-count-up
  69. :end-val="dataList.length"
  70. class="count_up"
  71. :options="{ separator: ',' }"
  72. />
  73. <van-col>条记录</van-col>
  74. </van-row>
  75. <template v-if="activeTab == 'bill'">
  76. <div class="info_list" key="bill">
  77. <van-list
  78. v-model:loading="loading"
  79. :finished="finished"
  80. :error="error"
  81. error-text="请求失败,点击重新加载"
  82. finished-text="没有更多了"
  83. @load="onLoad"
  84. >
  85. <van-checkbox-group
  86. ref="checkboxGroup"
  87. v-model="checkedCollapse"
  88. style="width: 100%"
  89. >
  90. <div
  91. v-for="item in dataList"
  92. :key="item.id"
  93. class="list_item"
  94. style="flex-direction: row; align-items: baseline"
  95. >
  96. <van-checkbox
  97. :name="item.id"
  98. :disabled="item.status == 1"
  99. style="margin-left: 16px"
  100. ></van-checkbox>
  101. <van-collapse
  102. v-model="activeCollapse"
  103. :border="false"
  104. style="flex: 1"
  105. accordion
  106. >
  107. <van-collapse-item :name="item.id">
  108. <template #title>
  109. <van-row class="collapse_title">
  110. <van-col class="label"
  111. >{{
  112. `${
  113. dict_filter(item.costType, "payTypeList")[
  114. "dictLabel"
  115. ]
  116. }`
  117. }}:</van-col
  118. >
  119. <van-col style="font-weight: 600; color: #fa5555"
  120. >¥{{
  121. (parseInt(item.amount * 100) / 100).toFixed(2)
  122. }}</van-col
  123. >
  124. </van-row>
  125. </template>
  126. <div class="collapse_info">
  127. <van-row
  128. class="info_item"
  129. v-for="ele in item.billLists"
  130. :key="ele.id"
  131. >
  132. <template
  133. v-if="
  134. item.costType == 'Water' || item.costType == 'Elec'
  135. "
  136. >
  137. <van-col
  138. >{{ ele.equipName }}费用:¥{{
  139. (parseInt(ele.amount * 100) / 100).toFixed(2)
  140. }}</van-col
  141. >
  142. </template>
  143. <template v-if="item.costType == 'PropertyFee'">
  144. <van-col
  145. >{{
  146. `${
  147. dict_filter(ele.costType, "propertyTypeList")[
  148. "dictLabel"
  149. ]
  150. }`
  151. }}:¥{{
  152. (parseInt(ele.amount * 100) / 100).toFixed(2)
  153. }}</van-col
  154. >
  155. </template>
  156. </van-row>
  157. </div>
  158. </van-collapse-item>
  159. </van-collapse>
  160. </div>
  161. </van-checkbox-group>
  162. </van-list>
  163. </div>
  164. </template>
  165. <template v-if="activeTab == 'record'">
  166. <div class="info_list" key="record">
  167. <van-list
  168. v-model:loading="loading"
  169. :finished="finished"
  170. :error="error"
  171. error-text="请求失败,点击重新加载"
  172. finished-text="没有更多了"
  173. @load="onLoad"
  174. >
  175. <div
  176. v-for="item in dataList"
  177. :key="item.id"
  178. class="list_item reduce_record"
  179. style="padding: 12px 16px"
  180. >
  181. <van-row
  182. align="center"
  183. class="reduce_type"
  184. :style="{
  185. 'background-color': `${
  186. dict_filter(item.type, 'payTypeList')['color']
  187. }`,
  188. }"
  189. >
  190. <van-col>{{
  191. `${dict_filter(item.type, "payTypeList")["dictLabel"]}`
  192. }}</van-col>
  193. </van-row>
  194. <van-row class="header">
  195. <van-col>{{ item.tenantInfo && item.tenantInfo.name }}</van-col>
  196. </van-row>
  197. <van-row>
  198. <van-col>扣缴金额:¥</van-col>
  199. <van-col style="color: #fa5555">{{
  200. (parseInt(item.amount * 100) / 100).toFixed(2)
  201. }}</van-col>
  202. </van-row>
  203. <van-row>
  204. <van-col>账户余额:¥</van-col>
  205. <van-col>{{
  206. (parseInt(item.surplus * 100) / 100).toFixed(2)
  207. }}</van-col>
  208. </van-row>
  209. <van-row>
  210. <van-col>租户电话:</van-col>
  211. <van-col>{{ item.tenantInfo && item.tenantInfo.tel }}</van-col>
  212. </van-row>
  213. <van-row>
  214. <van-col>操作人:</van-col>
  215. <van-col>{{ item.createName }}</van-col>
  216. </van-row>
  217. <van-row>
  218. <van-col>扣缴时间:</van-col>
  219. <van-col>{{ item.createDate }}</van-col>
  220. </van-row>
  221. </div>
  222. </van-list>
  223. </div>
  224. </template>
  225. </div>
  226. </van-pull-refresh>
  227. <template v-if="role == 'admin'">
  228. <van-tabbar v-model="activeTabBar" class="tab_bar">
  229. <van-tabbar-item @click="handleChangeTabBar(1)">预存</van-tabbar-item>
  230. <van-tabbar-item @click="handleChangeTabBar(2)">补助</van-tabbar-item>
  231. <van-tabbar-item @click="handleChangeTabBar(3)">退费</van-tabbar-item>
  232. </van-tabbar>
  233. </template>
  234. <template v-if="role == 'Tenant' && activeTab == 'record'">
  235. <van-submit-bar class="save_btn">
  236. <template #button>
  237. <van-button block type="primary" @click="handleClick('fee')">
  238. 预存充值
  239. </van-button>
  240. </template>
  241. </van-submit-bar>
  242. </template>
  243. <template
  244. v-if="role == 'Tenant' && activeTab == 'bill' && checkedCollapse.length"
  245. >
  246. <van-submit-bar
  247. :price="parseInt(amount * 100)"
  248. button-text="立即支付"
  249. button-color="#2E69EB"
  250. @submit="handleClick('bill')"
  251. >
  252. <van-checkbox v-model="checkedAll" :disabled="disabledAll"
  253. >全选</van-checkbox
  254. >
  255. </van-submit-bar>
  256. </template>
  257. <van-popup
  258. v-model:show="showPayPopup"
  259. position="bottom"
  260. :safe-area-inset-bottom="true"
  261. :overlay-style="{ background: 'unset' }"
  262. class="popup_info"
  263. >
  264. <component
  265. :is="currComponent"
  266. :pay-info="payInfo"
  267. @close="close"
  268. v-if="showPayPopup"
  269. ></component>
  270. </van-popup>
  271. </template>
  272. <script>
  273. import Api from "@/utils/api";
  274. import { isEmpty, getDictDataList } from "@/utils/index";
  275. import VCountUp from "../CountUp";
  276. import payFee from "./fee.vue";
  277. import payBill from "./pay.vue";
  278. export default {
  279. components: {
  280. "v-count-up": VCountUp,
  281. "pay-fee": payFee,
  282. "pay-bill": payBill,
  283. },
  284. data() {
  285. return {
  286. showPayPopup: false,
  287. payInfo: {},
  288. currComponent: "",
  289. role: "",
  290. title: "",
  291. disabledAll: false,
  292. showPopup: false,
  293. popupTitle: "",
  294. flag: false,
  295. checkedAll: false,
  296. checkedCollapse: [],
  297. amount: 0,
  298. activeTab: "",
  299. activeTabBar: 0,
  300. activeCollapse: "",
  301. costCycleTitle: "计费周期",
  302. costTypeTitle: "缴费类型",
  303. statusTitle: "支付状态",
  304. reduceDateTitle: "扣缴时间",
  305. typeTitle: "扣缴类型",
  306. operatorTitle: "操作人",
  307. costCycleList: [],
  308. payStatusList: [],
  309. reduceDateList: [],
  310. payTypeList: [],
  311. operatorList: [],
  312. propertyList: [],
  313. dataForm: {
  314. tenantId: "",
  315. costCycle: "2022-08",
  316. costType: "",
  317. status: "",
  318. type: "",
  319. reduceDate: "",
  320. operator: "",
  321. page: 1,
  322. limit: 10,
  323. },
  324. dataList: [],
  325. loading: false,
  326. refreshing: false,
  327. finished: false,
  328. };
  329. },
  330. watch: {
  331. checkedCollapse: {
  332. handler(newval, oldval) {
  333. if (newval.length == this.dataList.length) {
  334. if (this.dataList.length) {
  335. this.checkedAll = true;
  336. }
  337. } else {
  338. this.checkedAll = false;
  339. }
  340. this.amount = 0;
  341. this.checkedCollapse.forEach((item) => {
  342. this.amount += this.dataList.find((ele) => ele.id == item).amount;
  343. });
  344. },
  345. deep: true,
  346. },
  347. checkedAll: {
  348. handler(newval, oldval) {
  349. if (newval) {
  350. this.checkedCollapse = [];
  351. this.dataList.forEach((item) => {
  352. this.checkedCollapse.push(item.id);
  353. });
  354. } else {
  355. if (this.checkedCollapse.length == this.dataList.length) {
  356. this.checkedCollapse = [];
  357. }
  358. }
  359. },
  360. deep: true,
  361. },
  362. },
  363. created() {
  364. this.role = localStorage.getItem("role");
  365. this.title = this.$route.query.tenantName;
  366. this.dataForm.tenantId = this.$route.query.tenantId;
  367. this.dataForm.costCycle =
  368. this.$route.query.costCycle || this.dataForm.costCycle;
  369. this.activeTab = this.$route.query.activeTab;
  370. this.getPayStatusList();
  371. this.getPayTypeList();
  372. this.getPropertyTypeList();
  373. },
  374. methods: {
  375. getPayStatusList() {
  376. this.payStatusList = getDictDataList("PayStatus");
  377. this.payStatusList.forEach((item) => {
  378. item.text = item.dictLabel;
  379. item.value = item.dictValue;
  380. });
  381. },
  382. getPayTypeList() {
  383. this.payTypeList = getDictDataList("PayType");
  384. this.payTypeList.forEach((item) => {
  385. item.text = item.dictLabel;
  386. item.value = item.dictValue;
  387. if (item.value == "PreStorage") {
  388. item.color = "#30D3A2";
  389. }
  390. if (item.value == "Subsidy") {
  391. item.color = "#09C700";
  392. }
  393. if (item.value == "Refund") {
  394. item.color = "#FA5555";
  395. }
  396. if (item.value == "Water") {
  397. item.color = "#FF9C27";
  398. }
  399. if (item.value == "Elec") {
  400. item.color = "#FF9C27";
  401. }
  402. if (item.value == "PropertyFee") {
  403. item.color = "#FF9C27";
  404. }
  405. if (item.value == "CancelSubsidy") {
  406. item.color = "#ED3A25";
  407. }
  408. });
  409. },
  410. getPropertyTypeList() {
  411. this.propertyTypeList = getDictDataList("PropertyType");
  412. },
  413. dict_filter(val, list) {
  414. if (isEmpty(val)) {
  415. return "";
  416. }
  417. return this[list].find((item) => item.dictValue == val);
  418. },
  419. onLoad() {
  420. setTimeout(async () => {
  421. if (this.refreshing) {
  422. this.dataList = [];
  423. this.refreshing = false;
  424. }
  425. await this.getDataList();
  426. this.dataForm.page++; // 分页数加一
  427. }, 100);
  428. },
  429. onRefresh() {
  430. // 清空列表数据
  431. this.checkedAll = false;
  432. this.checkedCollapse = [];
  433. this.activeCollapse = "";
  434. this.amount = 0;
  435. this.finished = false;
  436. this.dataList = [];
  437. // 重新加载数据
  438. // 将 loading 设置为 true,表示处于加载状态
  439. this.loading = true;
  440. this.dataForm.page = 1; // 分页数赋值为1
  441. this.onLoad();
  442. },
  443. // 获取列表数据方法
  444. getDataList() {
  445. if (this.activeTab == "bill") {
  446. this.getRentBillList();
  447. }
  448. if (this.activeTab == "record") {
  449. this.getReduceRecordList();
  450. }
  451. },
  452. getRentBillList() {
  453. Api.rentBillDetail(this.dataForm).then((res) => {
  454. if (res.code == 0) {
  455. if (res.data) {
  456. if (res.data.length == 0) {
  457. // 判断获取数据条数若等于0
  458. this.dataList = []; // 清空数组
  459. this.finished = true; // 停止加载
  460. }
  461. res.data.forEach((item, index) => {
  462. item.id = "index_" + index;
  463. });
  464. // 若数据条数不等于0
  465. this.dataList.push(...res.data); // 将数据放入list中
  466. this.loading = false; // 加载状态结束
  467. this.disabledAll = this.dataList.every((item) => item.status == 1);
  468. // 如果list长度大于等于总数据条数,数据全部加载完成
  469. if (this.dataList.length >= res.data.length) {
  470. this.finished = true; // 结束加载状态
  471. }
  472. } else {
  473. // 判断获取数据条数若等于0
  474. this.dataList = []; // 清空数组
  475. this.finished = true; // 停止加载
  476. }
  477. } else {
  478. this.loading = false; // 加载状态结束
  479. this.finished = true; // 停止加载
  480. }
  481. });
  482. },
  483. getReduceRecordList() {
  484. Api.reduceRecordList(this.dataForm).then((res) => {
  485. if (res.code == 0) {
  486. if (res.data) {
  487. if (res.data.list.length == 0) {
  488. // 判断获取数据条数若等于0
  489. this.dataList = []; // 清空数组
  490. this.finished = true; // 停止加载
  491. }
  492. // 若数据条数不等于0
  493. this.dataList.push(...res.data.list); // 将数据放入list中
  494. this.loading = false; // 加载状态结束
  495. // 如果list长度大于等于总数据条数,数据全部加载完成
  496. if (this.dataList.length >= res.data.total) {
  497. this.finished = true; // 结束加载状态
  498. }
  499. } else {
  500. // 判断获取数据条数若等于0
  501. this.dataList = []; // 清空数组
  502. this.finished = true; // 停止加载
  503. }
  504. } else {
  505. this.loading = false; // 加载状态结束
  506. this.finished = true; // 停止加载
  507. }
  508. });
  509. },
  510. handelChange(type, val) {
  511. if (type == "costType") {
  512. // 这里打印出来的值就是我们想要的text
  513. this.costTypeTitle = this.payTypeList.filter(
  514. (item) => item.value === val
  515. )[0].text;
  516. }
  517. if (type == "type") {
  518. // 这里打印出来的值就是我们想要的text
  519. this.typeTitle = this.payTypeList.filter(
  520. (item) => item.value === val
  521. )[0].text;
  522. }
  523. if (type == "status") {
  524. // 这里打印出来的值就是我们想要的text
  525. this.typeTitle = this.payStatusList.filter(
  526. (item) => item.value === val
  527. )[0].text;
  528. }
  529. this.onRefresh();
  530. },
  531. handleChangeTab() {
  532. this.onRefresh();
  533. },
  534. handleChangeTabBar(val) {
  535. let popupTitle = "";
  536. let payType = "";
  537. if (val == 1) {
  538. popupTitle = "预存";
  539. payType = "PreStorage";
  540. }
  541. if (val == 2) {
  542. popupTitle = "补助";
  543. payType = "Subsidy";
  544. }
  545. if (val == 3) {
  546. popupTitle = "退费";
  547. payType = "Refund";
  548. }
  549. this.currComponent = "pay-fee";
  550. this.payInfo = {
  551. payType: payType,
  552. tenantId: this.dataForm.tenantId,
  553. popupTitle: popupTitle,
  554. };
  555. this.showPayPopup = true;
  556. },
  557. handleClick(type) {
  558. if (type == "fee") {
  559. this.currComponent = "pay-fee";
  560. this.payInfo = {
  561. payType: "PreStorage",
  562. tenantId: this.dataForm.tenantId,
  563. popupTitle: "预存",
  564. };
  565. }
  566. if (type == "bill") {
  567. let billIds = [];
  568. this.checkedCollapse.forEach((item) => {
  569. let tempBillList = [];
  570. tempBillList = this.dataList.find((ele) => ele.id == item).billLists;
  571. tempBillList.forEach((bill) => {
  572. billIds.push(bill.id);
  573. });
  574. });
  575. this.currComponent = "pay-bill";
  576. this.payInfo = {
  577. tenantId: this.dataForm.tenantId,
  578. amount: this.amount,
  579. billIds: billIds,
  580. };
  581. }
  582. this.showPayPopup = true;
  583. },
  584. close() {
  585. this.payInfo = {};
  586. this.showPayPopup = false;
  587. },
  588. backPath() {
  589. this.$router.back();
  590. },
  591. },
  592. };
  593. </script>
  594. <style lang="scss" scoped>
  595. .page_info {
  596. height: 100%;
  597. .search_pannel {
  598. background: #ffffff;
  599. /deep/ {
  600. .van-tabs__line {
  601. --van-tabs-bottom-bar-color: #2e69eb;
  602. }
  603. .van-dropdown-menu__bar {
  604. --van-gray-4: #999999;
  605. --van-dropdown-menu-title-font-size: 15px;
  606. --van-dropdown-menu-title-text-color: #0c1935;
  607. --van-dropdown-menu-box-shadow: 0;
  608. }
  609. .van-dropdown-item__option {
  610. .van-cell__title,
  611. .van-cell__value {
  612. font-size: 14px;
  613. }
  614. }
  615. }
  616. }
  617. .list_total {
  618. padding: 0 16px;
  619. margin: 8px 0;
  620. display: flex;
  621. text-align: left;
  622. .van-col {
  623. height: 16px;
  624. font-size: 12px;
  625. font-weight: 400;
  626. color: #999999;
  627. line-height: 16px;
  628. }
  629. .count_up {
  630. font-size: 16px;
  631. font-weight: 500;
  632. color: #fa5555;
  633. margin: 0 2px;
  634. }
  635. }
  636. .info_list {
  637. padding: 0 16px;
  638. .list_item {
  639. background: #ffffff;
  640. box-shadow: 0px 0px 10px 0px rgba(153, 153, 153, 0.15);
  641. border-radius: 4px;
  642. margin-bottom: 12px;
  643. padding: 6px 0;
  644. display: flex;
  645. flex-direction: column;
  646. align-items: flex-start;
  647. position: relative;
  648. &:nth-last-child(1) {
  649. margin-bottom: 0;
  650. }
  651. .list_btn {
  652. position: absolute;
  653. bottom: 15px;
  654. right: 12px;
  655. .van-button {
  656. &:nth-child(2) {
  657. margin: 0 12px;
  658. }
  659. }
  660. }
  661. .collapse_title {
  662. .label {
  663. font-size: 16px;
  664. font-weight: 500;
  665. color: #666666;
  666. }
  667. }
  668. .collapse_info {
  669. .info_item {
  670. text-align: left;
  671. margin-bottom: 2px;
  672. .van-col {
  673. height: 20px;
  674. font-size: 14px;
  675. color: #9da0ac;
  676. line-height: 20px;
  677. }
  678. &:nth-last-child(1) {
  679. margin: 0;
  680. }
  681. }
  682. }
  683. /deep/ {
  684. .van-cell:after {
  685. border-bottom: 0;
  686. }
  687. .van-collapse-item__content {
  688. padding: 0 16px;
  689. }
  690. }
  691. }
  692. .reduce_record {
  693. .van-col {
  694. height: 18px;
  695. font-size: 14px;
  696. color: #999999;
  697. line-height: 18px;
  698. margin-bottom: 4px;
  699. &:nth-last-child(1) {
  700. margin-bottom: 0;
  701. }
  702. }
  703. .header {
  704. .van-col {
  705. font-size: 16px;
  706. color: #0c1935;
  707. line-height: 22px;
  708. margin-bottom: 8px;
  709. }
  710. }
  711. }
  712. .reduce_type {
  713. position: absolute;
  714. top: 0;
  715. right: 0;
  716. height: 24px;
  717. padding: 0 12px;
  718. border-radius: 0px 4px 0px 10px;
  719. .van-col {
  720. font-size: 12px;
  721. font-weight: 400;
  722. color: #ffffff;
  723. line-height: 16px;
  724. }
  725. }
  726. }
  727. }
  728. </style>
  729. <style lang="scss">
  730. .tab_bar {
  731. /deep/ {
  732. .van-tabbar-item {
  733. color: #2e69eb;
  734. font-size: 14px;
  735. font-weight: 600;
  736. }
  737. }
  738. }
  739. .popup_info {
  740. height: auto;
  741. box-shadow: 0px -10px 20px 0px rgba(27, 32, 38, 0.1);
  742. border-radius: 20px 20px 0px 0px;
  743. }
  744. </style>