appointment.vue 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. <template>
  2. <!-- #ifdef MP-WEIXIN -->
  3. <page-meta page-style="overflow: {{X || R ? 'hidden' : 'visible'}}" />
  4. <!-- #endif -->
  5. <view :class="['page']">
  6. <view v-if="data && priceInfo">
  7. <view class="block">
  8. <view class="station">
  9. <ChargeMachine
  10. :title="'NO.' + data.equipment.shortId"
  11. :list="data.equipment.connectorInfos"
  12. :time="priceInfo.useTime"
  13. :parkingNo="data.equipment.parkingNo"
  14. ></ChargeMachine>
  15. </view>
  16. <view class="pt-20 pb-20 pl-30 pr-30 flex-align-center">
  17. <image
  18. src="/pages-charge/static/machines-banner-address.png"
  19. mode="widthFix"
  20. class="flex-shrink mr-12 width-40"
  21. />
  22. <view class="fs-26 color-666">{{ data.station.address }}</view>
  23. </view>
  24. </view>
  25. <view class="mt-40 color-999 fs-32 fw-500">费用说明</view>
  26. <view
  27. class="mt-20 block height-96 flex-align-center pl-30 pr-30"
  28. @click="openPriceDesc"
  29. >
  30. <view class="fs-26 color-666">充电费用</view>
  31. <view class="ml-64 fs-26 color-333"
  32. >{{ priceInfo.minPrice }}~{{ priceInfo.maxPrice }}元/度</view
  33. >
  34. <view class="ml-auto">
  35. <uni-icons type="right" size="16" color="rgba(0,0,0,0.4)"></uni-icons>
  36. </view>
  37. </view>
  38. <template v-if="appointmentData">
  39. <view class="mt-40 color-999 fs-32 fw-500">已预约充电</view>
  40. <view class="mt-20 block flex-align-center" style="height: 180rpx">
  41. <image
  42. class="width-56 ml-30"
  43. src="/pages-charge/static/icon-alarm.png"
  44. mode="widthFix"
  45. ></image>
  46. <view class="ml-24">
  47. <view class="flex" v-if="appointmentCountDown">
  48. <view class="fs-28 color-000">将在</view>
  49. <view class="fs-44 lh-36 color-primary ml-8 mr-8">{{
  50. appointmentCountDown
  51. }}</view>
  52. <view class="fs-28 color-000">后开始充电</view>
  53. </view>
  54. <view class="fs-24 color-999 mt-8"
  55. >请在{{ appointmentData.startTime }}前到达充电桩并开始充电</view
  56. >
  57. </view>
  58. </view>
  59. <view class="mt-40 flex-center">
  60. <view
  61. class="flex-center height-68 br-68 fs-26 color-666"
  62. style="width: 184rpx; border: 1px solid rgba(0, 0, 0, 0.3)"
  63. @click="cancelAppointment"
  64. >取消预约</view
  65. >
  66. </view>
  67. </template>
  68. <template v-else>
  69. <view class="mt-40 color-999 fs-32 fw-500">选择充电方式</view>
  70. <view class="mt-20 block pl-30 pr-30">
  71. <view
  72. v-for="(type, index) in chargeTypes"
  73. :key="index"
  74. :class="['pt-40', 'pb-40', 'flex-align-center']"
  75. :style="{
  76. borderTop: index === 0 ? '' : '1rpx solid rgba(0, 0, 0, 0.10)',
  77. }"
  78. @click="changeType(index)"
  79. >
  80. <view>
  81. <view class="fs-28 lh-28 color-000 fw-500">{{ type.title }}</view>
  82. <view
  83. class="fs-24 lh-24 mt-16"
  84. style="color: #f8386a"
  85. v-if="chargeType === index"
  86. >{{ type.checkTip }}</view
  87. >
  88. <view class="fs-24 color-999 lh-24 mt-16" v-else>{{
  89. type.tip
  90. }}</view>
  91. </view>
  92. <view class="ml-auto">
  93. <style-checkbox :checked="chargeType === index"></style-checkbox>
  94. </view>
  95. </view>
  96. </view>
  97. <view class="mt-20 block pl-30 pr-30" v-if="chargeType === 0">
  98. <view
  99. class="pt-40 pb-40 flex-between"
  100. style="border-bottom: 1rpx solid rgba(0, 0, 0, 0.1)"
  101. @click="selectTime"
  102. >
  103. <view class="fs-28 color-000 fw-500">充电时间</view>
  104. <view class="flex-align-center lh-28">
  105. <block v-if="chargeTime.isPowerSaving">
  106. <view class="fs-28 color-333 fw-500 mr-16">00:00 - 08:00</view>
  107. </block>
  108. <block v-else>
  109. <view
  110. v-if="chargeTime.format"
  111. class="fs-28 color-333 fw-500 mr-16"
  112. >{{ chargeTime.format }}</view
  113. >
  114. <view v-else class="fs-26 mr-16" style="color: #cacaca"
  115. >请选择</view
  116. >
  117. <uni-icons type="right" size="16" color="#CACACA"></uni-icons>
  118. </block>
  119. </view>
  120. </view>
  121. <view class="pt-40 pb-40 flex-between">
  122. <view class="fs-28 color-000 fw-500">预计费用</view>
  123. <view class="flex-align-center lh-28">
  124. <block v-if="chargeTime.isPowerSaving">
  125. <view class="fs-28 color-333 fw-500"
  126. >低至{{ priceInfo.minPrice }}元/kwh</view
  127. >
  128. </block>
  129. <block v-else>
  130. <view
  131. v-if="chargeTime.formatPrice"
  132. class="fs-28 color-333 fw-500"
  133. >{{ chargeTime.formatPrice }}</view
  134. >
  135. <view v-else class="fs-26 mr-16" style="color: #cacaca"
  136. >选择时间后显示</view
  137. >
  138. </block>
  139. </view>
  140. </view>
  141. </view>
  142. <view
  143. class="mt-20 block flex-align-center pl-30 pr-30 pt-30 pb-30"
  144. @click="
  145. to(
  146. `/pages-charge/discount/discount?index=${discountIndex}${
  147. activity && activity.id ? `&id=${activity.id}` : ''
  148. }`
  149. )
  150. "
  151. >
  152. <view class="fs-28 lh-28 color-000 fw-500">优惠</view>
  153. <block v-if="discountList.length > 0">
  154. <view class="fs-28 lh-28 ml-auto" style="color: #f43636"
  155. >{{ discountList[discountIndex].discountFormat }}折</view
  156. >
  157. <uni-icons type="right" size="16" color="#CACACA"></uni-icons>
  158. </block>
  159. <block v-else-if="activity">
  160. <view class="fs-28 lh-28 ml-auto" style="color: #f43636"
  161. >{{ activity.minDiscount }}折</view
  162. >
  163. <view class="fs-28 lh-28 color-666 ml-8">权益待领取</view>
  164. <uni-icons type="right" size="16" color="#CACACA"></uni-icons>
  165. </block>
  166. <view v-else class="fs-28 lh-28 color-666 ml-auto">无</view>
  167. </view>
  168. <view
  169. class="mt-20 block flex-align-center pl-30 pr-30 pt-30 pb-30"
  170. v-if="chargeType === 0"
  171. >
  172. <view class="flex-column">
  173. <view class="fs-28 lh-28 color-000 fw-500">省钱模式</view>
  174. <view class="fs-24 lh-30 color-999 mt-8"
  175. >处于00:00-08:00时,电费低至{{ priceInfo.minPrice }}元/kwh</view
  176. >
  177. </view>
  178. <view class="ml-auto">
  179. <switch
  180. :checked="chargeTime.isPowerSaving"
  181. color="#347DFF"
  182. @change="changePowerSaving"
  183. />
  184. </view>
  185. </view>
  186. </template>
  187. <view class="pt-60 pb-80"></view>
  188. <style-bottom-view>
  189. <view class="pt-20 pl-40 pr-40 pb-20 bg-fff flex">
  190. <template v-if="appointmentData">
  191. <view class="mr-10" style="width: 50%">
  192. <style-button size="small" @click="selectTime"
  193. >修改时间</style-button
  194. ></view
  195. >
  196. <view class="ml-10" style="width: 50%">
  197. <style-button type="primary" size="small" @click="submitNow"
  198. >立即开始</style-button
  199. >
  200. </view>
  201. </template>
  202. <style-button v-else type="primary" size="small" @click="submit">{{
  203. chargeType === 0 ? "提交预约" : "马上充电"
  204. }}</style-button>
  205. </view>
  206. </style-bottom-view>
  207. </view>
  208. <style-dialog
  209. v-if="chargeTimeDialog"
  210. @close="closeTime"
  211. :title="
  212. '请选择' + (chargeTime.isPowerSaving ? '省电模式' : '') + '充电时间'
  213. "
  214. >
  215. <view class="flex" style="border-top: 1rpx solid rgba(0, 0, 0, 0.1)">
  216. <view
  217. class="flex-shrink"
  218. style="height: 840rpx; width: 256rpx; background-color: #f0f0f0"
  219. >
  220. <view
  221. class="flex-align-center pl-32 height-90"
  222. v-for="(day, index) in timesInfo.day"
  223. :key="index"
  224. :style="{
  225. backgroundColor:
  226. day.format === chargeTime.day ? '#fff' : 'transparent',
  227. }"
  228. @click="changeDay(index)"
  229. >
  230. <view
  231. :class="[
  232. 'fs-32',
  233. 'fw-500',
  234. day.format === chargeTime.day ? 'color-primary' : 'color-000',
  235. ]"
  236. >{{ day.format }}</view
  237. >
  238. <view
  239. class="fs-24 color-666 ml-12 br-8 width-60 height-40 flex-center"
  240. style="background-color: rgba(0, 0, 0, 0.07)"
  241. v-if="day.year && day.format !== chargeTime.day"
  242. >{{ day.year }}年</view
  243. >
  244. </view>
  245. </view>
  246. <scroll-view
  247. scroll-y
  248. class="flex-grow"
  249. style="height: 840rpx"
  250. :scroll-into-view="chargeTime.scrollId"
  251. >
  252. <view
  253. :id="`hour-${hour.format}`"
  254. class="flex-align-center pl-40 height-90 fs-32"
  255. v-for="(hour, index) in timesInfo.hour"
  256. :key="index"
  257. :style="{
  258. color: hour.disabled
  259. ? '#999'
  260. : hour.format === chargeTime.hour
  261. ? 'var(--color-primary)'
  262. : '#000',
  263. }"
  264. @click="changeHour(index)"
  265. >
  266. {{ hour.format }}
  267. </view>
  268. <view class="hour-placeholder"></view>
  269. </scroll-view>
  270. </view>
  271. </style-dialog>
  272. <PriceDesc
  273. v-if="priceDescVisible"
  274. :desc="priceInfo.policyInfos || []"
  275. @close="closePriceDesc"
  276. ></PriceDesc>
  277. </view>
  278. </template>
  279. <script setup lang="ts">
  280. import {
  281. fetchChargeStatus,
  282. fetchStationByConnectorIdOrShortId,
  283. fetchStationPriceDesc,
  284. startCharge,
  285. startAppointmentCharge,
  286. cancelAppointmentCharge,
  287. changeAppointmentTime,
  288. } from "@/api/charge";
  289. import { fetchProfile } from "@/api/user";
  290. import { onLoad, onShow } from "@dcloudio/uni-app";
  291. import { ref } from "vue";
  292. import ChargeMachine from "../machines/charge-machine/charge-machine.vue";
  293. import PriceDesc from "../machines/price-desc/price-desc.vue";
  294. import { format } from "@/utils/date";
  295. import { to } from "../../utils/navigate";
  296. const DAY = 24 * 60 * 60 * 1000;
  297. const options = ref<any>();
  298. const data = ref<any>();
  299. const priceInfo = ref();
  300. const priceDescVisible = ref(false);
  301. const timesInfo = ref<any>({
  302. day: [],
  303. time: [],
  304. });
  305. const chargeType = ref(1);
  306. const chargeTypes = ref([
  307. {
  308. title: "预约充电",
  309. tip: "预约特定时间点开始充电",
  310. checkTip: "部分车辆可能进入休眠状态无法唤醒,将导致充电失败",
  311. },
  312. {
  313. title: "立即充电",
  314. },
  315. ]);
  316. const chargeTimeDialog = ref(false);
  317. const chargeTime = ref({
  318. time: 0, // 时间戳
  319. day: "",
  320. hour: "",
  321. format: "",
  322. formatPrice: "",
  323. scrollId: "",
  324. isPowerSaving: false, // 省电模式
  325. });
  326. const appointmentData = ref();
  327. const appointmentCountDown = ref();
  328. const discountIndex = ref(-1);
  329. const discountList = ref<any[]>([]);
  330. const activity = ref();
  331. const changeType = (index: number) => {
  332. chargeType.value = index;
  333. };
  334. const isPassTime = (hour: string, day: number) => {
  335. const now = new Date();
  336. const time = new Date(format("y/M/d", day) + " " + hour + ":00");
  337. return now > time;
  338. };
  339. const getHourPrice = (hour: string) => {
  340. let price = "";
  341. priceInfo.value.policyInfos.forEach((item: any) => {
  342. if (Number(hour) >= Number(item.startTime.substring(0, 2))) {
  343. price = item.totalPrice;
  344. }
  345. });
  346. return price;
  347. };
  348. const rebuildHours = (day: Date) => {
  349. timesInfo.value.hour = [];
  350. const nowHour = format("h");
  351. const isTaday = format("d") === format("d", day.getTime());
  352. // 当前时间的24小时内
  353. let startHour = isTaday ? Number(nowHour) : 0;
  354. let endHour = isTaday ? 24 : Number(nowHour) + 1;
  355. if (chargeTime.value.isPowerSaving) {
  356. startHour = 0;
  357. endHour = 8;
  358. }
  359. for (let index = startHour; index < endHour; index++) {
  360. timesInfo.value.hour = [...timesInfo.value.hour, ...buildHours(index, day)];
  361. }
  362. };
  363. const buildHours = (hour: number, day: Date) => {
  364. let res: any[] = [];
  365. let hourTemp = hour >= 10 ? `${hour}` : `0${hour}`;
  366. let priceTemp = getHourPrice(hourTemp);
  367. for (let index = 0; index < 12; index++) {
  368. res.push({
  369. format: `${hourTemp}:${index * 5 >= 10 ? index * 5 : `0${index * 5}`}`,
  370. formatPrice: priceTemp,
  371. disabled: isPassTime(
  372. `${hourTemp}:${index * 5 >= 10 ? index * 5 : `0${index * 5}`}`,
  373. chargeTime.value.time ? chargeTime.value.time : day.getTime()
  374. ),
  375. });
  376. }
  377. return res;
  378. };
  379. const selectTime = () => {
  380. if (chargeTime.value.isPowerSaving) {
  381. uni.showToast({
  382. title: "省电模式将在00:00-08:00进行充电",
  383. icon: "none",
  384. });
  385. return;
  386. }
  387. if (!appointmentData.value && chargeType.value === 1) {
  388. uni.showToast({
  389. title: "请选择预约模式",
  390. icon: "none",
  391. });
  392. return;
  393. }
  394. const now = appointmentData.value
  395. ? new Date(appointmentData.value.startTime.replace(/-/g, "/"))
  396. : new Date();
  397. const year = format("y", now.getTime());
  398. const nextyear = format("y", now.getTime() + DAY);
  399. // 天
  400. timesInfo.value.day = [
  401. {
  402. time: now.getTime(),
  403. format: format("M月d日", now.getTime()),
  404. year: "",
  405. },
  406. {
  407. time: now.getTime() + DAY,
  408. format: format("M月d日", now.getTime() + DAY),
  409. year: year === nextyear ? "" : nextyear.slice(2),
  410. },
  411. ];
  412. rebuildHours(now);
  413. // 预约时间
  414. if (!appointmentData.value) {
  415. if (!chargeTime.value.day) {
  416. chargeTime.value.time = timesInfo.value.day[0].time;
  417. chargeTime.value.day = timesInfo.value.day[0].format;
  418. }
  419. // 滚动到特定位置
  420. if (chargeTime.value.hour) {
  421. chargeTime.value.scrollId = `hour-${chargeTime.value.hour}`;
  422. } else {
  423. let hourNow = now.getHours();
  424. chargeTime.value.scrollId = `hour-${hourNow}:00`;
  425. }
  426. }
  427. // 修改时间
  428. if (appointmentData.value) {
  429. chargeTime.value.time = timesInfo.value.day[0].time;
  430. chargeTime.value.day = timesInfo.value.day[0].format;
  431. const findIndex = timesInfo.value.hour.findIndex(
  432. (item: any) => item.format === format("h:m:s", now.getTime())
  433. );
  434. if (findIndex >= 0) {
  435. chargeTime.value.hour = timesInfo.value.hour[findIndex].format;
  436. chargeTime.value.formatPrice =
  437. timesInfo.value.hour[findIndex].formatPrice;
  438. }
  439. }
  440. chargeTimeDialog.value = true;
  441. };
  442. const changeDay = (index: number) => {
  443. chargeTime.value.time = timesInfo.value.day[index].time;
  444. chargeTime.value.day = timesInfo.value.day[index].format;
  445. if (chargeTime.value.hour) {
  446. chargeTime.value.hour = "";
  447. chargeTime.value.formatPrice = "";
  448. }
  449. const now = new Date(chargeTime.value.time);
  450. rebuildHours(now);
  451. setTimeout(() => {
  452. chargeTime.value.scrollId = `hour-${timesInfo.value.hour[0].format}`;
  453. }, 0);
  454. };
  455. const changeHour = (index: number) => {
  456. if (timesInfo.value.hour[index].disabled) {
  457. uni.showToast({
  458. title: "无法选择过去的时间",
  459. icon: "none",
  460. });
  461. return;
  462. }
  463. if (appointmentData.value) {
  464. // 修改时间
  465. uni.showModal({
  466. title: "温馨提示",
  467. content: `确认修改为${timesInfo.value.hour[index].format}吗?`,
  468. confirmText: "确定",
  469. confirmColor: "#347DFF",
  470. success(modal) {
  471. if (modal.confirm) {
  472. uni.showLoading({
  473. title: "提交中",
  474. mask: true,
  475. });
  476. changeAppointmentTime(
  477. appointmentData.value.startChargeSeq,
  478. `${format("y-M-d", chargeTime.value.time)} ${
  479. timesInfo.value.hour[index].format
  480. }`
  481. )
  482. .then(() => {
  483. return fetchChargeStatus();
  484. })
  485. .then((res) => {
  486. uni.hideLoading();
  487. if (res && res.isAppointment) {
  488. uni.showToast({
  489. icon: "success",
  490. title: "修改成功",
  491. });
  492. closeTime();
  493. appointmentData.value = res;
  494. startAppointmentCountDown();
  495. }
  496. });
  497. }
  498. },
  499. });
  500. return;
  501. }
  502. chargeTime.value.hour = timesInfo.value.hour[index].format;
  503. chargeTime.value.format = `${format("y年M月d日", chargeTime.value.time)} ${
  504. chargeTime.value.hour
  505. }`;
  506. chargeTime.value.formatPrice = timesInfo.value.hour[index].formatPrice;
  507. closeTime();
  508. };
  509. const changePowerSaving = (e: any) => {
  510. chargeTime.value.isPowerSaving = e.detail.value;
  511. };
  512. const closeTime = () => {
  513. chargeTimeDialog.value = false;
  514. if (appointmentData.value) {
  515. return;
  516. }
  517. if (!chargeTime.value.hour) {
  518. chargeTime.value = {
  519. time: 0, // 时间戳
  520. day: "",
  521. hour: "",
  522. isPowerSaving: chargeTime.value.isPowerSaving, // 省电模式
  523. format: "",
  524. formatPrice: "",
  525. scrollId: "",
  526. };
  527. }
  528. };
  529. const openPriceDesc = () => {
  530. priceDescVisible.value = true;
  531. };
  532. const closePriceDesc = () => {
  533. priceDescVisible.value = false;
  534. };
  535. const cancelAppointment = () => {
  536. uni.showModal({
  537. title: "取消预约",
  538. content: "确定取消预约吗?",
  539. cancelText: "取消预约",
  540. cancelColor: "#999999",
  541. confirmText: "点错了",
  542. confirmColor: "#347DFF",
  543. success: (res) => {
  544. if (res.cancel) {
  545. uni.showLoading({
  546. title: "提交中",
  547. mask: true,
  548. });
  549. cancelAppointmentCharge()
  550. .then(() => {
  551. uni.hideLoading();
  552. uni.showToast({
  553. icon: "success",
  554. title: "已取消",
  555. });
  556. appointmentData.value = undefined;
  557. startAppointmentCountDown();
  558. })
  559. .catch((err) => {
  560. uni.hideLoading();
  561. });
  562. }
  563. },
  564. });
  565. };
  566. let appointmentCountDownTimer = 0;
  567. const startAppointmentCountDown = () => {
  568. appointmentCountDownTimer && clearTimeout(appointmentCountDownTimer);
  569. if (!appointmentData.value) {
  570. appointmentCountDown.value = "";
  571. return;
  572. }
  573. appointmentCountDown.value = formatAppointmentCountDown(
  574. appointmentData.value.startTime
  575. );
  576. if (appointmentCountDown.value) {
  577. appointmentCountDownTimer = setTimeout(() => {
  578. startAppointmentCountDown();
  579. }, 1000);
  580. } else {
  581. uni.showModal({
  582. content: "当前预约时间已到,将开始进行充电",
  583. showCancel: false,
  584. success() {
  585. uni.switchTab({
  586. url: "/pages/map/map",
  587. });
  588. },
  589. });
  590. }
  591. };
  592. const formatAppointmentCountDown = (time: string) => {
  593. const now = new Date();
  594. const date = new Date(time.replace(/-/g, "/"));
  595. let secondTime = parseInt(`${(date.getTime() - now.getTime()) / 1000}`);
  596. if (secondTime <= 0) {
  597. return "";
  598. }
  599. let hourTime = 0;
  600. let minuteTime = 0; // 分
  601. if (secondTime >= 60) {
  602. minuteTime = parseInt(`${secondTime / 60}`);
  603. secondTime = parseInt(`${secondTime % 60}`);
  604. if (minuteTime >= 60) {
  605. hourTime = parseInt(`${minuteTime / 60}`);
  606. minuteTime = parseInt(`${minuteTime % 60}`);
  607. }
  608. }
  609. return `${hourTime < 10 ? "0" + hourTime : hourTime}:${
  610. minuteTime < 10 ? "0" + minuteTime : minuteTime
  611. }:${secondTime < 10 ? "0" + secondTime : secondTime}`;
  612. };
  613. const submit = () => {
  614. if (
  615. chargeType.value === 0 &&
  616. !chargeTime.value.isPowerSaving &&
  617. !chargeTime.value.hour
  618. ) {
  619. uni.showToast({
  620. title: "请选择充电时间",
  621. icon: "none",
  622. });
  623. return;
  624. }
  625. const now = new Date();
  626. let startTime = chargeTime.value.time;
  627. if (chargeTime.value.isPowerSaving) {
  628. startTime = now.getTime();
  629. // 省电模式
  630. if (
  631. now.getHours() >= 8 &&
  632. now.getDate() === Number(format("d", chargeTime.value.time))
  633. ) {
  634. startTime += DAY;
  635. }
  636. }
  637. let query = "";
  638. if (chargeType.value === 0) {
  639. query += "isBooking=true";
  640. query += `&startTime=${format("y-M-d", startTime)} ${
  641. chargeTime.value.isPowerSaving
  642. ? "00:00:00"
  643. : `${chargeTime.value.hour}:00`
  644. }`;
  645. if (chargeTime.value.isPowerSaving) {
  646. query += `&endTime=${format("y-M-d", startTime)} 08:00:00`;
  647. }
  648. }
  649. if (chargeType.value === 1) {
  650. query += "isBooking=false";
  651. }
  652. if (discountIndex.value >= 0) {
  653. query += `&rechargeRightsId=${discountList.value[discountIndex.value].id}`;
  654. }
  655. console.log(query)
  656. uni.showLoading({
  657. title: "提交中",
  658. mask: true,
  659. });
  660. startCharge(options.value.sn, query)
  661. .then(() => {
  662. if (chargeType.value === 0) {
  663. fetchChargeStatus()
  664. .then((res) => {
  665. if (res && res.isAppointment) {
  666. uni.hideLoading();
  667. uni.showToast({
  668. icon: "success",
  669. title: "预约成功",
  670. });
  671. appointmentData.value = res;
  672. startAppointmentCountDown();
  673. }
  674. })
  675. .catch(() => {
  676. uni.navigateBack();
  677. });
  678. }
  679. if (chargeType.value === 1) {
  680. uni.navigateTo({
  681. url: `/pages-charge/ordering/ordering?sn=${options.value.sn}&start=1`,
  682. });
  683. }
  684. })
  685. .catch((err) => {
  686. uni.hideLoading();
  687. uni.showModal({
  688. content: `${err.errMsg}`,
  689. showCancel: false,
  690. });
  691. });
  692. };
  693. const submitNow = () => {
  694. uni.showLoading({
  695. title: "提交中",
  696. mask: true,
  697. });
  698. startAppointmentCharge(options.value.sn)
  699. .then(() => {
  700. _checkStartCharge();
  701. })
  702. .catch((err) => {
  703. uni.hideLoading();
  704. uni.showModal({
  705. content: `${err.errMsg}`,
  706. showCancel: false,
  707. });
  708. });
  709. };
  710. const _checkStartCharge = () => {
  711. fetchChargeStatus().then((res) => {
  712. if (res && [2].includes(res.chargeStatus)) {
  713. uni.hideLoading();
  714. uni.navigateTo({
  715. url: `/pages-charge/ordering/ordering?sn=${options.value.sn}&start=1`,
  716. });
  717. } else {
  718. _checkStartCharge();
  719. }
  720. });
  721. };
  722. onLoad((_options: any) => {
  723. // sn=SN100523042860091 测试环境
  724. console.log("options", _options);
  725. let sn = _options.sn;
  726. uni.showLoading({
  727. title: "加载中",
  728. });
  729. fetchStationByConnectorIdOrShortId(sn)
  730. .then((res) => {
  731. console.log(res);
  732. if (
  733. res.equipment &&
  734. res.equipment.connectorInfos &&
  735. res.equipment.connectorInfos.length
  736. ) {
  737. sn = res.equipment.connectorInfos[0].connectorId;
  738. _options.sn = res.equipment.connectorInfos[0].connectorId;
  739. }
  740. options.value = _options;
  741. data.value = res;
  742. return fetchStationPriceDesc(sn);
  743. })
  744. .then((res) => {
  745. // console.log(res);
  746. uni.hideLoading();
  747. priceInfo.value = res;
  748. return fetchChargeStatus(false, true);
  749. })
  750. .then((res) => {
  751. if (res && res.isAppointment) {
  752. appointmentData.value = res;
  753. startAppointmentCountDown();
  754. }
  755. })
  756. .catch((err) => {
  757. console.log(err);
  758. uni.hideLoading();
  759. });
  760. fetchProfile().then((res) => {
  761. if (res.userRechargeRightsList.length) {
  762. res.userRechargeRightsList.forEach((item: any) => {
  763. item.discountFormat = Number((Number(item.discount) / 10).toFixed(2));
  764. });
  765. discountList.value = res.userRechargeRightsList;
  766. discountIndex.value = 0;
  767. }
  768. if (res.activityList && res.activityList.length) {
  769. res.activityList[0].rechargeRightsList.sort((a: any, b: any) => {
  770. return a.discount - b.discount;
  771. });
  772. activity.value = res.activityList[0];
  773. activity.value.minDiscount = Number(
  774. (
  775. Number(res.activityList[0].rechargeRightsList[0].discount) / 10
  776. ).toFixed(2)
  777. );
  778. }
  779. });
  780. });
  781. onShow(() => {
  782. if (getApp<any>().globalData.lastData.discount) {
  783. discountIndex.value = getApp<any>().globalData.lastData.discount.index;
  784. getApp<any>().globalData.lastData.discount = undefined;
  785. }
  786. });
  787. </script>
  788. <style lang="scss" scoped>
  789. .page {
  790. min-height: 100vh;
  791. width: 100%;
  792. padding: 20rpx;
  793. background-color: #f6f7fa;
  794. }
  795. .block {
  796. border-radius: 20rpx;
  797. background: #fff;
  798. }
  799. .station {
  800. height: 148rpx;
  801. border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
  802. }
  803. .hour-placeholder {
  804. box-sizing: content-box;
  805. padding-bottom: constant(safe-area-inset-bottom);
  806. padding-bottom: env(safe-area-inset-bottom);
  807. }
  808. </style>