Quellcode durchsuchen

feat:新增更多页面

needcode vor 2 Jahren
Ursprung
Commit
d3d1e24c7e

+ 9 - 0
src/App.vue

@@ -8,6 +8,11 @@ export default <any>{
     normalCode: "",
   },
   onLaunch() {
+    uni.getSystemInfo({
+      success: (res) => {
+        this.globalData.device = res;
+      },
+    });
     return fetchToken().then((cache) => {
       if (cache) {
         this.globalData.token = cache;
@@ -34,6 +39,10 @@ view {
   --color-sec: #f7f7f7;
 }
 
+.box-content {
+  box-sizing: content-box;
+}
+
 image {
   width: 20rpx;
   height: 20rpx;

+ 53 - 0
src/components/style-result/style-result.vue

@@ -0,0 +1,53 @@
+<template>
+  <view class="style-result">
+    <image class="style-result_icon" :src="icon" v-if="icon" mode="widthFix"></image>
+    <view class="style-result_title">{{ title }}</view>
+    <view class="style-result_tip" v-if="tip">{{ tip }}</view>
+    <slot></slot>
+  </view>
+</template>
+
+<script lang="ts">
+export default {
+  props: {
+    icon: String,
+    title: String,
+    tip: String,
+    btn: String,
+  },
+};
+</script>
+
+<style lang="scss">
+.style-result {
+  position: fixed;
+  width: 100vw;
+  height: 100vh;
+  left: 0;
+  top: 0;
+  z-index: 99999;
+  background-color: #fff;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  flex-direction: column;
+  &_icon {
+    width: 324rpx;
+  }
+  &_title {
+    color: #000;
+    text-align: center;
+    font-size: 30rpx;
+    font-weight: 500;
+    line-height: normal;
+  }
+  &_tip {
+    width: 370rpx;
+    margin-top: 16rpx;
+    color: rgba(0, 0, 0, 0.6);
+    text-align: center;
+    font-size: 26rpx;
+    font-weight: 400;
+  }
+}
+</style>

+ 1 - 36
src/custom-tab-bar/index.js

@@ -1,11 +1,8 @@
 import { fetchToken, login, onLogin } from "../api/auth";
-import { fetchChargeStatus } from "../api/charge";
-import { scanCode } from "../utils/code";
 
 Component({
   data: {
     hidden: false,
-    dialog: false,
     tabIndex: -1,
     tabs: [
       {
@@ -13,7 +10,7 @@ Component({
         text: "充电地图",
       },
       {
-        path: "",
+        path: "/pages-charge/camera/camera",
         text: "扫码充电",
       },
       {
@@ -25,7 +22,6 @@ Component({
         text: "个人中心",
       },
     ],
-    charging: "",
   },
   lifetimes: {
     ready() {
@@ -51,24 +47,11 @@ Component({
   },
   methods: {
     switchTab(e) {
-      fetchChargeStatus().then(res => {
-        this.setData({
-          charging: [1, 2].includes(res.chargeStatus) ? res.connectorId : ''
-        })
-      }).catch(() => {
-        this.setData({
-          charging: ''
-        })
-      })
       const data = e.currentTarget.dataset;
       const url = data.path;
       if (!url) {
-        this.switchDialog();
         return;
       }
-      this.setData({
-        dialog: false,
-      });
       wx.vibrateShort &&
         wx.vibrateShort({
           type: "light",
@@ -77,11 +60,6 @@ Component({
         url,
       });
     },
-    switchDialog() {
-      this.setData({
-        dialog: !this.data.dialog,
-      });
-    },
     hiddenTab() {
       this.setData({
         hidden: true,
@@ -95,18 +73,5 @@ Component({
     login(e) {
       login(e);
     },
-    scanCode() {
-      scanCode()
-    },
-    inputCode() {
-      wx.navigateTo({
-        url: "/pages-charge/codeing/codeing",
-      });
-    },
-    toCharging() {
-      wx.navigateTo({
-        url: `/pages-charge/ordering/ordering?sn=${this.data.charging}&start=1`,
-      });
-    },
   },
 });

+ 0 - 17
src/custom-tab-bar/index.wxml

@@ -16,20 +16,3 @@
   </view>
   <button class="tab-bar-login" wx:if="{{!token}}" style="width: 100vw;height: var(--tab-bar-height);border: none;" open-type="getPhoneNumber" bindgetphonenumber="login"></button>
 </view>
-
-<view class="tab-bar-charge" style="height: {{dialog ? '100vh':'0px'}};" bindtap="switchDialog">
-  <view style="padding-left: {{charging ? '92' : '112'}}rpx;">
-    <view class="tab-bar-charge_menu" catchtouchend="scanCode" style="margin-right: {{charging ? '100' : '140'}}rpx;">
-      <image class="tab-bar-charge_menu--icon" src="/static/images/custom-tab-bar/2-2.png" mode="widthFix" />
-      <view class="tab-bar-charge_menu--text">扫二维码</view>
-    </view>
-    <view class="tab-bar-charge_menu" catchtouchend="inputCode" style="margin-right: {{charging ? '100' : '140'}}rpx;">
-      <image class="tab-bar-charge_menu--icon" src="/static/images/custom-tab-bar/2-3.png" mode="widthFix" />
-      <view class="tab-bar-charge_menu--text">输入编码</view>
-    </view>
-    <view class="tab-bar-charge_menu" catchtouchend="toCharging" wx:if="{{charging}}">
-      <image class="tab-bar-charge_menu--icon" src="/static/images/custom-tab-bar/2-4.png" mode="widthFix" />
-      <view class="tab-bar-charge_menu--text">充电中</view>
-    </view>
-  </view>
-</view>

+ 7 - 0
src/pages-charge/appointment/appointment.vue

@@ -0,0 +1,7 @@
+<template>
+  <view class="list"> </view>
+</template>
+
+<script setup lang="ts"></script>
+
+<style></style>

+ 7 - 0
src/pages-charge/camera/camera.vue

@@ -0,0 +1,7 @@
+<template>
+  <view class="list"> </view>
+</template>
+
+<script setup lang="ts"></script>
+
+<style></style>

+ 1 - 1
src/pages-charge/codeing/codeing.vue

@@ -44,7 +44,7 @@ const submit = () => {
     return;
   }
   uni.navigateTo({
-    url: `/pages-charge/ordering/ordering?sn=${value.value}`,
+    url: `/pages-charge/appointment/appointment?sn=${value.value}`,
   });
 };
 const input = (e: any) => {

+ 20 - 8
src/pages-charge/machines/charge-machine/charge-machine.vue

@@ -5,13 +5,25 @@
     :key="index"
     @click="toOrdering(index)"
   >
-    <view
-      :class="[
-        'charge-point_icon',
-        `charge-point_icon-${item.connectorStatusInfo.status}`,
-      ]"
-    >
-      <!-- TODO 图标 -->
+    <view :class="['charge-point_icon']">
+      <image
+        style="width: 100%"
+        v-if="item.connectorStatusInfo.status === 1"
+        src="/pages-charge/static/icon-status-1.png"
+        mode="widthFix"
+      ></image>
+      <image
+        style="width: 100%"
+        v-else-if="item.connectorStatusInfo.status === 0 || item.connectorStatusInfo.status === 255"
+        src="/pages-charge/static/icon-status-3.png"
+        mode="widthFix"
+      ></image>
+      <image
+        style="width: 100%"
+        v-else
+        src="/pages-charge/static/icon-status-2.png"
+        mode="widthFix"
+      ></image>
     </view>
     <view class="charge-point_title ml-16">
       <view class="flex-align-center">
@@ -88,7 +100,7 @@ export default {
           success: (res) => {
             if (res.tapIndex === 0) {
               uni.navigateTo({
-                url: `/pages-charge/ordering/ordering?sn=${list[index].connectorId}`,
+                url: `/pages-charge/appointment/appointment?sn=${list[index].connectorId}`,
               });
             }
           },

BIN
src/pages-charge/static/icon-status-1.png


BIN
src/pages-charge/static/icon-status-2.png


BIN
src/pages-charge/static/icon-status-3.png


BIN
src/pages-user/static/icon-submit-success.png


BIN
src/pages-user/static/wallet-banner.png


+ 0 - 142
src/pages-user/wallet-detail/wallet-detail.vue

@@ -1,142 +0,0 @@
-<template>
-  <view class="tabs flex-align-center">
-    <view
-      v-for="(item, index) in types"
-      :key="index"
-      class="fs-30 mr-60"
-      :style="{
-        color:
-          type === item.value ? 'rgba(0, 0, 0, 1);' : 'rgba(0, 0, 0, 0.6);',
-      }"
-      @click="changeType(index)"
-      >{{ item.label
-      }}<view
-        :style="{ opacity: type === item.value ? '1' : '0' }"
-        class="active"
-      ></view
-    ></view>
-  </view>
-
-  <view
-    class="pl-30 pr-30"
-    v-if="infiniteScroller.list && infiniteScroller.list.length"
-  >
-    <view
-      class="item flex-align-center"
-      v-for="(item, index) in infiniteScroller.list"
-      :key="index"
-      @click="detail(index)"
-    >
-      <view>
-        <view class="fs-30 fw-500" key="title" duration="300">{{
-          typesMap[item.type - 1]
-        }}</view>
-        <view class="fs-24" style="color: rgba(0, 0, 0, 0.4)">余额</view>
-      </view>
-      <view class="ml-auto" style="text-align: right">
-        <view class="fs-30 fw-500">
-          <text>{{ item.type > 1 ? "- " : "" }}{{ item.amount }}</text>
-          <text class="fs-24 ml-6">元</text>
-        </view>
-        <view class="fs-24" style="color: rgba(0, 0, 0, 0.4)">{{
-          item.transactionTime
-        }}</view>
-      </view>
-      <view class="ml-32" v-if="item.type === 3">
-        <uni-icons type="right" size="12" color="rgba(0,0,0,0.4)"></uni-icons>
-      </view>
-    </view>
-  </view>
-
-  <view
-    class="pt-40 flex-center fs-30"
-    style="color: rgba(0, 0, 0, 0.6)"
-    v-if="infiniteScroller.list && infiniteScroller.list.length <= 0"
-    >暂无数据</view
-  >
-</template>
-
-<script setup lang="ts">
-import { useInfiniteScroll } from "../../utils/infinite-scroll";
-import { onLoad, onPullDownRefresh, onReachBottom } from "@dcloudio/uni-app";
-import { ref } from "vue";
-import { fetchWallet } from "../../api/user";
-const type = ref(0);
-const types = ref([
-  {
-    label: "全部",
-    value: 0,
-  },
-  {
-    label: "充值",
-    value: 1,
-  },
-  {
-    label: "消费",
-    value: 3,
-  },
-]);
-const typesMap = ref(["充值", "提现", "消费"]);
-const infiniteScroller = useInfiniteScroll(10, (page) => {
-  return fetchWallet(type.value, page, 10).then((res: any) => {
-    if (res && res.length) {
-      res.forEach((item: any) => {
-        item.amount = (Number(item.amount) / 100).toFixed(2);
-      });
-    }
-    return res;
-  });
-});
-const changeType = (index: number) => {
-  type.value = types.value[index].value;
-  infiniteScroller.refresh();
-};
-const detail = (index: number) => {
-  if (!infiniteScroller.list) {
-    return;
-  }
-  if (infiniteScroller.list[index].type === 3) {
-    uni.navigateTo({
-      url: `/pages-charge/order/order?id=${infiniteScroller.list[index].orderNo}`,
-    });
-  }
-};
-onLoad(() => {
-  infiniteScroller.refresh();
-});
-onReachBottom(() => {
-  infiniteScroller.next();
-});
-onPullDownRefresh(() => {
-  infiniteScroller.refresh();
-});
-</script>
-
-<style lang="scss">
-.tabs {
-  height: 92rpx;
-  padding: 0 40rpx;
-  & > view {
-    position: relative;
-    height: 62rpx;
-    .active {
-      position: absolute;
-      left: 50%;
-      bottom: 0px;
-      transform: translateX(-50%);
-      width: 40rpx;
-      height: 4rpx;
-      border-radius: 4rpx;
-      background-color: var(--color-primary);
-    }
-  }
-}
-
-.item {
-  height: 170rpx;
-  border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
-  &:last-child {
-    border-bottom: none;
-  }
-}
-</style>

+ 191 - 0
src/pages-user/wallet-recharge/wallet-recharge.vue

@@ -0,0 +1,191 @@
+<template>
+  <view class="pl-30 pr-30">
+    <view class="wallet">
+      <image
+        src="/static/images/wallet-logo.png"
+        mode="widthFix"
+        class="image"
+      />
+      <view class="tag flex-center" @click="detail">
+        <view class="fs-26" style="color: #fff; line-height: 58rpx"
+          >钱包明细</view
+        >
+        <view style="margin-top: -8rpx; margin-left: 6rpx">
+          <uni-icons type="right" size="10" color="#FFFFFF"></uni-icons>
+        </view>
+      </view>
+      <view class="label">钱包余额</view>
+      <view class="value mt-16">
+        <text class="fs-40 lh-48 fw-500 mr-12">¥</text>
+        <text class="fw-500" style="font-size: 60rpx; line-height: 72rpx">{{
+          balance
+        }}</text>
+      </view>
+    </view>
+    <view class="pay">
+      <view class="title">充值金额</view>
+      <view class="flex-wrap">
+        <view
+          :class="[
+            'option',
+            'flex-center',
+            `option-${index === payOption && !payValue ? 'active' : ''}`,
+          ]"
+          v-for="(item, index) in payOptions"
+          :key="index"
+          @click="changeOption(index)"
+        >
+          {{ item }}
+        </view>
+      </view>
+      <view class="title">自定义金额</view>
+      <style-input
+        :value="payValue > 0 ? payValue : ''"
+        title="金额"
+        type="digit"
+        @input="input"
+      />
+    </view>
+  </view>
+
+  <style-bottom-view>
+    <view class="pl-30 pr-30 pb-20">
+      <style-button type="primary" @click="confirm">充值</style-button>
+    </view>
+  </style-bottom-view>
+</template>
+
+<script setup lang="ts">
+import { ref } from "vue";
+import { fetchProfile, insertMoney } from "../../api/user";
+import { onLoad } from "@dcloudio/uni-app";
+const balance = ref(0);
+const payOption = ref(1);
+const payOptions = ref([50, 100, 200, 500, 1000]);
+const payValue = ref(0);
+const input = (e: any) => {
+  payValue.value = e.value;
+};
+const changeOption = (index: number) => {
+  payValue.value = 0;
+  payOption.value = index;
+};
+const detail = () => {
+  uni.navigateTo({
+    url: "/pages-user/wallet/wallet",
+  });
+};
+const confirm = () => {
+  if (payValue.value && !/^[0-9]*(\.\d{1,2})?$/.test(`${payValue.value}`)) {
+    uni.showModal({
+      title: "温馨提示",
+      content: "请输入正确的金额",
+      showCancel: false,
+      confirmColor: "#347DFF",
+    });
+    return;
+  }
+  const params = payValue.value
+    ? Number(payValue.value)
+    : payOptions.value[payOption.value];
+  if (params > 10000 || params <= 0) {
+    uni.showModal({
+      title: "温馨提示",
+      content: "每次最大充值金额10000,请修改金额",
+      showCancel: false,
+      confirmColor: "#347DFF",
+    });
+    return;
+  }
+  insertMoney(params)
+    .then(() => {
+      uni.showToast({
+        title: "已支付",
+        icon: "success",
+      });
+      fetchProfile().then((res) => {
+        payValue.value = 0;
+        balance.value = Number((Number(res.balance) / 100).toFixed(2))
+      });
+    })
+    .catch((err) => {
+      if (/cancel/.test(err.errMsg)) {
+        return;
+      }
+      uni.showModal({
+        content: `${err.errMsg},请重试`,
+      });
+    });
+};
+onLoad(() => {
+  const user = getApp<any>().globalData.user;
+  if (user) {
+    balance.value = user.balance;
+  }
+});
+</script>
+
+<style lang="scss">
+.wallet {
+  height: 220rpx;
+  background: linear-gradient(180deg, #347dff 0%, #4faaff 100%);
+  box-shadow: 0px 12rpx 22rpx rgba(13, 21, 62, 0.1);
+  border-radius: 40rpx;
+  position: relative;
+  margin-top: 100rpx;
+  padding: 44rpx 40rpx;
+
+  .image {
+    position: absolute;
+    width: 148rpx;
+    right: 40rpx;
+    top: -60rpx;
+  }
+
+  .label {
+    font-size: 26rpx;
+    color: rgba(255, 255, 255, 0.8);
+  }
+
+  .value {
+    color: #fff;
+  }
+
+  .tag {
+    position: absolute;
+    width: 170rpx;
+    height: 58rpx;
+    right: 0;
+    bottom: 0;
+    background: var(--color-primary);
+    border-radius: 29rpx 0 29rpx 0;
+  }
+}
+
+.pay {
+  padding-top: 20rpx;
+  .title {
+    font-weight: 500;
+    font-size: 32rpx;
+    color: #000;
+    padding-bottom: 30rpx;
+    padding-top: 40rpx;
+  }
+
+  .option {
+    width: 214rpx;
+    height: 82rpx;
+    background: var(--color-sec);
+    border-radius: 10rpx;
+    margin-left: 20rpx;
+    margin-bottom: 20rpx;
+    &:nth-child(3n + 1) {
+      margin-left: 0;
+    }
+  }
+  .option-active {
+    background-color: var(--color-primary);
+    color: #fff;
+  }
+}
+</style>

+ 151 - 0
src/pages-user/wallet-refund/wallet-refund.vue

@@ -0,0 +1,151 @@
+<template>
+  <view class="page">
+    <navigation-bar title="退款"></navigation-bar>
+    <view class="block">
+      <view class="fs-28 color-000 fw-500">退款金额</view>
+      <view
+        class="pt-24 pb-24 box-content flex-inline"
+        style="border-bottom: 1rpx solid rgba(0, 0, 0, 0.1)"
+      >
+        <text style="font-size: 32px; line-height: 32px">¥</text>
+        <input
+          style="height: 46px; font-size: 46px; line-height: 46px"
+          class="fw-600 color-000 ml-18"
+          :value="value"
+        />
+      </view>
+      <view class="height-94 flex-align-center">
+        <view class="fs-28 color-999"
+          >当前余额 {{ user ? user.balance : 0 }} 元,</view
+        >
+        <view class="fs-28 color-primary" @click="allRefund">全部提现</view>
+      </view>
+    </view>
+    <view class="block mt-16">
+      <view class="fs-28 color-000 fw-500 pb-8">退款原因</view>
+      <view class="pb-40 flex-wrap">
+        <view
+          :class="[
+            'reason',
+            'mt-16',
+            'mr-20',
+            'fs-26',
+            reason === i ? 'reason-active' : '',
+          ]"
+          v-for="(r, i) in reasons"
+          :key="i"
+          @click="changeReason(i)"
+          >{{ r }}</view
+        >
+      </view>
+    </view>
+    <view class="block mt-16 relative">
+      <view class="fs-28 color-000 fw-500 pb-16">退款说明</view>
+      <view class="pb-40 reason-text">
+        <textarea
+          class="fs-28"
+          style="height: 100%"
+          placeholder="请您详细填写申请说明"
+          maxlength="200"
+          @input="inputReasonText"
+        ></textarea>
+      </view>
+      <view class="reason-text-length lh-28 fs-28 color-999"
+        >{{ reasonText.length }}/200</view
+      >
+    </view>
+    <style-bottom-view>
+      <view class="pl-40 pr-40 pb-30 pt-30" style="background-color: #fff">
+        <style-button type="primary" @click="submit">提交申请</style-button>
+      </view>
+    </style-bottom-view>
+    <style-result
+      v-if="success"
+      icon="/pages-user/static/icon-submit-success.png"
+      title="提交成功"
+      tip="预计需要5个工作日内审核完成请及时查收"
+    >
+      <view class="pt-64" style="width: 280rpx">
+        <style-button height="80" type="primary" @click="close"
+          >完成</style-button
+        >
+      </view>
+    </style-result>
+  </view>
+</template>
+
+<script setup lang="ts">
+import { onLoad } from "@dcloudio/uni-app";
+import { ref } from "vue";
+
+const user = ref();
+const value = ref(0);
+const reasonText = ref("");
+const reason = ref(-1);
+const reasons = ref([
+  "不常住该小区",
+  "充电故障",
+  "下次使用再充值",
+  "充电费用贵",
+  "很难充上电",
+  "其他原因",
+]);
+const success = ref(false);
+onLoad(() => {
+  if (getApp<any>().globalData.user) {
+    user.value = getApp<any>().globalData.user;
+  }
+});
+
+const allRefund = () => {
+  if (user.value) {
+    value.value = Number(user.value.balance);
+  }
+};
+const changeReason = (i: number) => {
+  reason.value = i;
+};
+const inputReasonText = (e: any) => {
+  reasonText.value = e.detail.value;
+};
+const submit = () => {
+  success.value = true;
+};
+const close = () => {
+  success.value = false;
+  uni.navigateBack();
+};
+</script>
+
+<style lang="scss">
+.page {
+  height: 100vh;
+  background-color: #f6f7fa;
+  padding: 20rpx;
+  .block {
+    border-radius: 24rpx;
+    background: #fff;
+    padding: 40rpx 40rpx 0px 40rpx;
+  }
+  .reason {
+    color: #666;
+    background-color: #f7f7f7;
+    border-radius: 4rpx;
+    padding: 12rpx 16rpx;
+    border: 1px solid #f7f7f7;
+  }
+  .reason-active {
+    color: var(--color-primary);
+    border: 1px solid var(--color-primary);
+    background: rgba(52, 125, 255, 0.1);
+  }
+  .reason-text {
+    height: 224rpx;
+  }
+  .reason-text-length {
+    position: absolute;
+    top: 40rpx;
+    right: 40rpx;
+  }
+}
+</style>

+ 211 - 161
src/pages-user/wallet/wallet.vue

@@ -1,191 +1,241 @@
 <template>
-  <view class="pl-30 pr-30">
-    <view class="wallet">
-      <image
-        src="/static/images/wallet-logo.png"
-        mode="widthFix"
-        class="image"
-      />
-      <view class="tag flex-center" @click="detail">
-        <view class="fs-26" style="color: #fff; line-height: 58rpx"
-          >钱包明细</view
-        >
-        <view style="margin-top: -8rpx; margin-left: 6rpx">
-          <uni-icons type="right" size="10" color="#FFFFFF"></uni-icons>
+  <view class="page flex-column">
+    <navigation-bar title="我的钱包" @ready="ready"></navigation-bar>
+    <view class="head flex-shrink">
+      <view>
+        <image class="bg" src="/pages-user/static/wallet-banner.png"></image>
+        <view class="fg pt-48 pl-48 pr-48">
+          <view class="flex-align-center">
+            <uni-icons
+              type="wallet-filled"
+              size="24"
+              color="#ffffff"
+            ></uni-icons>
+            <view class="fs-36 color-fff fw-500 ml-16">我的钱包</view>
+            <view class="btn flex-center fs-28 ml-auto" @click="toRefund">退款</view>
+          </view>
+          <view class="price mt-50" v-if="user">
+            <text class="color-fff fw-600 fs-48" style="vertical-align: top"
+              >¥</text
+            >
+            <text
+              class="color-fff fw-600 ml-12"
+              style="font-size: 46px; line-height: 46px"
+              >{{ user.balance }}</text
+            >
+          </view>
         </view>
       </view>
-      <view class="label">钱包余额</view>
-      <view class="value mt-16">
-        <text class="fs-40 lh-48 fw-500 mr-12">¥</text>
-        <text class="fw-500" style="font-size: 60rpx; line-height: 72rpx">{{
-          balance
-        }}</text>
-      </view>
     </view>
-    <view class="pay">
-      <view class="title">充值金额</view>
-      <view class="flex-wrap">
+    <view class="body flex-grow flex-column">
+      <view class="tabs flex-shrink flex-align-center">
         <view
-          :class="[
-            'option',
-            'flex-center',
-            `option-${index === payOption && !payValue ? 'active' : ''}`,
-          ]"
-          v-for="(item, index) in payOptions"
+          v-for="(item, index) in tabs"
           :key="index"
-          @click="changeOption(index)"
+          class="flex-align-center fs-30 mr-60"
+          :style="{
+            color:
+              tab === item.value ? 'rgba(0, 0, 0, 1);' : 'rgba(0, 0, 0, 0.6);',
+          }"
+          @click="changeTab(index)"
+          >{{ item.label
+          }}<view
+            :style="{ opacity: tab === item.value ? '1' : '0' }"
+            class="active"
+          ></view
+        ></view>
+      </view>
+      <view class="list flex-grow">
+        <scroll-view
+          class="scroll-view"
+          :style="{
+            height: `${scrollViewHeight}px`,
+          }"
+          scroll-y="true"
+          v-if="scrollViewHeight"
         >
-          {{ item }}
-        </view>
+          <view
+            class="item flex-align-center"
+            v-for="(item, index) in list"
+            :key="index"
+            @click="detail(index)"
+          >
+            <view>
+              <view class="fs-30 fw-500" key="title" duration="300">{{
+                typeMap[item.type - 1]
+              }}</view>
+              <view class="fs-24" style="color: rgba(0, 0, 0, 0.4)">余额</view>
+            </view>
+            <view class="ml-auto" style="text-align: right">
+              <view class="fs-30 fw-500">
+                <text>{{ item.type > 1 ? "- " : "" }}{{ item.amount }}</text>
+                <text class="fs-24 ml-6">元</text>
+              </view>
+              <view class="fs-24" style="color: rgba(0, 0, 0, 0.4)">{{
+                item.transactionTime
+              }}</view>
+            </view>
+            <view class="ml-32" v-if="item.type === 3">
+              <uni-icons
+                type="right"
+                size="12"
+                color="rgba(0,0,0,0.4)"
+              ></uni-icons>
+            </view>
+          </view>
+          <view style="height: 200rpx"></view>
+        </scroll-view>
       </view>
-      <view class="title">自定义金额</view>
-      <style-input
-        :value="payValue > 0 ? payValue : ''"
-        title="金额"
-        type="digit"
-        @input="input"
-      />
     </view>
   </view>
-
-  <style-bottom-view>
-    <view class="pl-30 pr-30 pb-20">
-      <style-button type="primary" @click="confirm">充值</style-button>
-    </view>
-  </style-bottom-view>
 </template>
 
 <script setup lang="ts">
-import { ref } from "vue";
-import { fetchProfile, insertMoney } from "../../api/user";
 import { onLoad } from "@dcloudio/uni-app";
-const balance = ref(0);
-const payOption = ref(1);
-const payOptions = ref([50, 100, 200, 500, 1000]);
-const payValue = ref(0);
-const input = (e: any) => {
-  payValue.value = e.value;
-};
-const changeOption = (index: number) => {
-  payValue.value = 0;
-  payOption.value = index;
-};
-const detail = () => {
-  uni.navigateTo({
-    url: "/pages-user/wallet-detail/wallet-detail",
-  });
-};
-const confirm = () => {
-  if (payValue.value && !/^[0-9]*(\.\d{1,2})?$/.test(`${payValue.value}`)) {
-    uni.showModal({
-      title: "温馨提示",
-      content: "请输入正确的金额",
-      showCancel: false,
-      confirmColor: "#347DFF",
-    });
-    return;
-  }
-  const params = payValue.value
-    ? Number(payValue.value)
-    : payOptions.value[payOption.value];
-  if (params > 10000 || params <= 0) {
-    uni.showModal({
-      title: "温馨提示",
-      content: "每次最大充值金额10000,请修改金额",
-      showCancel: false,
-      confirmColor: "#347DFF",
-    });
-    return;
-  }
-  insertMoney(params)
-    .then(() => {
-      uni.showToast({
-        title: "已支付",
-        icon: "success",
-      });
-      fetchProfile().then((res) => {
-        payValue.value = 0;
-        balance.value = Number((Number(res.balance) / 100).toFixed(2))
-      });
-    })
-    .catch((err) => {
-      if (/cancel/.test(err.errMsg)) {
-        return;
-      }
-      uni.showModal({
-        content: `${err.errMsg},请重试`,
-      });
-    });
-};
+import { fetchWallet } from "../../api/user";
+import { ref } from "vue";
+import { rpxToPx } from "@/utils/device";
+
+const user = ref();
+
+const tab = ref(0);
+const tabs = ref([
+  {
+    label: "全部",
+    value: 0,
+  },
+  {
+    label: "充值",
+    value: 1,
+  },
+  {
+    label: "消费",
+    value: 3,
+  },
+  {
+    label: "退款", // TODO
+    value: 2,
+  },
+]);
+
+const typeMap = ref(["充值", "提现", "消费"]);
+const list = ref<any[]>([]);
+const scrollViewHeight = ref(0);
+
 onLoad(() => {
-  const user = getApp<any>().globalData.user;
-  if (user) {
-    balance.value = user.balance;
+  refresh();
+
+  if (getApp<any>().globalData.user) {
+    user.value = getApp<any>().globalData.user;
   }
 });
-</script>
 
-<style lang="scss">
-.wallet {
-  height: 220rpx;
-  background: linear-gradient(180deg, #347dff 0%, #4faaff 100%);
-  box-shadow: 0px 12rpx 22rpx rgba(13, 21, 62, 0.1);
-  border-radius: 40rpx;
-  position: relative;
-  margin-top: 100rpx;
-  padding: 44rpx 40rpx;
+const ready = (e: any) => {
+  scrollViewHeight.value =
+    getApp<any>().globalData.device.windowHeight -
+    (e.detail.navigationBarHeight + rpxToPx(380));
+};
 
-  .image {
-    position: absolute;
-    width: 148rpx;
-    right: 40rpx;
-    top: -60rpx;
-  }
+const changeTab = (index: number) => {
+  tab.value = tabs.value[index].value;
+  refresh();
+};
 
-  .label {
-    font-size: 26rpx;
-    color: rgba(255, 255, 255, 0.8);
-  }
+const refresh = () => {
+  fetchWallet(tab.value, 1, 10).then((res: any) => {
+    if (res && res.length) {
+      res.forEach((item: any) => {
+        item.amount = (Number(item.amount) / 100).toFixed(2);
+      });
+    }
+    list.value = res;
+  });
+};
 
-  .value {
-    color: #fff;
+const detail = (index: number) => {
+  if (list.value[index].type === 3) {
+    uni.navigateTo({
+      url: `/pages-charge/order/order?id=${list.value[index].orderNo}`,
+    });
   }
+};
 
-  .tag {
-    position: absolute;
-    width: 170rpx;
-    height: 58rpx;
-    right: 0;
-    bottom: 0;
-    background: var(--color-primary);
-    border-radius: 29rpx 0 29rpx 0;
-  }
+const toRefund = () => {
+  uni.navigateTo({
+    url: `/pages-user/wallet-refund/wallet-refund`,
+  });
 }
+</script>
 
-.pay {
-  padding-top: 20rpx;
-  .title {
-    font-weight: 500;
-    font-size: 32rpx;
-    color: #000;
-    padding-bottom: 30rpx;
-    padding-top: 40rpx;
-  }
-
-  .option {
-    width: 214rpx;
-    height: 82rpx;
-    background: var(--color-sec);
-    border-radius: 10rpx;
-    margin-left: 20rpx;
-    margin-bottom: 20rpx;
-    &:nth-child(3n + 1) {
-      margin-left: 0;
+<style lang="scss">
+.page {
+  height: 100vh;
+  width: 100vw;
+  background: linear-gradient(
+    180deg,
+    #e0ebff 0%,
+    rgba(255, 255, 255, 0) 60.13%
+  );
+  .head {
+    padding: 30rpx 40rpx;
+    & > view {
+      position: relative;
+      height: 320rpx;
+      border-radius: 40rpx;
+      overflow: hidden;
+      .bg {
+        height: 100%;
+        width: 100%;
+      }
+      .fg {
+        position: absolute;
+        left: 0px;
+        top: 0px;
+        height: 100%;
+        width: 100%;
+        .btn {
+          width: 120rpx;
+          height: 64rpx;
+          border-radius: 40rpx;
+          background: rgba(255, 255, 255, 0.3);
+          color: #076370;
+        }
+      }
     }
   }
-  .option-active {
-    background-color: var(--color-primary);
-    color: #fff;
+  .body {
+    .tabs {
+      padding: 0 40rpx;
+      & > view {
+        position: relative;
+        height: 72rpx;
+        .active {
+          position: absolute;
+          left: 50%;
+          bottom: 0px;
+          transform: translateX(-50%);
+          width: 40rpx;
+          height: 4rpx;
+          border-radius: 4rpx;
+          background-color: var(--color-primary);
+        }
+      }
+    }
+    .list {
+      height: 100%;
+      .scroll-view {
+        width: 100%;
+        box-sizing: border-box;
+        padding: 0rpx 30rpx;
+      }
+      .item {
+        height: 170rpx;
+        border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
+        &:last-child {
+          border-bottom: none;
+        }
+      }
+    }
   }
 }
 </style>

+ 18 - 5
src/pages.json

@@ -61,6 +61,17 @@
         },
         {
           "path": "search/search"
+        },
+        {
+          "path": "appointment/appointment",
+          "style": {
+            "navigationBarTitleText": "预约充电",
+            "navigationStyle": "default",
+            "navigationBarBackgroundColor": "#F6F7FA"
+          }
+        },
+        {
+          "path": "camera/camera"
         }
       ]
     },
@@ -90,17 +101,19 @@
           }
         },
         {
-          "path": "wallet/wallet",
+          "path": "wallet/wallet"
+        },
+        {
+          "path": "wallet-refund/wallet-refund",
           "style": {
-            "navigationStyle": "default",
-            "navigationBarTitleText": "我的钱包"
+            "disableScroll": true
           }
         },
         {
-          "path": "wallet-detail/wallet-detail",
+          "path": "wallet-recharge/wallet-recharge",
           "style": {
             "navigationStyle": "default",
-            "navigationBarTitleText": "钱包明细",
+            "navigationBarTitleText": "我的钱包",
             "enablePullDownRefresh": true
           }
         }

+ 4 - 0
src/styles/flex.scss

@@ -98,4 +98,8 @@
 
 .flex-shrink {
   flex-shrink: 0;
+}
+
+.flex-inline {
+  display: inline-flex;
 }

+ 1 - 1
src/utils/code.ts

@@ -22,7 +22,7 @@ export function deCode(url: string) {
     const split = url.split("/");
     const sn = split[split.length - 1].replace("#", "");
     uni.navigateTo({
-      url: `/pages-charge/ordering/ordering?sn=${sn}`,
+      url: `/pages-charge/appointment/appointment?sn=${sn}`,
     });
   } else {
     uni.showModal({

+ 13 - 0
src/utils/device.ts

@@ -0,0 +1,13 @@
+export function rpxToPx(rpx: number): number {
+  if (getApp<any>().globalData.device) {
+    return (rpx * getApp<any>().globalData.device.windowWidth) / 750;
+  }
+  return rpx;
+}
+
+export function pxToRpx(px: number): number {
+  if (getApp<any>().globalData.device) {
+    return (750 * px) / getApp<any>().globalData.device.windowWidth;
+  }
+  return px;
+}