index.vue 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. <template>
  2. <view class="container fixed">
  3. <view class="toolbar" v-if="chargeInfo">
  4. <view class="tool-title">Charge</view>
  5. <view class="tool-desc" v-if="chargeInfo.chargeBoxId">{{chargeInfo.chargeBoxId + "-" + chargeInfo.connectorId}}</view>
  6. <view class="tool-desc" v-else>-</view>
  7. </view>
  8. <header-view
  9. :info="connectorInfo"
  10. :status="connectorInfo.status"
  11. :isLoading="isLoading"
  12. :password="password"/>
  13. <info-view
  14. :info="connectorInfo"
  15. :isLoading="isLoading"/>
  16. <payment-view
  17. v-if="connectorInfo.status == 'Preparing'"
  18. :info="connectorInfo"/>
  19. <divide size="36"/>
  20. <view class="bottom-button">
  21. <button
  22. v-if="connectorInfo.status == 'Initiating'"
  23. class="ui-button margin0"
  24. type="primary"
  25. @click="onStart"
  26. :disabled="!connectorInfo.shouldClickStart">START CHARGING</button>
  27. <button
  28. v-else-if="connectorInfo.status == 'Charging'"
  29. class="ui-button margin0"
  30. type="primary"
  31. @click="stopCharge">INPUT PIN TO STOP CHARGING</button>
  32. <view class="flexc" v-else-if="connectorInfo.status == 'Finishing'">
  33. <button
  34. class="ui-button margin0 flex3"
  35. type="primary"
  36. :disabled="!chargingPk"
  37. @click="toReceipt">VIEW RECEIPT</button>
  38. <divide :size="24"/>
  39. <button
  40. class="ui-button margin0 flex1"
  41. type="accent"
  42. @click="goBack">EXIT</button>
  43. </view>
  44. <template v-else-if="connectorInfo.status == 'Preparing'">
  45. <template v-if="password">
  46. <button
  47. class="ui-button margin0"
  48. type="primary"
  49. @click="onStart"
  50. v-if="connectorInfo.paymentStatus == 'PAID'">START CHARGING</button>
  51. <button
  52. class="ui-button margin0"
  53. type="primary"
  54. @click="onPayment"
  55. v-else>
  56. <view class="flexcc">
  57. <text>MAKE PAYMENT</text>
  58. <view class="icon-key" v-if="false">
  59. <i-icon name="key-fill" size="32rpx" color="#333"/>
  60. </view>
  61. </view>
  62. </button>
  63. </template>
  64. <button
  65. v-else
  66. class="ui-button margin0"
  67. type="accent"
  68. @click="showPinPage">INPUT PIN</button>
  69. </template>
  70. <button
  71. v-else-if="connectorInfo.status == 'Available' && isLoading"
  72. class="ui-button margin0"
  73. type="cancel"
  74. @click="cancelAuth">CANCEL</button>
  75. <button
  76. v-else
  77. class="ui-button margin0"
  78. type="primary"
  79. @click="onAuthentic"
  80. :disabled="connectorInfo.status != 'Available' || isLoading">
  81. <view class="flexcc">
  82. <text>AUTHENTICATE</text>
  83. <view class="icon-key" v-if="false">
  84. <i-icon name="key-fill" size="32rpx" color="#333"/>
  85. </view>
  86. </view>
  87. </button>
  88. </view>
  89. <PasswordView
  90. :visible="showPin || stopPin"
  91. :verify="stopPin"
  92. @change="changePassword"/>
  93. </view>
  94. </template>
  95. <script>
  96. import HeaderView from './views/HeaderView.vue';
  97. import InfoView from './views/InfoView.vue';
  98. import PaymentView from './views/PaymentView.vue';
  99. import PasswordView from '@/components/PasswordView.vue';
  100. import apiCharge from '@/api/apiCharge';
  101. import {openUrl} from '@/utils/utils.js';
  102. import settings from '../../settings';
  103. import auth from '../../utils/auth';
  104. export default {
  105. data() {
  106. return {
  107. refreshId: 0,
  108. isLoading: false,
  109. waitPayment: false,
  110. isPaymentFailed: false,
  111. chargeInfo: {
  112. chargeBoxId: "",
  113. connectorId: ""
  114. },
  115. connectorInfo: {},
  116. stoped: false,
  117. creditHistoryPk: "",
  118. chargingPk: "",
  119. paymentId:"",
  120. showPin: false,
  121. stopPin: false,
  122. password: ""
  123. }
  124. },
  125. components: {
  126. HeaderView,
  127. InfoView,
  128. PaymentView,
  129. PasswordView
  130. },
  131. onLoad(query) {
  132. if (query.pk) {
  133. this.paymentId = query.pk;
  134. }
  135. if (query.info) {
  136. this.chargeInfo = JSON.parse(decodeURIComponent(query.info));
  137. } /*else {
  138. this.waitPayment = getApp().globalData.waitPayment;
  139. let id = auth.getPaymentId();
  140. if (id) {
  141. this.paymentId = id;
  142. }
  143. }*/
  144. if (!query.pk && !query.info) {
  145. uni.reLaunch({
  146. url: "/pages/index/index"
  147. });
  148. return;
  149. }
  150. this.refreshStatus(500);
  151. },
  152. methods: {
  153. goBack() {
  154. uni.redirectTo({
  155. url: "/pages/index/index"
  156. })
  157. },
  158. refreshStatus(time=2000) {
  159. this.refreshId += 1;
  160. setTimeout(() => {
  161. if (this.stoped) {
  162. return;
  163. }
  164. if (this.paymentId) {
  165. this.getChargingStatus(this.refreshId);
  166. } else if (this.chargeInfo.connectorId) {
  167. this.getChargerInfo(this.refreshId)
  168. }
  169. }, time);
  170. },
  171. getChargerInfo(id) {
  172. if (id !== this.refreshId) {
  173. return;
  174. }
  175. apiCharge.getChargerDetails(this.chargeInfo).then(res => {
  176. if (res.data) {
  177. this.connectorInfo = res.data;
  178. this.showPageWithStatus()
  179. }
  180. }).catch(err => {
  181. uni.showModal({
  182. title: "Error",
  183. content: err,
  184. confirmText: "OK",
  185. showCancel: false,
  186. success: res => {
  187. if (res.confirm) {
  188. this.goBack();
  189. }
  190. }
  191. })
  192. }).finally(() => {
  193. uni.stopPullDownRefresh();
  194. })
  195. },
  196. getChargingStatus(id) {
  197. if (id !== this.refreshId) {
  198. return;
  199. }
  200. apiCharge.getChargingDetails({
  201. creditHistoryPk: this.paymentId
  202. }).then(res => {
  203. if (res.data) {
  204. this.connectorInfo = res.data;
  205. if (res.data.creditHistoryPk) {
  206. this.createPayment(res.data.creditHistoryPk);
  207. }
  208. if (!this.chargeInfo.chargeBoxId && res.data.chargeBoxId) {
  209. this.chargeInfo.chargeBoxId = res.data.chargeBoxId;
  210. this.chargeInfo.connectorId = res.data.connectorId;
  211. }
  212. this.showPageWithStatus()
  213. }
  214. }).catch(err => {
  215. /*uni.showToast({
  216. icon: "none",
  217. title: err
  218. })*/
  219. uni.showModal({
  220. title: "Error",
  221. content: err,
  222. confirmText: "OK",
  223. showCancel: false,
  224. success: res => {
  225. if (res.confirm) {
  226. this.goBack();
  227. }
  228. }
  229. })
  230. }).finally(() => {
  231. uni.stopPullDownRefresh();
  232. })
  233. },
  234. showPageWithStatus() {
  235. //this.connectorInfo.status = "Charging"
  236. switch (this.connectorInfo.status) {
  237. case "Available":
  238. if (this.isLoading) {
  239. this.refreshStatus(3000);
  240. }
  241. break;
  242. case "Preparing":
  243. this.isLoading = false;
  244. if (this.connectorInfo.paymentStatus == "FAILED") {
  245. this.isPaymentFailed = true;
  246. }
  247. break;
  248. case "Initiating":
  249. if (this.isLoading || this.waitPayment) {
  250. this.refreshStatus(3000);
  251. } else {
  252. this.isLoading = true;
  253. this.refreshStatus(3000);
  254. }
  255. break;
  256. case "Charging":
  257. if (this.waitPayment) {
  258. this.isLoading = true;
  259. this.waitPayment = false;
  260. getApp().globalData.waitPayment = false;
  261. this.refreshStatus(3000);
  262. } else {
  263. this.isLoading = false;
  264. this.refreshStatus(10000);
  265. }
  266. break;
  267. case "Finishing":
  268. if (this.connectorInfo.chargingPk) {
  269. this.chargingPk = this.connectorInfo.chargingPk;
  270. //this.toReceipt();
  271. } else {
  272. this.refreshStatus(5000);
  273. }
  274. break;
  275. default:
  276. this.refreshId = 0;
  277. this.isLoading = false;
  278. break;
  279. }
  280. uni.hideLoading();
  281. },
  282. changePassword(psd) {
  283. this.password = psd;
  284. if (this.stopPin) {
  285. this.stopPin = false;
  286. this.onStop();
  287. } else {
  288. this.showPin = false;
  289. //this.onAuthentic();
  290. }
  291. },
  292. refreshPayment() {
  293. uni.showLoading({
  294. title: "Waiting..."
  295. });
  296. this.getChargingStatus();
  297. },
  298. onAuthentic() {
  299. this.isLoading = true;
  300. this.refreshStatus();
  301. },
  302. showPinPage() {
  303. this.showPin = true;
  304. },
  305. cancelAuth() {
  306. this.isLoading = false;
  307. },
  308. onPayment() {
  309. if (!this.password) {
  310. this.showPin = true;
  311. return;
  312. }
  313. if (this.connectorInfo.alertContent) {
  314. uni.showModal({
  315. title: "Note",
  316. content: this.connectorInfo.alertContent,
  317. showCancel: true,
  318. success: rs => {
  319. if (rs.confirm) {
  320. this.requestPayment()
  321. }
  322. }
  323. })
  324. } else if (this.connectorInfo.preAuthAmount) {
  325. uni.showModal({
  326. title: "Pre-Authorization Payment",
  327. content: this.connectorInfo.preAuthAmount + " will be held for Pre-Authorization.\nUpon charging completion, this amount will be refunded and actual usage will be charged.",
  328. showCancel: true,
  329. success: rs => {
  330. if (rs.confirm) {
  331. this.requestPayment()
  332. }
  333. }
  334. })
  335. } else {
  336. uni.showModal({
  337. title: "Pre-Authorization Payment",
  338. content: "S$50 will be held for Pre-Authorization.\nUpon charging completion, this amount will be refunded and actual usage will be charged.",
  339. showCancel: true,
  340. success: rs => {
  341. if (rs.confirm) {
  342. this.requestPayment()
  343. }
  344. }
  345. })
  346. }
  347. },
  348. requestPayment() {
  349. uni.showLoading({
  350. title: "Waiting..."
  351. })
  352. apiCharge.makePayment({
  353. ...this.chargeInfo,
  354. pin: this.password
  355. }).then(res => {
  356. if (res.data.creditHistoryPk) {
  357. this.createPayment(res.data.creditHistoryPk);
  358. }
  359. if (res.data.webPaymentUrl) {
  360. openUrl(res.data.webPaymentUrl);
  361. }
  362. }).catch(err => {
  363. uni.showModal({
  364. title: "Error",
  365. content: err,
  366. confirmText: "OK",
  367. showCancel: false,
  368. })
  369. /*uni.showToast({
  370. icon: "none",
  371. title: err
  372. })*/
  373. }).finally(() => {
  374. uni.hideLoading();
  375. });
  376. },
  377. onStart() {
  378. this.isLoading = true;
  379. uni.showLoading({
  380. title: "Loading..."
  381. })
  382. apiCharge.startCharge({
  383. //connectorPk: this.connectorPk,
  384. creditHistoryPk: this.paymentId
  385. }).then(res => {
  386. this.refreshStatus();
  387. if (res.msg) {
  388. uni.showToast({
  389. icon: "none",
  390. title: res.msg
  391. })
  392. } else {
  393. uni.hideLoading();
  394. }
  395. }).catch(err => {
  396. this.isLoading = false;
  397. //this.paymentId = "";
  398. //auth.setPaymentId("");
  399. this.connectorInfo.paymentStatus = "";
  400. uni.showToast({
  401. icon: "none",
  402. title: err
  403. })
  404. })
  405. },
  406. stopCharge() {
  407. uni.showModal({
  408. title: "Confirm Stop Charging?",
  409. content: "Your charging session will stop",
  410. confirmText: "CONFIRM",
  411. cancelText: "CANCEL",
  412. success: res => {
  413. if (res.confirm) {
  414. this.stopPin = true;
  415. }
  416. }
  417. })
  418. },
  419. onStop() {
  420. uni.showLoading({
  421. title: "Stopping..."
  422. })
  423. apiCharge.stopCharge({
  424. creditHistoryPk: this.paymentId,
  425. pin: this.password
  426. }).then(res => {
  427. this.stoped = true;
  428. this.paymentId = "";
  429. auth.setPaymentId("");
  430. if (res.data.chargingPk) {
  431. uni.hideLoading();
  432. this.connectorInfo.status = "Finishing";
  433. this.chargingPk = res.data.chargingPk;
  434. //this.toReceipt();
  435. } else {
  436. uni.showToast({
  437. icon: "none",
  438. title: "Stop failed"
  439. });
  440. this.refreshStatus();
  441. }
  442. }).catch(err => {
  443. uni.showModal({
  444. title: "Error",
  445. content: err,
  446. confirmText: "OK",
  447. showCancel: false
  448. })
  449. uni.hideLoading();
  450. this.refreshStatus();
  451. })
  452. },
  453. confirmStop() {
  454. uni.showModal({
  455. title: "Confirm Stop Charging?",
  456. content: "Your charging session will stop",
  457. confirmText: "CONFIRM",
  458. cancelText: "BACK",
  459. //confirmColor: "var(--primary-color)",
  460. success: (res) => {
  461. if (res.confirm) {
  462. this.onStop();
  463. }
  464. }
  465. })
  466. },
  467. createPayment(id) {
  468. if (id) {
  469. this.paymentId = id;
  470. //auth.setPaymentId("" + id);
  471. }
  472. },
  473. resetPayment() {
  474. this.isLoading = false;
  475. this.waitPayment = false;
  476. this.isPaymentFailed = false;
  477. getApp().globalData.waitPayment = false;
  478. },
  479. toReceipt() {
  480. uni.navigateTo({
  481. url: "/pages/receipt/index?id=" + this.chargingPk
  482. })
  483. }
  484. },
  485. onPullDownRefresh() {
  486. this.refreshStatus(500);
  487. }
  488. }
  489. </script>
  490. <style scoped>
  491. .container {
  492. display: flex;
  493. flex-direction: column;
  494. }
  495. .toolbar {
  496. display: flex;
  497. padding: 16rpx;
  498. position: relative;
  499. align-items: center;
  500. flex-direction: column;
  501. justify-content: center;
  502. background-color: white;
  503. }
  504. .tool-title {
  505. color: #111;
  506. font-size: 32rpx;
  507. font-weight: bold;
  508. padding-bottom: 4rpx;
  509. }
  510. .tool-desc {
  511. color: #666;
  512. font-size: 24rpx;
  513. }
  514. .bottom-button {
  515. padding: 32rpx;
  516. background-color: white;
  517. box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.1);
  518. }
  519. .icon-key {
  520. padding: 0 8rpx;
  521. transform: rotate(-90deg);
  522. }
  523. .ui-button[disabled] >>> .icon-key span {
  524. color: #888;
  525. }
  526. </style>