ordering.vue 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. <template>
  2. <view class="container">
  3. <image class="bg" src="../static/charge-ordering-bg.png" mode="widthFix" />
  4. <view class="body">
  5. <view class="iphonex-placeholder"></view>
  6. <view
  7. class="status flex-center transition"
  8. :style="{
  9. opacity: step >= 1 ? '1' : '0',
  10. }"
  11. >
  12. <image
  13. :class="['border', `${step <= 2 ? 'border-animation' : ''}`]"
  14. src="../static/charge-ordering-border.png"
  15. @load="onImgLoad"
  16. />
  17. <view class="timer flex-column flex-center">
  18. <block v-if="step === 1">
  19. <view>
  20. <text class="fw-600" style="font-size: 100rpx">{{
  21. status.time
  22. }}</text>
  23. <text class="fs-40 fw-500 ml-10">s</text>
  24. </view>
  25. <view class="fs-26">充电启动中</view>
  26. </block>
  27. <block v-if="step === 2">
  28. <image class="icon" src="../static/charge-ordering-icon.png" />
  29. <view class="fs-26 mt-10">充电中...</view>
  30. </block>
  31. <block v-if="step === 3">
  32. <image class="icon" src="../static/charge-ordering-finish.png" />
  33. <view class="fs-26 mt-10">充电结束</view>
  34. </block>
  35. </view>
  36. </view>
  37. </view>
  38. </view>
  39. <style-bottom-view>
  40. <view
  41. class="transition pl-60 pr-60 pb-40"
  42. :style="{
  43. opacity: step >= 1 ? '1' : '0',
  44. }"
  45. >
  46. <view class="mb-40" v-if="step === 2 || step === 3">
  47. <shadow-card :list="chargeInfo"></shadow-card>
  48. </view>
  49. <style-button
  50. v-if="step === 1 || step === 2"
  51. type="warning"
  52. size="small"
  53. @click="cancel"
  54. >取消充电</style-button
  55. >
  56. <style-button v-if="step === 3" type="primary" size="small" @click="back"
  57. >返回首页</style-button
  58. >
  59. </view>
  60. </style-bottom-view>
  61. </template>
  62. <script setup lang="ts">
  63. import { onHide, onLoad, onShow } from "@dcloudio/uni-app";
  64. import { cancelCharge, fetchChargeStatus, startCharge } from "../../api/charge";
  65. import { ref } from "vue";
  66. import { format } from "../../utils/date";
  67. let timer: any;
  68. let statusTimer: any;
  69. const step = ref(0);
  70. const options = ref<any>();
  71. const status = ref({
  72. time: 30,
  73. start: false,
  74. cancel: false,
  75. error: false,
  76. });
  77. const chargeInfo = ref<any[]>([]);
  78. const startStartTimer = () => {
  79. if (status.value.start || status.value.cancel || status.value.error) {
  80. timer && clearTimeout(timer);
  81. return;
  82. }
  83. timer = setTimeout(() => {
  84. if (status.value.time <= 1 && !status.value.start) {
  85. uni.showModal({
  86. title: "充电错误",
  87. content: "出现问题,请重试",
  88. showCancel: false,
  89. confirmText: "知道了",
  90. confirmColor: "#347DFF",
  91. success() {
  92. uni.navigateBack();
  93. },
  94. });
  95. return;
  96. }
  97. status.value.time = status.value.time - 1;
  98. startStartTimer();
  99. }, 1000);
  100. };
  101. const startStatusTimer = () => {
  102. statusTimer = setTimeout(() => {
  103. fetchChargeStatus()
  104. .then((res) => {
  105. if (status.value.cancel) {
  106. return;
  107. }
  108. if ([1, 2].includes(res.chargeStatus)) {
  109. setChargeData(res);
  110. }
  111. startStatusTimer();
  112. })
  113. .catch(() => {
  114. startStatusTimer();
  115. });
  116. }, 30000);
  117. };
  118. const start = () => {
  119. step.value = 1;
  120. startStartTimer();
  121. startCharge(options.value && options.value.sn ? options.value.sn : "")
  122. .then(() => {
  123. fetchStatus();
  124. })
  125. .catch((err) => {
  126. setTimeout(() => {
  127. status.value.error = true;
  128. timer && clearTimeout(timer);
  129. uni.showModal({
  130. content: `${err.errMsg}`,
  131. showCancel: false,
  132. success: () => {
  133. uni.navigateBack();
  134. },
  135. });
  136. }, 300);
  137. });
  138. };
  139. const back = () => {
  140. uni.navigateBack();
  141. };
  142. const cancel = () => {
  143. uni.showModal({
  144. title: "停止充电",
  145. content: "是否停止充电",
  146. cancelText: "停止",
  147. cancelColor: "#999999",
  148. confirmText: "点错了",
  149. confirmColor: "#347DFF",
  150. success: (res) => {
  151. if (res.cancel) {
  152. clearTimeout(timer);
  153. status.value.cancel = true;
  154. if ([1, 2].includes(step.value)) {
  155. if (status.value.start) {
  156. finish();
  157. } else {
  158. uni.showLoading({
  159. title: "正在取消",
  160. });
  161. cancelCharge(
  162. options.value && options.value.sn ? options.value.sn : ""
  163. )
  164. .then(() => {
  165. // console.log(res)
  166. uni.hideLoading();
  167. uni.showToast({
  168. title: "已取消充电",
  169. icon: "none",
  170. });
  171. setTimeout(() => {
  172. uni.navigateBack();
  173. }, 2000);
  174. })
  175. .catch(() => {
  176. uni.hideLoading();
  177. uni.showToast({
  178. title: "已取消充电",
  179. icon: "none",
  180. });
  181. setTimeout(() => {
  182. uni.navigateBack();
  183. }, 2000);
  184. });
  185. }
  186. }
  187. }
  188. },
  189. });
  190. };
  191. const finish = () => {
  192. uni.showLoading({
  193. title: "正在结束中",
  194. });
  195. fetchChargeStatus()
  196. .then((res) => {
  197. if ([1, 2].includes(res.chargeStatus)) {
  198. // 当前充电中
  199. const start = new Date(res.startTime.replace(/-/g, "/"));
  200. const end = new Date();
  201. const diff = parseInt(`${(end.getTime() - start.getTime()) / 1000}`);
  202. const min = parseInt(`${diff / 60}`);
  203. const time =
  204. min >= 60
  205. ? `${parseInt(`${min / 60}`)}小时${parseInt(
  206. `${min - parseInt(`${min / 60}`) * 60}`
  207. )}分钟`
  208. : `${parseInt(`${diff / 60}`)}分钟`;
  209. const endFormat = format("y-M-d h:m:s");
  210. const _chargeInfo = [
  211. {
  212. label: "累计充电量",
  213. value: `${res.totalPower}度`,
  214. },
  215. {
  216. label: "累计费用",
  217. value: `${res.elecMoney}元`,
  218. },
  219. {
  220. label: "开始时间",
  221. value: res.startTime,
  222. },
  223. {
  224. label: "结束时间",
  225. value: endFormat,
  226. },
  227. {
  228. label: "累计用时",
  229. value: time,
  230. },
  231. ];
  232. if (res.soc) {
  233. _chargeInfo.unshift({
  234. label: "剩余电量",
  235. value: `${res.soc}%`,
  236. });
  237. }
  238. chargeInfo.value = _chargeInfo;
  239. cancelCharge(options.value && options.value.sn ? options.value.sn : "")
  240. .then(() => {
  241. uni.hideLoading();
  242. if (res.failReason) {
  243. uni.showModal({
  244. content: res.failReason,
  245. showCancel: false,
  246. success() {
  247. uni.navigateBack();
  248. },
  249. });
  250. return;
  251. }
  252. step.value = 3;
  253. })
  254. .catch((err) => {
  255. console.log(err);
  256. uni.hideLoading();
  257. uni.showToast({
  258. title: "已取消充电",
  259. icon: "none",
  260. });
  261. setTimeout(() => {
  262. uni.navigateBack();
  263. }, 2000);
  264. });
  265. }
  266. })
  267. .catch((err) => {
  268. console.log(err);
  269. uni.hideLoading();
  270. uni.showModal({
  271. title: "温馨提示",
  272. content: "出现错误,请重试",
  273. showCancel: false,
  274. confirmText: "重试",
  275. confirmColor: "#347DFF",
  276. success: () => {
  277. finish();
  278. },
  279. });
  280. });
  281. };
  282. const setChargeData = (res: any) => {
  283. const start = new Date(res.startTime.replace(/-/g, "/"));
  284. const end = new Date();
  285. const diff = parseInt(`${(end.getTime() - start.getTime()) / 1000}`);
  286. const min = parseInt(`${diff / 60}`);
  287. const time =
  288. min >= 60
  289. ? `${parseInt(`${min / 60}`)}小时${parseInt(
  290. `${min - parseInt(`${min / 60}`) * 60}`
  291. )}分钟`
  292. : `${parseInt(`${diff / 60}`)}分钟`;
  293. const _chargeInfo = [
  294. {
  295. label: "累计充电量",
  296. value: `${res.totalPower}度`,
  297. },
  298. {
  299. label: "累计费用",
  300. value: `${res.elecMoney}元`,
  301. },
  302. {
  303. label: "开始时间",
  304. value: res.startTime,
  305. },
  306. {
  307. label: "累计用时",
  308. value: time,
  309. },
  310. ];
  311. if (res.soc) {
  312. _chargeInfo.unshift({
  313. label: "剩余电量",
  314. value: `${res.soc}%`,
  315. });
  316. }
  317. chargeInfo.value = _chargeInfo;
  318. };
  319. const fetchStatus = (data?: any) => {
  320. if (status.value.cancel) {
  321. return;
  322. }
  323. const promise = data ? Promise.resolve(data) : fetchChargeStatus();
  324. promise
  325. .then((res) => {
  326. if ([1, 2].includes(res.chargeStatus)) {
  327. // 当前充电中
  328. status.value.start = true;
  329. step.value = 2;
  330. setChargeData(res);
  331. startStatusTimer();
  332. }
  333. })
  334. .catch((err) => {
  335. console.log(err);
  336. setTimeout(() => {
  337. fetchStatus(data);
  338. }, 1000);
  339. });
  340. };
  341. const onImgLoad = () => {
  342. fetchChargeStatus()
  343. .then((res) => {
  344. if ([1, 2].includes(res.chargeStatus)) {
  345. if (options.value && options.value.sn === res.connectorId) {
  346. fetchStatus(res);
  347. return;
  348. }
  349. // 当前充电中
  350. uni.showModal({
  351. title: "温馨提示",
  352. content: "当前有正在充电中的订单",
  353. showCancel: false,
  354. confirmText: "查看订单",
  355. confirmColor: "#347DFF",
  356. success: () => {
  357. fetchStatus(res);
  358. },
  359. });
  360. } else {
  361. start();
  362. }
  363. })
  364. .catch((err) => {
  365. console.log(err);
  366. start();
  367. });
  368. };
  369. onLoad((_options: any) => {
  370. options.value = _options;
  371. });
  372. onHide(() => {
  373. timer && clearTimeout(timer);
  374. statusTimer && clearTimeout(statusTimer);
  375. });
  376. onShow(() => {
  377. startStartTimer();
  378. });
  379. </script>
  380. <style lang="scss">
  381. .container {
  382. height: 100vh;
  383. width: 100%;
  384. background-color: #fff;
  385. position: relative;
  386. overflow: hidden;
  387. .bg {
  388. width: 100%;
  389. position: absolute;
  390. left: 50%;
  391. top: 50%;
  392. transform: translate(-50%, -50%);
  393. transform-origin: center;
  394. }
  395. .body {
  396. position: absolute;
  397. left: 0;
  398. top: 0;
  399. height: 100%;
  400. width: 100%;
  401. .iphonex-placeholder {
  402. box-sizing: content-box;
  403. padding-bottom: constant(safe-area-inset-bottom);
  404. padding-bottom: env(safe-area-inset-bottom);
  405. }
  406. .status {
  407. width: 420rpx;
  408. height: 420rpx;
  409. border-radius: 50%;
  410. position: relative;
  411. margin: 0 auto;
  412. margin-top: 130rpx;
  413. .border {
  414. width: 100%;
  415. height: 100%;
  416. }
  417. .border-animation {
  418. animation: rot 3s linear infinite;
  419. }
  420. .timer {
  421. position: absolute;
  422. width: 340rpx;
  423. height: 340rpx;
  424. left: 50%;
  425. top: 50%;
  426. transform: translate(-50%, -50%);
  427. background: linear-gradient(180deg, #ffffff 0%, #ecf3ff 100%);
  428. box-shadow: 0px 18rpx 30rpx rgba(0, 0, 0, 0.1);
  429. border-radius: 50%;
  430. .icon {
  431. width: 152rpx;
  432. height: 152rpx;
  433. }
  434. }
  435. }
  436. }
  437. }
  438. @keyframes rot {
  439. 0% {
  440. transform: rotate(0deg);
  441. }
  442. 100% {
  443. transform: rotate(360deg);
  444. }
  445. }
  446. </style>