Explorar o código

设备、用户、扫码页面等修改

zuypeng hai 1 ano
pai
achega
38084e597a

+ 36 - 12
src/App.vue

@@ -1,14 +1,30 @@
 <script lang="ts">
-import { fetchToken } from "./utils/auth";
+import {fetchToken} from "./utils/auth";
+import {body} from "@/utils/https";
+import {groupByKey} from "@/utils/common";
+
 export default <any>{
   globalData: {
-    token: "",
-    userInfo:{},
-    isLogin:false,
-    lastData: {},
-    stations: [],
+    token: "bafdaa62-49a8-42a7-b4c9-d323703f65b0",
+    user: {
+      balance: 0,
+      defaultPlateNo: "",
+      discountAmount: 0,
+      gender: "",
+      id: "1306350524487958528",
+      lastLoginTime: "2024-11-17 20:47:13",
+      mobilePhone: "15071072750",
+      nickname: "",
+      openid: "oWsHs6-sE-JqrVmJgTPGO7boZGMY",
+      refundableAmount: 0,
+      status: 1,
+      userCouponList: [],
+      userRechargeRightsList: [],
+      username: "15071072750"
+    },
+    isLogin: false,
     normalCode: "",
-    device:null
+    device: null
   },
   onLaunch() {
     uni.getSystemInfo({
@@ -16,15 +32,23 @@ export default <any>{
         this.globalData.device = res;
       },
     });
-    return fetchToken().then((cache) => {
-      if (cache) {
-        this.globalData.token = cache;
+
+    body(`/dict/list`).then((res: any) => {
+      if (res) {
+        let dicts = res.map((k:any) => {
+          let {code, name, value, color} = k;
+          return {code, name, value, color}
+        })
+        let dictMap = groupByKey(dicts, "code");
+        uni.setStorage({key: 'dict', data: dictMap})
       }
-    });
+    })
+
+    this.globalData.token = fetchToken();
   },
   onPageNotFound() {
     uni.switchTab({
-      url: "/pages/map/map",
+      url: "/pages/index/index",
     });
   },
 };

+ 11 - 2
src/components/login-bar/index.vue

@@ -1,6 +1,6 @@
 <template>
   <view class="login-bar flex flex-inline" v-if="!state.isLogin">
-    <text class="font12" >   登录以享受更多洗车功能</text>
+    <text class="login-bar_title" >   请先登录以享受更多洗车功能</text>
     <uv-button class="login-bar_btn" size="mini" shape="circle" type="primary" open-type="getPhoneNumber"
                @getphonenumber="handleGetPhone">去登录
     </uv-button>
@@ -33,13 +33,22 @@ const handleGetPhone = (e:any) => {
 
 <style scoped lang="scss">
 .login-bar {
-  width: 92%;
+  width: calc(100vw - 40rpx);
   justify-content: space-between;
   background: #eee;
   border-radius: 8rpx;
   padding: 16rpx 10rpx;
   margin: 20rpx;
   box-shadow: 5px 5px 15px 5px rgba(0, 0, 0, 0.3);
+  position: fixed;
+  bottom: 160rpx;
+  left: 0;
+
+  &_title{
+    font-size: 12px;
+    height: 22px;
+    line-height: 22px;
+  }
 
   &_btn {
     margin-right: 30rpx;

+ 11 - 1
src/components/station/index.vue

@@ -25,7 +25,12 @@
         </view>
       </view>
       <view class="station_item-content-right">
-        <uv-button circle type="primary" size="mini" plain @click.stop="handleNavMap(item)">{{ item.distance }}km</uv-button>
+<!--        <image
+            style="width: 20px; height: 20px;color: #eeeeee;"
+            src="/static/nav.png"
+        />-->
+        <uv-icon name="map" color="#19A497"></uv-icon>
+        <text class="font12"  @click.stop="handleNavMap(item)">{{ item.distance }}km</text>
         <!--            <uv-tags text="1222km" type="warning" plain size="mini"></uv-tags>-->
       </view>
     </view>
@@ -156,11 +161,16 @@ const handleNavStation = (station: any) => {
     }
 
     &-right {
+      border-radius: 10rpx;
+      background-color: #eee;
+      //border: 1px solid $uni-color-primary;
       width: 120rpx;
       display: flex;
       flex-direction: column;
       justify-content: center;
       align-content: center;
+      align-items: center;
+
     }
   }
 

+ 193 - 49
src/components/tab-bar/index.vue

@@ -1,59 +1,203 @@
 <template>
-  <view class="tabbar">
-    <uv-tabbar :value="value" :fixed="true" @change="index=>value = index">
-      <uv-tabbar-item text="网点" icon="home" @tap.stop="handleTabbarClick('index')"></uv-tabbar-item>
-<!--      <uv-tabbar-item text="优惠" icon="photo" @tap.stop="handleTabbarClick('coupon')"></uv-tabbar-item>-->
-      <uv-tabbar-item text="" icon="scan" :iconSize="40" @tap.stop="handleTabbarClick('map')" style="margin-top: -125px">
-      </uv-tabbar-item>
-<!--      <uv-tabbar-item text="订单" icon="play-right" @tap.stop="handleTabbarClick('order')"></uv-tabbar-item>-->
-      <uv-tabbar-item text="我的" icon="account" @tap.stop="handleTabbarClick('user')"></uv-tabbar-item>
-    </uv-tabbar>
+  <view class="tabbar-container">
+    <block>
+      <view class="tabbar-item"
+            v-for="(item, index) in state.tabbarList" :key="index"
+            :class="[item.centerItem ? ' center-item' : '']"
+            @click="handleTabbarClick(item)">
+        <view class="item-top"><image :src="state.currentItem == item.id ? item.selectIcon : item.icon"></image></view>
+        <view class="item-bottom" :class="[state.currentItem == item.id ? 'item-active' : '']">
+          <text>{{ item.text }}</text>
+        </view>
+      </view>
+    </block>
   </view>
-
 </template>
+
 <script setup lang="ts" name="TabBar">
-import {onMounted, reactive, ref} from 'vue'
-import {onLoad, onShow, onTabItemTap} from "@dcloudio/uni-app";
+  import {onMounted, reactive, ref} from 'vue'
+  import {onLoad, onShow} from "@dcloudio/uni-app";
 
-const props = defineProps({
-  index: {
-    type: Number,
-    default: 0
-  }
-})
-const value = ref(0)
-
-
-onLoad(() => {
-  console.log("tabbar onLoad", props.index, value.value)
-  value.value = props.index;
-})
-
-onShow(() => {
-  console.log("tabbar onshow", props.index, value.value)
-  value.value = props.index;
-})
-
-onMounted(()=>{
-  console.log("tabbar onMounted", props.index, value.value)
-  value.value = props.index;
-})
-
-const handleTabbarClick = (tab: string) => {
-  uni.switchTab({
-    url: `/pages/${tab}/index`,
-    success: (e: any) => {
-      console.log("tabbar switch>>>>", tab,e)
-    },
-    fail: (e: any) => {
-      console.error("swtich error >>>>>", JSON.stringify(e))
+  const props = defineProps({
+    index: {
+      type: Number,
+      default: 0
     }
   })
-}
-</script>
 
-<style lang="scss" scoped>
-.tabbar {
-  background-image: url("../../static/tabbar/bg.png");
+  const state = reactive({
+    currentItem:0,
+    tabbarList:[
+      {
+        id: 0,
+        path: '/pages/index/index',
+        icon: '/static/tabbar/1.png',
+        selectIcon: '/static/tabbar/1-1.png',
+        text: '网点',
+        centerItem: false
+      },
+      {
+        id: 1,
+        path: '/pages-wash/scan/index',
+        icon: '/static/tabbar/2.png',
+        selectIcon: '/static/tabbar/2-1.png',
+        text: '扫码',
+        centerItem: true
+      },
+      {
+        id: 2,
+        path: '/pages/user/index',
+        icon: '/static/tabbar/4.png',
+        selectIcon: '/static/tabbar/4-1.png',
+        text: '我的',
+        centerItem: false
+      }
+    ]
+  })
+
+  onLoad(() => {
+    state.currentItem = props.index;
+  })
+
+  onShow(() => {
+    state.currentItem = props.index;
+  })
+
+  onMounted(()=>{
+    state.currentItem = props.index;
+  })
+
+
+  const handleTabbarClick = (item: string) => {
+    if(item.path.includes("scan")){
+      uni.navigateTo({url:item.path})
+      return;
+    }
+
+    uni.switchTab({
+      url: item?.path,
+      success: (e: any) => {
+        console.log("tabbar switch>>>>", item,e)
+      },
+      fail: (e: any) => {
+        console.error("swtich error >>>>>", JSON.stringify(e))
+      }
+    })
+  }
+
+ /* export default {
+  props: {
+    index: {
+      type: Number,
+      default: 0
+    }
+  },
+  data() {
+    return {
+      currentItem: 0,
+      tabbarList: [
+        {
+          id: 0,
+          path: '/pages/index/index',
+          icon: '/static/tabbar/1.png',
+          selectIcon: '/static/tabbar/1-1.png',
+          text: '网点',
+          centerItem: false
+        },
+        {
+          id: 1,
+          path: '/pages/map/index',
+          icon: '/static/tabbar/2.png',
+          selectIcon: '/static/tabbar/2-1.png',
+          text: '扫码',
+          centerItem: true
+        },
+        {
+          id: 2,
+          path: '/pages/user/index',
+          icon: '/static/tabbar/4.png',
+          selectIcon: '/static/tabbar/4-1.png',
+          text: '我的',
+          centerItem: false
+        }
+      ]
+    };
+  },
+  mounted() {
+    this.currentItem = this.currentPage;
+    // uni.hideTabBar();
+  },
+  methods: {
+    changeItem(item) {
+      let _this = this;
+      //_this.currentItem = item.id;
+      uni.switchTab({
+        url: item.path
+      });
+    }
+  }
+};*/
+</script>
+<style>
+view {
+  padding: 0;
+  margin: 0;
+  box-sizing: border-box;
+}
+.tabbar-container {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  width: 100%;
+  height: 110rpx;
+  box-shadow: 0 0 5px #999;
+  display: flex;
+  align-items: center;
+  padding: 5rpx 0;
+  color: #999999;
+}
+.tabbar-container .tabbar-item {
+  width: 33.3%;
+  height: 100rpx;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  text-align: center;
+}
+.tabbar-container .item-active {
+  color: #398ade;
+}
+.tabbar-container .center-item {
+  display: block;
+  position: relative;
+}
+.tabbar-container .tabbar-item .item-top {
+  width: 70rpx;
+  height: 70rpx;
+  padding: 10rpx;
+}
+.tabbar-container .center-item .item-top {
+  flex-shrink: 0;
+  width: 100rpx;
+  height: 100rpx;
+  position: absolute;
+  top: -50rpx;
+  left: calc(50% - 50rpx);
+  border-radius: 50%;
+  box-shadow: 0 0 5px #999;
+  background-color: #ffffff;
+}
+.tabbar-container .tabbar-item .item-top image {
+  width: 100%;
+  height: 100%;
+}
+.tabbar-container .tabbar-item .item-bottom {
+  font-size: 28rpx;
+  width: 100%;
+}
+.tabbar-container .center-item .item-bottom {
+  position: absolute;
+  bottom: 5rpx;
 }
 </style>

+ 37 - 193
src/pages-user/profile/index.vue

@@ -1,32 +1,12 @@
 <template>
-  <view class="pt-60 pb-20 flex-center">
-    <button
-        class="avatar"
-        open-type="chooseAvatar"
-        @chooseavatar="chooseAvatar">
-      <image class="avatar_image" :src="avatar" @error="errorHandle"></image>
-      <view class="avatar_text flex-center">编辑</view>
-    </button>
-  </view>
-
-  <view class="pl-50 pr-50">
-    <view
-        class="menu flex-align-center flex-between"
-        v-for="(item, index) in menu"
-        :key="index"
-        @click="edit(index)">
-      <view class="fs-30">{{ item.title }}</view>
-      <view class="flex">
-        <view
-            :class="['fs-30', 'fw-500', `mr-${item.disabled ? '0' : '20'}`]"
-            style="color: rgba(0, 0, 0, 0.8)">{{ item.value }}
-        </view>
-        <uv-icon name="right-arrow" v-if="!item.disabled" size="12" color="rgba(0,0,0,0.4)"></uv-icon>
-      </view>
-    </view>
-  </view>
-
-  <view class="pl-60 pr-60 pb-40">
+  <uv-list>
+    <uv-list-item title="车牌号"
+                  :show-arrow="true"
+                  clickable :rightText="plateNo"
+                  @click="handleChoosePlate"></uv-list-item>
+  </uv-list>
+
+  <view class="logout-btn">
     <uv-button :custom-style="customStyle" type="error" @click="logoutUser">退出登录</uv-button>
   </view>
 </template>
@@ -37,35 +17,7 @@ import {ref} from "vue";
 import {body, get, upload} from "@/utils/https";
 import {clearToken} from "@/utils/auth"
 
-const avatar = ref<string>();
-const menu = ref<any[]>([]);
-const MENU_TEMPLATE = [
-  {
-    title: "昵称",
-    key: "nickname",
-    value: "",
-  },
-  {
-    title: "电话",
-    key: "",
-    disabled: true,
-  },
-  {
-    title: "车牌号",
-    key: "defaultPlateNo",
-    value: "",
-  },
-  {
-    title: "VIN码",
-    key: "vin",
-    value: "",
-  },
-  // {
-  //   title: "充电卡",
-  //   key: "",
-  //   value: "",
-  // },
-];
+const plateNo = ref("未绑定")
 
 const customStyle = () => {
   return {
@@ -80,102 +32,38 @@ const customStyle = () => {
   }
 }
 
-const refresh = () => {
-  const _menu = [...MENU_TEMPLATE];
-  get(`user/profile`).then((res: any) => {
-    let {user, permission} = res;
-    getApp<any>().globalData.user = user;
 
-    if (user) {
-      _menu[0].value = user.nickname;
-      _menu[1].value = user.mobilePhone;
-      _menu[2].value = user.defaultPlateNo;
-      _menu[3].value = user.vin;
-      // _menu[4].value = user.card_no;
-      avatar.value =
-          user.avatar ||
-          "https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0";
-      menu.value = _menu;
-    }
-  })
-};
+const handleChoosePlate = () => {
+  uni.chooseLicensePlate({
+    success: (res) => {
+      save({
+        defaultPlateNo: res.plateNumber,
+      });
+    },
+    fail: (err) => {
+      console.log(err);
+    },
+  });
+}
+
 
 const save = (form: Record<string, any>) => {
   console.log(form)
   uni.showLoading({
     title: "保存中",
   });
-  body(`user/updateProfile`, form).then(() => {
+  body(`/user/updateUser`, form).then(() => {
     uni.hideLoading();
+    getApp<any>().globalData.user.defaultPlateNo = form.defaultPlateNo;
     uni.showToast({
       icon: "success",
       title: "保存成功",
     });
-    refresh();
   }).catch((err: any) => {
     uni.hideLoading();
   })
 };
 
-const chooseAvatar = (e: any) => {
-  console.log(e)
-  if (e.detail.avatarUrl) {
-    uni.showLoading({
-      title: "上传中",
-    });
-
-    upload(`file/upload`, {filePath: e.detail.avatarUrl,name:'avatar.jpg'}).then((res: any) => {
-      body(`user/updateAvatar`, {avatar: res.url}).then(() => {
-        uni.hideLoading();
-        uni.showToast({
-          icon: "success",
-          title: "保存成功",
-        });
-        refresh();
-      }).catch((err: any) => {
-        console.error(err)
-        uni.hideLoading();
-      })
-    })
-  } else {
-    uni.showModal({
-      content: `${e.detail.errMsg},请重试`,
-    });
-  }
-};
-
-
-const edit = (index: number) => {
-  const menuItem = menu.value[index];
-  if (menuItem.disabled) {
-    return;
-  }
-  if (!menuItem.key) {
-    uni.showToast({
-      icon: "none",
-      title: "暂不支持修改",
-    });
-    return;
-  }
-  if (/车牌/.test(menuItem.title)) {
-    uni.chooseLicensePlate({
-      success: (res) => {
-        save({
-          defaultPlateNo: res.plateNumber,
-        });
-      },
-      fail: (err) => {
-        console.log(err);
-      },
-    });
-    return;
-  }
-  uni.navigateTo({
-    url: `/pages-user/profile-edit/profile-edit?key=${menuItem.key}&title=${
-        menuItem.title
-    }${menuItem.value ? `&value=${encodeURIComponent(menuItem.value)}` : ""}`,
-  });
-};
 
 const logoutUser = () => {
   uni.showModal({
@@ -190,7 +78,7 @@ const logoutUser = () => {
           title: "退出中",
         });
 
-        get(`user/logout`).then(() => {
+        get(`/user/logout`).then(() => {
           uni.hideLoading();
           uni.showToast({
             icon: "success",
@@ -200,7 +88,7 @@ const logoutUser = () => {
           clearToken();
           setTimeout(() => {
             uni.reLaunch({
-              url: "/pages/map/map",
+              url: "/pages/index/index",
             });
           }, 1500);
 
@@ -210,72 +98,28 @@ const logoutUser = () => {
   });
 };
 
-const errorHandle = (e: any) => {
-  console.log(e);
-};
 
 onLoad(() => {
   if (getApp<any>().globalData.user) {
     const user = getApp<any>().globalData.user;
-    const _menu = [...MENU_TEMPLATE];
-    _menu[0].value = user.nickname;
-    _menu[1].value = user.mobilePhone;
-    _menu[2].value = user.defaultPlateNo;
-    _menu[3].value = user.vin;
-    // _menu[4].value = user.card_no;
-    avatar.value =
-        user.avatar ||
-        "https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0";
-    menu.value = _menu;
-  }
-});
-onShow(() => {
-  if (getApp<any>().globalData.lastData.profile) {
-    const {key, value} = getApp<any>().globalData.lastData.profile;
-    save({
-      [key]: value,
-    })
+    plateNo.value = user.defaultPlateNo || "未绑定";
   }
 });
-</script>
 
-<style lang="scss">
-.avatar {
-  position: relative;
-  height: 116rpx !important;
-  width: 116rpx !important;
-  border-radius: 50%;
-  border: 2rpx solid rgba(0, 0, 0, 0.15);
-  overflow: hidden;
 
-  &_image {
-    position: absolute;
-    width: 100%;
-    height: 100%;
-    left: 0;
-    top: 0;
-    border-radius: 50%;
+onShow(() => {
+  if (getApp<any>().globalData.user) {
+    const user = getApp<any>().globalData.user;
+    plateNo.value = user.defaultPlateNo || "未绑定";
   }
 
-  &_text {
-    position: absolute;
-    bottom: 0;
-    left: 0;
-    width: 100%;
-    height: 40rpx;
-    background: rgba(0, 0, 0, 0.5);
-    color: #fff;
-    font-size: 24rpx;
-  }
-}
 
-.menu {
-  background-color: #fff;
-  height: 120rpx;
-  border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
+});
+</script>
 
-  &:last-child {
-    border-bottom: none;
-  }
+<style lang="scss">
+.logout-btn{
+  width: calc(100vw - 60rpx);
+  margin: 60rpx auto;
 }
 </style>

+ 110 - 206
src/pages-user/wallet/index.vue

@@ -1,89 +1,56 @@
 <template>
   <view class="page flex-column">
-    <view class="head flex-shrink">
-      <view>
-        <image class="bg" src="/static/wallet-banner.png"></image>
-        <view class="fg pt-48 pl-48 pr-48">
-          <view class="flex-align-center">
-            <uv-icon type="wallet" size="24" color="#ffffff"></uv-icon>
-            <view class="fs-36 color-fff fw-500 ml-16">我的钱包</view>
-            <view
-                class="btn flex-center fs-28 ml-auto"
-                @click="to(`/pages-user/wallet/refund`)">退款
-            </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 class="wallet-header">
+      <view class="wallet-header_title">
+        <view class="wallet-header_title-left">
+          <uv-icon name="level" color="white" size="28"></uv-icon>
+          <text class="font16">我的钱包</text>
         </view>
+        <text class="wallet-header_title-refund" @click="handleRefund">退款</text>
       </view>
-    </view>
-    <view class="body flex-grow flex-column">
-      <view class="tabs flex-shrink flex-align-center">
-        <view
-            v-for="(item, index) in tabs"
-            :key="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 class="wallet-header_balance">
+        <text class="font18 mr10" style="vertical-align: top">¥</text>
+        <text style="font-size: 32px; line-height: 32px;font-weight: 600;">{{ (user?.balance || 0).toFixed(2) }}
+        </text>
       </view>
-      <view class="list pl-30 pr-30">
-        <view
-            class="item flex-align-center"
-            v-for="(item, index) in dataList"
-            :key="index"
-            @click="detail(index)">
-          <view>
-            <view class="fs-30 fw-500" key="title" duration="300">{{
-                typeMap[item.type - 1]
-              }}
-            </view>
-            <view v-if="item.type!==2">
-              <view class="fs-24" style="color: rgba(0, 0, 0, 0.4)">余额</view>
-            </view>
-            <view v-else>
-              <text class="refund-status" :style="refundStyle(item.status)">{{ refundLabel(item.status) }}</text>
-            </view>
+      <view class="wallet-header_pounds">
+        <view>
+          <text>充值余额:</text>
+          <text>112.34</text>
+        </view>
 
-          </view>
-          <view class="ml-auto" style="text-align: right">
-            <view class="fs-30 fw-500">
-              <text>{{ item.type == 3 ? "- " : "" }}{{ 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">
-            <uv-icon type="right" size="12" color="rgba(0,0,0,0.4)"></uv-icon>
-          </view>
-          <view class="ml-32" v-else>&nbsp;&nbsp;&nbsp;</view>
+        <view>
+          <text>赠款余额:</text>
+          <text>20.00</text>
         </view>
       </view>
+    </view>
 
-      <view style="height: 170rpx"></view>
+    <view class="wallet-body">
+      <uv-tabs :list="tabs" @click="handleTabClick"></uv-tabs>
+      <uv-list>
+        <uv-list-item
+                      clickable show-arrow v-for="(item,index) in dataList" :key="index">
+          <template #default>
+
+          </template>
+        </uv-list-item>
+        <uv-list-item title="列表文字" note="列表描述信息"></uv-list-item>
+        <uv-list-item title="列表文字" note="列表描述信息"></uv-list-item>
+        <uv-list-item title="列表文字" note="列表描述信息"></uv-list-item>
+        <uv-list-item title="列表文字" note="列表描述信息"></uv-list-item>
+      </uv-list>
     </view>
-    <view>
-      <view class="pl-40 pr-40 pb-30 pt-30">
-        <uv-button
-            type="primary"
-            @click="to(`/pages-user/wallet-recharge/wallet-recharge`)">充值
-        </uv-button>
-      </view>
+
+    <view class="wallet-bottom">
+      <uv-button
+          shape="circle"
+          type="primary"
+          color="#19A497"
+          @click="to(`/pages-user/wallet/recharge`)">充值
+      </uv-button>
     </view>
+
   </view>
 </template>
 
@@ -99,32 +66,28 @@ const dataList = ref([])
 const tab = ref(0);
 const tabs = ref([
   {
-    label: "全部",
+    name: "全部",
     value: 0,
   },
   {
-    label: "充值",
+    name: "充值",
     value: 1,
   },
   {
-    label: "消费",
+    name: "消费",
     value: 3,
   },
   {
-    label: "退款",
+    name: "退款",
     value: 2,
   },
 ]);
 
-const refundStatusMap = ref([
-  {label: '退款成功 ', value: 'SUCCESS', color: '#4cd964'},
-  {label: '退款关闭  ', value: 'CLOSED', color: '#000000'},
-  {label: '退款处理中 ', value: 'PROCESSING', color: '#007aff'},
-  {label: '退款异常  ', value: 'ABNORMAL', color: '#dd524d'},
-  {label: '退款已申请  ', value: 'NEW', color: '#f0ad4e'},
-])
 
-const typeMap = ref(["充值", "退款", "消费"]);
+const handleRefund = () => {
+  to(`/pages-user/wallet/refund`)
+}
+
 /*const infiniteScroller = useInfiniteScroll(10, (page) => {
   return fetchWallet(tab.value, page, 10).then((res: any) => {
     if (res && res.length) {
@@ -165,79 +128,29 @@ const to = (url: string) => {
   })
 }
 
-const ready = (e: any) => {
-  scrollViewHeight.value =
-      getApp<any>().globalData.device.windowHeight -
-      (e.detail.navigationBarHeight + rpxToPx(380));
-};
-
-const refundLabel = (value: string) => {
-  return refundStatusMap.value.find((item: any) => item.value === value)?.label
-}
-
-const refundStyle = (value: string) => {
-  let rf = refundStatusMap.value.find((item: any) => item.value === value);
-  return setupLabelColorStyle(rf?.color)
-}
-
-const setupLabelColorStyle = (hex: string = "#000000", opacity = 0.2) => {
-  if (!hex) {
-    hex = "#000000"
-  }
-  hex = hex.replace("#", "");
-  // Convert the hex value to RGB values
-  const r = parseInt(hex.substring(0, 2), 16);
-  const g = parseInt(hex.substring(2, 4), 16);
-  const b = parseInt(hex.substring(4, 6), 16);
-
-  return {
-    /*    'text-shadow': `2px 2px 3px rgba(${r},${g},${b},${opacity})`,
-        'background-color': `rgba(${r},${g},${b},${opacity})`,*/
-    'color': `rgb(${r},${g},${b})`
-  }
-}
-
-const changeTab = (index: number) => {
-  tab.value = tabs.value[index].value;
+const handleTabClick = (e:any) => {
+  let {name,value,index} = e
+  tab.value = index;
+  console.log(index)
   loadData();
 }
 
 const loadData = () => {
   if (!user) return;
-  if (tab.value !== 2) {
-    get(`user/wallet`).then((res: any) => {
-      if (res && res.length) {
-        res.forEach((item: any) => {
-          item.amount = (Number(item.amount) / 100).toFixed(2);
-        });
-      }
-      dataList.value = res;
-    })
-  } else {
-    body((`user/refundList`)).then((res: any) => {
-      console.log(res)
-      let list = (res.list || []).map(item => {
-        item.amount = (Number(item.refund) / 100).toFixed(2);
-        item.type = 2;
-        if (item.successTime) {
-          item.transactionTime = item.successTime.slice(0, 3).join("-") + " " + item.successTime.slice(3, 6).join(":")
-        }
-        return item;
-      })
-      dataList.value = list;
-    })
-  }
+  get(`/account/walletDetail`, {type: tab.value}).then((list: any) => {
+    dataList.value = list;
+  })
 }
 
 const detail = (index: number) => {
   if (!dataList.value) {
     return;
   }
-  if (dataList.value[index].type === 3) {
+/*  if (dataList.value[index].type === 3) {
     uni.navigateTo({
       url: `/pages-order/detail/index?id=${dataList.value[index]?.orderNo}`,
     });
-  }
+  }*/
 };
 </script>
 
@@ -250,77 +163,68 @@ const detail = (index: number) => {
           #e0ebff 0%,
           rgba(255, 255, 255, 0) 60.13%
   );
+  display: flex;
+  flex-direction: column;
+
+  .wallet-header {
+    border-radius: 20rpx;
+    background-color: $uni-color-primary;
+    margin: 20rpx;
+    display: flex;
+    flex-direction: column;
+    padding: 20rpx;
+
+    &_title {
+      display: inline-flex;
+      justify-content: space-between;
+      color: whitesmoke;
+
+      &-left {
+        display: inline-flex;
+        align-items: center;
+        align-content: center;
+        color: whitesmoke;
+      }
 
-  .head {
-    padding: 30rpx 40rpx;
-
-    & > view {
-      position: relative;
-      height: 320rpx;
-      border-radius: 40rpx;
-      overflow: hidden;
-
-      .bg {
-        height: 100%;
-        width: 100%;
+      &-refund {
+        color: #127779;
+        padding: 6rpx 28rpx;
+        font-size: 26rpx;
+        border-radius: 14px;
+        background-color: #65C0B7;
       }
+    }
 
-      .fg {
-        position: absolute;
-        left: 0px;
-        top: 0px;
-        height: 100%;
-        width: 100%;
+    &_balance {
+      display: inline-flex;
+      color: white;
+      align-content: center;
+      margin-top: 40rpx;
+    }
 
-        .btn {
-          width: 120rpx;
-          height: 64rpx;
-          border-radius: 40rpx;
-          background: rgba(255, 255, 255, 0.3);
-          color: #076370;
-        }
-      }
+    &_pounds {
+      margin-top: 20rpx;
+      display: inline-flex;
+      align-content: center;
+      align-items: center;
+      color: white;
+      justify-content: space-between;
     }
   }
 
-  .body {
-    .tabs {
-      padding: 0 40rpx;
+  .wallet-body {
 
-      & > view {
-        position: relative;
-        height: 72rpx;
+    margin-bottom: 60rpx;
+  }
 
-        .active {
-          position: absolute;
-          left: 50%;
-          bottom: 0px;
-          transform: translateX(-50%);
-          width: 40rpx;
-          height: 4rpx;
-          border-radius: 4rpx;
-          background-color: var(--color-primary);
-        }
-      }
-    }
+  .wallet-bottom {
+    width: 100%;
+    position: absolute;
+    bottom: 20rpx;
+    left: 0;
+  }
 
-    .list {
-      .item {
-        height: 130rpx;
-        border-bottom: 1rpx solid rgba(0, 0, 0, 0.1);
 
-        &:last-child {
-          border-bottom: none;
-        }
-      }
-    }
-  }
 }
 
-.refund-status {
-  display: inline-block;
-  //padding: 8rpx;
-  font-size: 22rpx;
-  font-weight: 500;
-}
 </style>

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

@@ -0,0 +1,219 @@
+<template>
+  <view class="pl-30 pr-30">
+    <view class="pay">
+      <view class="title pt-30 pb-30">充值金额</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)">
+          <image
+              v-if="payOptionsDiscount[index]"
+              src="/static/images/coupon-center.png"
+              mode="widthFix"
+              class="tag fs-24 color-fff fw-500  width-40"
+          />
+          <!--          <view
+                        class="tag fs-24 color-fff fw-500"
+                        v-if="payOptionsDiscount[index]">{{ payOptionsDiscount[index] }}
+                    </view>-->
+          {{ item }}
+        </view>
+      </view>
+      <view v-if="payOptionsDiscountDay[payOption]" class="flex-align-center">
+        <view class="fs-30 color-666">
+          {{ (payOptionsDiscount[payOption] && payOptionsDiscount[payOption] > 0) ? `享服务费${payOptionsDiscount[payOption]}折,` : '' }}权益有效期{{
+            payOptionsDiscountDay[payOption]
+          }}天
+        </view>
+        <view
+            class="ml-12 color-primary fs-30"
+            @click="to(`/pages-common/activity/activity?id=${activityId}`)">
+          <text>详细规则</text>
+          <text class="fs-24 ml-6">>></text>
+        </view>
+      </view>
+      <view class="title pt-60 pb-30">自定义金额</view>
+      <style-input
+          :value="payValue > 0 ? payValue : ''"
+          title="金额"
+          type="digit"
+          @input="input"/>
+    </view>
+  </view>
+
+  <style-bottom-view>
+    <view class="pl-60 pr-60 pb-20">
+      <style-button size="small" type="primary" @click="debounceConfirm">充值</style-button>
+    </view>
+  </style-bottom-view>
+</template>
+
+<script setup lang="ts">
+import {ref} from "vue";
+import {onLoad} from "@dcloudio/uni-app";
+import {back, to} from "@/utils/navigate";
+import {debounce} from "@/utils/common";
+
+const balance = ref(0);
+const payOption = ref(3);
+const payOptions = ref([30, 50, 100, 200, 500, 1000]);
+const payOptionsDiscount = ref(["", "", "", "", "", ""]);
+const payOptionsDiscountDay = ref([0, 0, 0, 0, 0, 0]);
+const payValue = ref(0);
+const activityId = ref();
+const rechargeRightsId = ref();
+const rechargeRightsList = ref([]);
+const needBack = ref(false);
+const input = (e: any) => {
+  payValue.value = e.value;
+  rechargeRightsId.value = 0;
+};
+const changeOption = (index: number) => {
+  payValue.value = 0;
+  payOption.value = index;
+  let find = rechargeRightsList.value.find((k:any) => (k.amountMin || 0) / 100 === payOptions.value[index]);
+  if (find) {
+    rechargeRightsId.value = find?.id;
+  }
+};
+
+const debounceConfirm = debounce(() => {
+  confirm();
+}, 500)
+
+const confirm = () => {
+  if (payValue.value && !/^[0-9]*(\.\d{1,2})?$/.test(`${payValue.value}`)) {
+    uni.showModal({
+      title: "温馨提示",
+      content: "请输入正确的金额",
+      showCancel: false,
+      confirmColor: "#2d9e95",
+    });
+    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: "#2d9e95",
+    });
+    return;
+  }
+  uni.showLoading({
+    title: "加载中",
+  });
+  insertMoney(params, rechargeRightsId.value)
+      .then(() => {
+        return fetchProfile();
+      })
+      .then((res) => {
+        payValue.value = 0;
+        balance.value = res.balance;
+        uni.hideLoading();
+        uni.showToast({
+          title: "已支付",
+          icon: "success",
+        });
+        setTimeout(() => {
+          if (needBack.value) {
+            back();
+          } else {
+            to("/pages-user/wallet/wallet");
+          }
+        }, 2000);
+      })
+      .catch((err) => {
+        if (/cancel/.test(err.errMsg)) {
+          return;
+        }
+        uni.showModal({
+          content: `${err.errMsg},请重试`,
+        });
+      });
+};
+
+
+onLoad((options: any) => {
+  console.log(options)
+  if (options.value) {
+    payOption.value = payOptions.value.findIndex(
+        (item) => item === Number((Number(options.value) / 100).toFixed(2))
+    );
+    needBack.value = !!options.back;
+  }
+
+  if (options.discount) {
+    payValue.value = Number((Number(options.discount) / 100).toFixed(2));
+  }
+  fetchProfile().then((res) => {
+    // console.log(res);
+    balance.value = res.balance;
+    if (res && res.activityList && res.activityList.length) {
+      res.activityList[0].rechargeRightsList.forEach((item: any) => {
+        const val = Number((Number(item.amountMin) / 100).toFixed(2));
+        const fi = payOptions.value.findIndex((o) => o === val);
+        if (fi >= 0) {
+          payOptionsDiscount.value[fi] = ((item.discount || 0) / 10).toFixed(1);
+          payOptionsDiscountDay.value[fi] = item.validity > 0 ? item.validity : 1;
+        }
+      });
+      if (res.activityList && res.activityList[0].rechargeRightsList && res.activityList[0].rechargeRightsList.length > 0) {
+        rechargeRightsList.value = res?.activityList[0]?.rechargeRightsList
+      }
+      activityId.value = res.activityList[0].id;
+    }
+  });
+});
+</script>
+
+<style lang="scss">
+.pay {
+  .title {
+    font-weight: 500;
+    font-size: 32rpx;
+    color: #000;
+  }
+
+  .option {
+    position: relative;
+    width: 214rpx;
+    height: 140rpx;
+    background: var(--color-sec);
+    border-radius: 10rpx;
+    margin-left: 20rpx;
+    margin-bottom: 20rpx;
+    font-size: 36rpx;
+    color: #000;
+    font-weight: 500;
+    //overflow: hidden;
+
+    &:nth-child(3n + 1) {
+      margin-left: 0;
+    }
+
+    .tag {
+      position: absolute;
+      top: -9px;
+      right: -10px;
+      padding: 2rpx 2rpx;
+    }
+  }
+
+  .option-active {
+    color: var(--color-primary);
+    //border-color: var(--color-primary);
+    //color: #fff;
+    font-weight: 700;
+  }
+}
+</style>

+ 0 - 41
src/pages-wash/detail/index.vue

@@ -1,41 +0,0 @@
-<template>
-  <view :class="['page']">
-
-  </view>
-</template>
-
-<script setup lang="ts" >
-import {onHide, onLoad, onShow} from "@dcloudio/uni-app";
-import {reactive, ref} from "vue";
-
-const initState = () => ({
-  couponList: [] as any[],
-})
-
-const state = reactive(initState())
-
-onHide(() => {
-  Object.assign(state, initState());
-})
-
-onLoad((options) => {
-  console.log("detail show>>>>",options)
-});
-
-
-
-</script>
-
-<style lang="scss" scoped>
-.page {
-  min-height: 100vh;
-  width: 100%;
-  padding: 20rpx;
-  background-color: #f6f7fa;
-}
-
-.block {
-  border-radius: 20rpx;
-  background: #fff;
-}
-</style>

+ 118 - 0
src/pages-wash/device/index.vue

@@ -0,0 +1,118 @@
+<template>
+  <view :class="['page']">
+      <view class="device-header">
+        <view class="device-header_name">
+          <text>洗车机编号:{{state.device.name}}</text>
+        </view>
+        <view class="device-header_fun">
+          <uv-tags v-for="(f,i) in state.device.funcs" :key="i" size="mini" type="primary">{{f}}</uv-tags>
+        </view>
+      </view>
+      <view class="device-body">
+        <view class="device-body_ops" @click="handleClickDevice">
+          <text v-if="state.device.isRunning">停止</text>
+          <text >启动</text>
+        </view>
+        <view class="device-body_ops-time">{{state.time}}</view>
+      </view>
+  </view>
+</template>
+
+<script setup lang="ts" >
+import {onHide, onLoad, onShow} from "@dcloudio/uni-app";
+import {reactive, ref} from "vue";
+import {get} from "@/utils/https";
+
+const initState = () => ({
+  device:{},
+  time:"00:00:00",
+  start:new Date()
+})
+
+const state = reactive(initState())
+
+onHide(() => {
+  Object.assign(state, initState());
+})
+
+onLoad((options) => {
+  console.log("detail show>>>>",options)
+  let id = options?.id;
+  if(!id){
+    return;
+  }
+  loadDeviceDetail(id);
+});
+
+
+const loadDeviceDetail = (id:number) => {
+  get(`/wash-device/queryDevice/${id}`).then((res:any)=>{
+    state.device = res;
+  })
+  countTime();
+}
+
+const handleClickDevice = () => {
+
+}
+
+const countTime= ()=>{
+  setInterval(()=>{
+    let delta = new Date().getTime() - state.start.getTime();
+    delta = delta/1000;
+    let hour = (delta/3600).toFixed(0);
+    let min = ((delta%3600)/60).toFixed(0);
+    let second =  ((delta%3600)%60).toFixed(0);
+    state.time = [
+        Number(hour)>9?hour:`0${hour}`,
+        Number(min)>9?min:`0${min}`,
+        Number(second)>9?second:`0${second}`
+    ].join(":")
+  },1000)
+}
+
+
+</script>
+
+<style lang="scss" scoped>
+.page {
+  min-height: 100vh;
+  width: 100%;
+  background-color: #f6f7fa;
+}
+
+.device-header{
+  padding: 20rpx;
+  display: flex;
+  flex-direction: column;
+
+  &_name{
+    font-weight: 500;
+  }
+
+}
+
+.device-body{
+  flex-grow: 1;
+  margin-top: 60rpx;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  align-content: center;
+
+  &_ops{
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    align-content: center;
+    width: 240rpx;
+    height: 240rpx;
+    border-radius: 50%;
+    background-color: $uni-color-primary;
+    color: white;
+    font-size: 32px;
+    font-weight: 600;
+  }
+}
+</style>

+ 228 - 0
src/pages-wash/scan/index.vue

@@ -0,0 +1,228 @@
+<template>
+  <view class="page flex-column">
+    <cover-image
+      class="page_back"
+      :style="backStyle"
+      src="/static/scan/scan-camera-back.png"
+      @click="back"
+    ></cover-image>
+    <view class="page_camera flex-grow">
+      <camera
+        v-if="!isDevTool"
+        device-position="back"
+        mode="scanCode"
+        :flash="cameraFlash"
+        @scancode="handleScancode"
+        @ready="handleReady"
+        @error="handleError"
+        :style="{
+          width: '100%',
+          height: `${cameraHeight}px`,
+        }"
+      ></camera>
+      <view
+        v-else
+        class="mock-camera"
+        :style="{
+          width: '100%',
+          height: `${cameraHeight}px`,
+        }"
+      ></view>
+    </view>
+    <view class="page_action flex-shrink" id="page_action">
+      <cover-view
+        @click="toggleFlash"
+        style="
+          text-align: center;
+          position: absolute;
+          width: 100%;
+          left: 0;
+          top: -96px;
+        "
+      >
+        <cover-image
+          style="width: 28px; height: 28px; margin: 0 auto"
+          src="/static/scan/scan-code-light.png"
+        ></cover-image>
+        <cover-view
+          style="
+            color: rgba(255, 255, 255, 0.7);
+            font-size: 13px;
+            margin-top: 10px;
+          "
+          >{{ cameraFlash === "off" ? "轻触照亮" : "轻触关闭" }}</cover-view
+        >
+      </cover-view>
+      <view class="flex">
+        <view
+          class="flex-center flex-column"
+          @click="redirect('/pages-charge/codeing/codeing')"
+        >
+          <image
+            class="width-96"
+            mode="widthFix"
+            src="/static/scan/scan-code-input.png"
+          ></image>
+<!--          <view class="fs-24 color-fff mt-20">输入充电桩编码</view>-->
+        </view>
+        <view class="flex-center flex-column" @click="chooseImage">
+          <image
+            class="width-96"
+            mode="widthFix"
+            src="/static/scan/scan-code-album.png"
+          ></image>
+          <view class="fs-24 color-fff mt-20">打开相册</view>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script setup lang="ts">
+import { ref } from "vue";
+import { isDevTool } from "@/utils/device";
+import { back, redirect } from "@/utils/navigate";
+import { onLoad, onReady } from "@dcloudio/uni-app";
+import {debounce} from "@/utils/common";
+
+const cameraHeight = ref(0);
+const cameraFlash = ref("off");
+const backStyle = ref("");
+const scaning = ref(false)
+
+onLoad(() => {
+  const menuButtonRect = uni.getMenuButtonBoundingClientRect();
+  backStyle.value = `left:12px;top:${menuButtonRect.top + 6}px;`;
+  // uni.showLoading({
+  //   title: "加载中",
+  // });
+  // fetchChargeStatus(true, true)
+  //   .then(() => {
+  //     uni.hideLoading();
+  //   })
+  //   .catch(() => {
+  //     uni.hideLoading();
+  //   });
+});
+
+onReady(() => {
+  // #ifdef MP-WEIXIN
+  const query = wx.createSelectorQuery();
+  query.select("#page_action").boundingClientRect();
+  query.exec(function (res: any) {
+    if (res && res.length) {
+      cameraHeight.value =
+        getApp<any>().globalData.device.windowHeight - res[0].height;
+      uni.hideLoading();
+    }
+  });
+  // #endif
+});
+
+const handleReady = () => {
+  uni.hideLoading();
+};
+
+const handleScancode = (e: any) => {
+  // debounce(()=>{
+  if(scaning.value){
+    return;
+  }else{
+    scaning.value = true;
+  }
+    uni.vibrateShort({});
+    if (e.detail && e.detail.result) {
+      console.log(e)
+      let {id} = e.detail.result;
+      uni.navigateTo({
+        url:'/pages-wash/device/index?id='+id
+      })
+    }
+    setTimeout(()=>{
+      scaning.value = false;
+    },500)
+  // },2000)
+};
+
+const debounceScan = debounce((e)=>{
+  handleScancode(e)
+},2000)
+
+const handleError = (e: any) => {
+  uni.hideLoading();
+  if (e.detail && e.detail.errMsg && /auth/.test(e.detail.errMsg)) {
+    uni.showModal({
+      content: "请打开摄像头权限开关",
+      success: () => {
+        uni.openSetting();
+      },
+    });
+    return;
+  }
+  uni.showModal({
+    content: e.detail.errMsg,
+  });
+};
+
+const toggleFlash = () => {
+  if (cameraFlash.value === "off") {
+    cameraFlash.value = "on";
+    return;
+  }
+  cameraFlash.value = "off";
+};
+
+const chooseImage = () => {
+  uni.chooseImage({
+    count: 1,
+    sizeType: ["compressed"],
+    sourceType: ["album"],
+    success: (res) => {
+      uni.showLoading({
+        title: "正在识别",
+      });
+    },
+    fail: (err) => {
+      console.log(err);
+      if (/cancel/.test(err.errMsg)) {
+        return;
+      }
+      uni.showModal({
+        content: err.errMsg || "出现错误,请重试",
+      });
+    },
+  });
+};
+</script>
+
+<style lang="scss">
+.page {
+  position: relative;
+  height: 100vh;
+  background-color: #000;
+  &_back {
+    position: absolute;
+    width: 24px;
+    height: auto;
+  }
+  &_camera {
+    height: 100%;
+    .mock-camera {
+      background-color: #999;
+    }
+  }
+  &_action {
+    position: relative;
+    box-sizing: content-box;
+    padding-bottom: constant(safe-area-inset-bottom);
+    padding-bottom: env(safe-area-inset-bottom);
+    & > view {
+      height: 222rpx;
+      & > view {
+        width: 50%;
+        height: 222rpx;
+      }
+    }
+  }
+}
+</style>

+ 58 - 96
src/pages-wash/station/index.vue

@@ -1,6 +1,6 @@
 <template>
   <view :class="['page']">
-  <image :src="state.station.pictures" mode="heightFix"></image>
+    <image :src="state.station.pictures" mode="heightFix"></image>
 
     <view class="station-box">
       <view class=" station_wrapper">
@@ -9,9 +9,20 @@
     </view>
 
     <view class="device-box w100">
-      <view class="device-item" v-for="device in state.deviceList" :key="device.id">
-
+      <view class="device-item" v-for="device in state.deviceList" :key="device.id" @click="handleClickDevice(device)">
+        <view class="device-item_header">
+          <text>{{ device.deviceName }}</text>
+          <text class="device-item_header-status">{{ getDictName('WashDevice.state',device.state) }}</text>
+        </view>
+        <view class="device-item_func">
+          <text class="device-item_func-label">{{device.functions}}</text>
+        </view>
       </view>
+
+    </view>
+
+    <view class="scan-btn">
+    <uv-button type="primary" icon="scan" iconColor="var(uni-color-primary)" text="扫码洗车"></uv-button>
     </view>
   </view>
 </template>
@@ -20,6 +31,7 @@
 import {onHide, onLoad, onShow} from "@dcloudio/uni-app";
 import {reactive, ref} from "vue";
 import {get} from "@/utils/https";
+import {getDictName} from "@/utils/common";
 import WashStation from "@/components/station/index.vue"
 
 const initState = () => ({
@@ -50,7 +62,7 @@ const loadStationDeviceList = () => {
   if (!state.station.id) {
     return;
   }
-  get(`/wash-device/listWashDevice`, {stationId: state.station.stationId}).then((deviceList:any) => {
+  get(`/wash-device/listWashDevice`, {stationId: state.station.stationId}).then((deviceList: any) => {
     state.deviceList = deviceList;
   })
 }
@@ -59,6 +71,12 @@ const handleNavStation = () => {
 
 }
 
+const handleClickDevice = (device:any) => {
+  uni.navigateTo({
+    url:'/pages-wash/device/index?id='+device.id
+  })
+}
+
 
 </script>
 
@@ -66,7 +84,6 @@ const handleNavStation = () => {
 .page {
   min-height: 100vh;
   width: 100%;
-  padding: 20rpx;
   background-color: #eee;
 }
 
@@ -74,113 +91,58 @@ const handleNavStation = () => {
   border-radius: 20rpx;
   background: #fff;
 }
+
 .content_station {
   height: calc(100vh - 480px);
 }
 
-.station-box{
-  width: calc(100vw - 40px);
-  margin: -80rpx auto;
+.station-box {
+  width: calc(100vw - 80rpx);
+  margin: -80rpx auto 0 auto;
   border-radius: 15rpx;
 }
 
-.station_item {
+.device-box {
+  margin-top: 30rpx;
+  margin-bottom: 100rpx;
+}
+
+.device-item {
+  background-color: #fff;
+  border-radius: 10rpx;
+  width: calc(100vw - 80rpx);
+  margin: 20rpx auto;
+  padding: 10rpx;
   display: flex;
   flex-direction: column;
-  border-radius: 10rpx;
-  margin-top: 20rpx;
-  padding: 15rpx;
-  background: #fafafa;
-  position: relative;
-
-  &-title {
-    display: inline-flex;
-    padding-left: 5px;
-  }
 
-  &-status {
-    position: absolute;
-    right: 0;
-    top: 0;
-
-    &-text {
-      background: $uni-color-primary;
-      padding: 6rpx;
-      color: white;
-      font-size: 12px;
-      border-radius: 20rpx 6rpx;
+  &_header {
+    font-size: 13px;
+    padding: 10rpx 0;
+
+    &-status {
+      font-size: 20rpx;
+      background-color: $uni-color-primary;
+      color: #fff;
+      border-radius: 6rpx;
+      padding: 6rpx 10rpx;
+      margin-left: 30rpx;
     }
   }
 
-  &-content {
-    display: flex;
-    justify-content: space-between;
-    width: 100%;
-
-    &-left {
-      flex: 1;
-      display: flex;
-      flex-direction: column;
-      padding: 5rpx;
-
-      &-label {
-        padding: 4rpx 8rpx;
-        display: inline-flex;
-        margin-top: 8rpx;
-        //justify-content: space-between;
-
-        &-left {
-          //border: 1px solid $uni-color-primary;
-          border-radius: 4rpx;
-
-          &_idle {
-            background: $uni-color-primary;
-            padding: 6rpx;
-            color: white;
-            border-radius: 4rpx;
-          }
-
-          &_count {
-            //border-radius: 4rpx;
-            margin-left: 10px;
-            color: $uni-color-primary;
-            font-size: 13px;
-          }
-
-          &_tag {
-            width: 30rpx;
-          }
-
-        }
-
-
-        &_func {
-          padding-left: 50rpx;
-          font-size: 24rpx;
-          color: #aaa;
-        }
-      }
-
-      &-position {
-        display: inline-flex;
-        font-size: 24rpx;
-        margin-top: 8rpx;
-      }
-    }
+  &_func {
 
-    &-right {
-      width: 120rpx;
-      display: flex;
-      flex-direction: column;
-      justify-content: center;
-      align-content: center;
+    &-label{
+      font-size: 24rpx;
+      color: #aaa;
     }
   }
+}
 
-  &-distance {
-    font-size: 24rpx;
-    padding-left: 5px;
-    margin-top: 8rpx;
-  }
+.scan-btn{
+  width: calc(100vw - 40rpx);
+  position: fixed;
+  bottom: 10rpx;
+  left: 20rpx;
 }
 </style>

+ 20 - 16
src/pages.json

@@ -59,7 +59,7 @@
           "path": "faq/index",
           "style": {
             "navigationStyle": "default",
-            "navigationBarTitleText": "常见问题",
+            "navigationBarTitleText": "洗车指导",
             "navigationBarBackgroundColor": "#ffffff"
           }
         },
@@ -87,6 +87,14 @@
             "navigationBarBackgroundColor": "#ffffff"
           }
         },
+        {
+          "path": "wallet/recharge",
+          "style": {
+            "navigationStyle": "default",
+            "navigationBarTitleText": "充值",
+            "navigationBarBackgroundColor": "#ffffff"
+          }
+        },
         {
           "path": "wallet/refund",
           "style": {
@@ -107,14 +115,22 @@
             "navigationBarTitleText": "网点",
             "navigationBarBackgroundColor": "#ffffff"
           }
-        }    ,
+        },
         {
-          "path": "detail/index",
+          "path": "device/index",
           "style": {
             "navigationStyle": "default",
             "navigationBarTitleText": "洗车机",
             "navigationBarBackgroundColor": "#ffffff"
           }
+        },
+        {
+          "path": "scan/index",
+          "style": {
+            "navigationStyle": "default",
+            "navigationBarTitleText": "扫码",
+            "navigationBarBackgroundColor": "#ffffff"
+          }
         }
       ]
     }
@@ -126,8 +142,6 @@
     "borderStyle": "black",
     "backgroundColor": "#ffffff",
     "fontSize": "12px",
-    "spacing": "5px",
-    "height": "60px",
     "list": [
       {
         "pagePath": "pages/index/index",
@@ -135,29 +149,19 @@
         "selectedIconPath": "static/tabbar/1-1.png",
         "text": "网点"
       },
-
       {
         "pagePath": "pages/map/index",
         "iconPath": "static/tabbar/2.png",
         "selectedIconPath": "static/tabbar/2.png",
         "text": "扫码"
       },
-
       {
         "pagePath": "pages/user/index",
         "iconPath": "static/tabbar/4.png",
         "selectedIconPath": "static/tabbar/4-1.png",
         "text": "我的"
       }
-    ],
-    "midButton": {
-      "width": "80rpx",
-      "height": "80rpx",
-      "text": "扫码",
-      "iconPath": "static/tabbar/1.png",
-      "selectedIconPath": "static/tabbar/1-1.png",
-      "iconWidth": "50rpx"
-    }
+    ]
   },
   "globalStyle": {
     "navigationBarTextStyle": "black",

+ 11 - 48
src/pages/index/index.vue

@@ -26,7 +26,7 @@
 
     <view class="menu-content w100">
       <uv-grid :border="false" :col="4">
-        <uv-grid-item v-for="(item,index) in state.menuList" :key="index">
+        <uv-grid-item v-for="(item,index) in state.menuList" :key="index" @click="handleMenuClick(item)">
           <uv-icon :customStyle="{paddingTop:20+'rpx'}" :name="item.name" :size="22"></uv-icon>
           <text class="grid-text">{{ item.title }}</text>
         </uv-grid-item>
@@ -38,56 +38,11 @@
     <!--    站点清单  start-->
     <view class="w100 content_station">
       <WashStation v-for="item in state.stationList" :key="item.id" :item="item"></WashStation>
-<!--      <view class="station_item" v-for="item in state.stationList" :key="item.id"
-            @click="handleNavStation(item)">
-        <view class="station_item-title">
-          <text class="font13">{{ item.stationName }}</text>
-        </view>
-
-        <view class="station_item-status">
-          <text class="station_item-status-text">{{ item.stationStatus == 'Normal' ? '营业中' : '暂停营业' }}</text>
-        </view>
-
-        <view class="station_item-content">
-          <view class="station_item-content-left">
-            <view class="station_item-content-left-label">
-              <view class="font12 station_item-content-left-label-left">
-                <text class="station_item-content-left-label-left_idle">空闲</text>
-                <text class="station_item-content-left-label-left_count">{{ item.parkingNum }}/{{ item.parkingNum }}</text>
-              </view>
-              &lt;!&ndash;              <uv-tags size="small" class="station_item-content-left-label_tag" text="洗车机" plain shape="circle"></uv-tags>&ndash;&gt;
-&lt;!&ndash;              <view class="station_item-content-left-label_func">{{ ['清洁', '泡沫', '吸尘', '消毒', '充电']?.join(" | ") }}</view>&ndash;&gt;
-            </view>
-            <view class="station_item-content-left-position">
-              <uv-icon name="empty-address" size="20" color="#aaa"></uv-icon>
-              <text>{{ item.address }}</text>
-            </view>
-          </view>
-          <view class="station_item-content-right">
-            <uv-button circle type="primary" size="mini" plain @click.stop="handleNavMap(item)">{{  item.distance  }}km</uv-button>
-            &lt;!&ndash;            <uv-tags text="1222km" type="warning" plain size="mini"></uv-tags>&ndash;&gt;
-          </view>
-        </view>
-
-        <view class="station_item-distance">
-          <uv-text type="primary" :text="item.parkingFee" size="12"></uv-text>
-        </view>
-      </view>-->
     </view>
     <!--    站点清单  end-->
 
-    <!--    <view class="mt10">
-          <uv-alert title="提示" type="warning" description="启动洗车机服务按钮开始洗车"></uv-alert>
-        </view>-->
-
-    <!--    <view class=" mt10 guide-content">
-          <view>
-            <uv-text size="13" shape="circle" href="#" @click="handleGotoGuide" text="查看操作指引" type="primary">查看操作指引</uv-text>
-          </view>
-        </view>-->
-
-    <login-bar class="w100 text-center loginbar"></login-bar>
-    <tab-bar :index="0"></tab-bar>
+<!--    <login-bar class="w100 text-center loginbar"></login-bar>-->
+    <tab-bar :index="0" style="height: 110rpx;"></tab-bar>
   </view>
 </template>
 
@@ -168,6 +123,14 @@ onHide(() => {
   Object.assign(state, initState());
 })
 
+const handleMenuClick = (menu:any) => {
+  if(menu.title==='洗车'){
+    uni.navigateTo({
+      url:'/pages-wash/scan/index'
+    })
+  }
+}
+
 /**
  * 获取当前的地理位置
  */

+ 52 - 30
src/pages/user/index.vue

@@ -14,15 +14,14 @@
         <view class="main flex-shrink">
           <view
               class="avatar"
-              @click="toPage(2)"
               :style="{
-              'background-image': `url(${user.avatar})`,
+              'background-image': `url('/static/user.png')`,
             }"></view>
-          <view class="phone fs-40 fw-500">{{ user.mobilePhoneFormat }}</view>
+          <view class="phone fs-40 fw-500">{{ user.mobilePhone }}</view>
 
           <view class="money" @click="toPage({path: '/pages-user/wallet/index'})">
             <uv-icon name="red-packet" size="24"></uv-icon>
-            <view>¥{{ user.balance }}</view>
+            <view>¥{{ (user.balance||0).toFixed(2) }}</view>
           </view>
         </view>
       </view>
@@ -44,7 +43,11 @@
       </view>
     </view>
   </block>
-<!--  <login-bar class="w100 text-center"></login-bar>-->
+
+  <cover-view class="login_bar">
+    <login-bar class="w100 text-center"></login-bar>
+  </cover-view>
+
   <tab-bar :index="2"/>
 </template>
 
@@ -53,35 +56,38 @@ import {onLoad, onShow} from "@dcloudio/uni-app";
 import {ref} from "vue";
 import TabBar from "@/components/tab-bar/index.vue";
 import LoginBar from "@/components/login-bar/index.vue";
+import {checkLogin} from "@/utils/auth"
 
 const containerStyle = ref({});
 const user = ref<any>({
+  id: 0,
   avatar: "",
-  mobilePhoneFormat: '15012341234',
-  balance: '2345.67',
+  mobilePhoneFormat: '',
+  balance: 0,
 });
+const isLogin = ref(false)
 const service = ref("15012341234");
 const menu = ref([
   {
-    title: "个人信息",
+    title: "绑定车辆",
     path: "/pages-user/profile/index",
     icon: '/static/user/profile.png'
   },
+  /*  {
+      title: "我的卡包",
+      path: "/pages/coupon/index",
+      icon: '/static/user/coupon.png'
+    },*/
   {
-    title: "我的卡包",
-    path: "/pages/coupon/index",
-    icon: '/static/user/coupon.png'
-  },
-  {
-    title: "洗车订单",
+    title: "我的订单",
     path: "/pages/order/index",
     icon: '/static/user/order.png'
   },
-  {
-    title: "我的收藏",
-    path: "/pages-user/fav/index",
-    icon: '/static/user/fav.png'
-  },
+  /*  {
+      title: "我的收藏",
+      path: "/pages-user/fav/index",
+      icon: '/static/user/fav.png'
+    },*/
 
   {
     title: "联系我们",
@@ -89,7 +95,7 @@ const menu = ref([
     icon: '/static/user/contact.png'
   },
   {
-    title: "常见问题",
+    title: "洗车指导",
     path: "/pages-user/faq/index",
     icon: '/static/user/faq.png'
   },
@@ -99,7 +105,10 @@ const menu = ref([
     icon: '/static/user/feedback.png'
   },
 ]);
-const toPage = (item: any) => {
+
+
+const toPage = async (item: any) => {
+  // let checkUser = await checkLogin();
   let {title, path} = item;
   if (path.includes('contact')) {
     uni.makePhoneCall({
@@ -119,6 +128,18 @@ const toPage = (item: any) => {
   });
 };
 
+const loginListen = () => {
+
+  uni.$on('loginEvent', function (data) {
+    isLogin.value = data.isLogin;
+    console.log("event>>>",data)
+    if (data.isLogin) {
+      user.value = getApp<any>().globalData.user;
+      console.log("event1111>>>", user.value )
+    }
+  })
+}
+
 onLoad(() => {
   uni.setNavigationBarTitle({title: '个人中心'})
   const bound = uni.getMenuButtonBoundingClientRect();
@@ -130,16 +151,17 @@ onLoad(() => {
   //     service.value = res.mobile;
   //   }
   // });
+  // loginListen();
 });
+
+
 onShow(() => {
-  // fetchProfile().then((res) => {
-  //   res.mobilePhoneFormat =
-  //       res.mobilePhone.slice(0, 3) + "****" + res.mobilePhone.slice(7);
-  //   res.avatar = res.avatar
-  //       ? res.avatar
-  //       : "https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQP6yfMxBgJ0F3YRqJCJ1aPAK2dQagdusBZg/0";
-  //   user.value = res;
-  // });
+  const user = getApp<any>().globalData.user;
+  if (user) {
+    isLogin.value = true;
+    user.value = user;
+  }
+  loginListen();
 });
 </script>
 
@@ -149,7 +171,7 @@ onShow(() => {
   left: 0;
   top: 0;
   width: 100%;
-  height: 660rpx;
+  height: 460rpx;
 }
 
 .container {

BIN=BIN
src/static/mock/zhuti.jpg


BIN=BIN
src/static/nav.png


BIN=BIN
src/static/scan/scan-code-album.png


BIN=BIN
src/static/scan/scan-code-input.png


BIN=BIN
src/static/scan/scan-code-light.png


BIN=BIN
src/static/tabbar/2-1.png


BIN=BIN
src/static/user.png


BIN=BIN
src/static/wallet-card.png


+ 1 - 1
src/uni.scss

@@ -17,7 +17,7 @@
 @import '@climblee/uv-ui/theme.scss';
 
 /* 行为相关颜色 */
-$uni-color-primary: #007aff;
+$uni-color-primary: #19A497;
 $uni-color-success: #4cd964;
 $uni-color-warning: #f0ad4e;
 $uni-color-error: #dd524d;

+ 154 - 133
src/utils/auth.ts

@@ -1,167 +1,188 @@
-import Storage from "../utils/storage";
 import {body, get} from "@/utils/https";
 
-const _tokenStorage = new Storage("AUTH");
-
 const _tokenQueue: {
-  pending: boolean;
-  list: {
-    resolve: (value: string) => void;
-    reject: (err: any) => void;
-  }[];
+    pending: boolean;
+    list: {
+        resolve: (value: string) => void;
+        reject: (err: any) => void;
+    }[];
 } = {
-  pending: false,
-  list: [],
+    pending: false,
+    list: [],
 };
 
 let _onTokenListener: {
-  cb: (token: string) => void;
+    cb: (token: string) => void;
 }[] = [];
 
 const _resolveTokenQueue = function (res: any) {
-  _tokenQueue.pending = false;
-  uni.hideLoading();
-  if (res.errMsg) {
-    console.log(res);
-    uni.showModal({
-      title: "登录失败",
-      content: `${res.errMsg}`,
-    });
-    _tokenQueue.list.forEach((item) => {
-      item.reject(res);
-    });
-  } else {
-    uni.showToast({
-      icon: "success",
-      title: "登录成功",
-    });
-    setToken(res as string);
-    _onTokenListener.forEach((item) => {
-      item.cb(res as string);
-    });
-    _tokenQueue.list.forEach((item) => {
-      item.resolve(res as string);
-    });
-  }
-  _onTokenListener = [];
-  _tokenQueue.list = [];
+    _tokenQueue.pending = false;
+    uni.hideLoading();
+    if (res.errMsg) {
+        console.log(res);
+        uni.showModal({
+            title: "登录失败",
+            content: `${res.errMsg}`,
+        });
+        _tokenQueue.list.forEach((item) => {
+            item.reject(res);
+        });
+    } else {
+        uni.showToast({
+            icon: "success",
+            title: "登录成功",
+        });
+        setToken(res as string);
+        _onTokenListener.forEach((item) => {
+            item.cb(res as string);
+        });
+        _tokenQueue.list.forEach((item) => {
+            item.resolve(res as string);
+        });
+    }
+    _onTokenListener = [];
+    _tokenQueue.list = [];
 };
 
 export function login(e: any): Promise<string> {
-  return new Promise((resolve, reject) => {
-    if (/deny|cancel/.test(e.errMsg)) {
-      reject();
-      return;
-    }
-    if (!e.code) {
-      uni.showModal({
-        title: `${e.errMsg},请重试`,
-      });
-      reject();
-      return;
-    }
-    _tokenQueue.list.push({
-      resolve,
-      reject,
-    });
-    if (_tokenQueue.pending) {
-      return;
-    }
-    _tokenQueue.pending = true;
-    uni.showLoading({
-      title: "登录中",
-      mask: true,
-    });
-    uni.login({
-      success: (res) => {
-        let data = {
-          phoneCode: e.code,
-          code: res.code,
-          avatar: "",
-          nickname: "",
+    return new Promise((resolve, reject) => {
+        if (/deny|cancel/.test(e.errMsg)) {
+            reject();
+            return;
         }
-        body(`/user/wxLogin`,data).then((res:any)=>{
-          const { statusCode, data } = res;
-          if (
-              statusCode === 200 &&
-              data &&
-              data.message === "ok" &&
-              data.code === 200
-          ) {
-            _resolveTokenQueue(data.data.satoken);
-          } else {
-            _resolveTokenQueue({
-              errMsg: data.msg ? data.msg : `${JSON.stringify(res)}`,
+        if (!e.code) {
+            uni.showModal({
+                title: `${e.errMsg},请重试`,
             });
-          }
-        }).catch(e=>{
-          _resolveTokenQueue({})
-        })
-      },
-      fail: _resolveTokenQueue,
+            reject();
+            return;
+        }
+        _tokenQueue.list.push({
+            resolve,
+            reject,
+        });
+        if (_tokenQueue.pending) {
+            return;
+        }
+        _tokenQueue.pending = true;
+        uni.showLoading({
+            title: "登录中",
+            mask: true,
+        });
+        uni.login({
+            success: (res) => {
+                let data = {
+                    phoneCode: e.code,
+                    code: res.code,
+                    avatar: "",
+                    nickname: "",
+                }
+                body(`/user/wxLogin`, data).then((res: any) => {
+                    const {satoken, userId} = res;
+                    if (satoken) {
+                        _resolveTokenQueue(satoken);
+                        setToken(satoken);
+                        loadUserInfo();
+                 
+                    } else {
+                        _resolveTokenQueue({
+                            errMsg:  `${JSON.stringify(res)}`,
+                        });
+                    }
+                }).catch(e => {
+                    _resolveTokenQueue({})
+                })
+            },
+            fail: _resolveTokenQueue,
+        });
     });
-  });
+}
+
+
+export function checkLogin() {
+    return new Promise((resolve, reject) => {
+        let user = getApp<any>().globalData.user;
+        if (!user) {
+            uni.showToast({
+                icon: "none",
+                title: "请先登录",
+            });
+            reject();
+        } else {
+            resolve(user);
+        }
+    })
+}
+
+function loadUserInfo() {
+    get(`/user/me`).then((res: any) => {
+        console.log("userIfnop", res)
+        getApp<any>().globalData.user = res;
+        uni.$emit('loginEvent', {isLogin: true})
+    })
 }
 
 export function refresh(): Promise<string> {
-  return new Promise((resolve, reject) => {
-    _tokenStorage.get("token").then((token) => {
-      if (!token) {
-        clearToken();
-        reject({
-          errMsg: "请登录",
-        });
-        uni.reLaunch({
-          url: "/pages/map/index",
-        });
-      } else {
-        getApp<any>().globalData.token = "";
-        _tokenStorage.clear("token");
-        get(`/user/refresh`).then((res:any)=>{
-          console.log("refresh返回", res);
-          const { statusCode, data } = res;
-          if (
-              statusCode === 200 &&
-              data &&
-              data.msg === "OK" &&
-              data.code === 200
-          ) {
-            resolve(data.data.access_token);
-          } else {
-            if (data.code === 21005) {
-              uni.reLaunch({
-                url: "/pages/map/index",
-              });
+    return new Promise((resolve, reject) => {
+        uni.getStorage({key:"token"}).then((token) => {
+            if (!token) {
+                clearToken();
+                reject({
+                    errMsg: "请登录",
+                });
+                uni.reLaunch({
+                    url: "/pages/map/index",
+                });
+            } else {
+                getApp<any>().globalData.token = "";
+                uni.removeStorageSync("token");
+                get(`/user/refresh`).then((res: any) => {
+                    console.log("refresh返回", res);
+                    const {statusCode, data} = res;
+                    if (
+                        statusCode === 200 &&
+                        data &&
+                        data.msg === "OK" &&
+                        data.code === 200
+                    ) {
+                        resolve(data.data.access_token);
+                    } else {
+                        if (data.code === 21005) {
+                            uni.reLaunch({
+                                url: "/pages/map/index",
+                            });
+                        }
+                        reject({
+                            errMsg: `${JSON.stringify(res)}`,
+                        });
+                    }
+                }).catch(() => {
+                    reject()
+                })
             }
-            reject({
-              errMsg: `${JSON.stringify(res)}`,
-            });
-          }
-        }).catch(()=>{
-          reject()
-        })
-      }
+        });
     });
-  });
 }
 
 export function onLogin(cb: (token: string) => void) {
-  _onTokenListener.push({
-    cb,
-  });
+    _onTokenListener.push({
+        cb,
+    });
 }
 
 export function fetchToken() {
-  return _tokenStorage.get("token");
+    let token = uni.getStorageSync("token")
+    console.log("fetchToken1", token)
+    return token;
 }
 
 export function setToken(token: string) {
-  getApp<any>().globalData.token = token;
-  getApp<any>().globalData.isLogin = true;
-  return _tokenStorage.set("token", token);
+    getApp<any>().globalData.token = token;
+    getApp<any>().globalData.isLogin = true;
+    uni.setStorageSync("token", token)
 }
 
 export function clearToken() {
-  getApp<any>().globalData.token = "";
-  return _tokenStorage.clear("token");
+    getApp<any>().globalData.token = "";
+    uni.removeStorageSync("token")
 }

+ 28 - 0
src/utils/common.ts

@@ -52,3 +52,31 @@ export function calcMapDistance(lat1: number, lng1: number, lat2: number, lng2:
     s = Math.round(s * 10000) / 10000;
     return s.toFixed(2);
 }
+
+export function groupByKey(elements: Array<any>, key: string) {
+    return elements.reduce((groups, item) => {
+        const groupKey = item[key];
+        if (!groups[groupKey]) {
+            groups[groupKey] = [];
+        }
+        groups[groupKey].push(item);
+        return groups;
+    }, {});
+}
+
+export function getDictName(code:string, value: string) {
+    let dictStorage:any = uni.getStorageSync('dict');
+    console.log(dictStorage)
+    if(!dictStorage){
+        return value;
+    }
+
+    let elements = dictStorage[code];
+    if(elements){
+        let ele = elements.find((k: any)=>k.value===value);
+        if(ele){
+            return ele.name;
+        }
+    }
+    return value;
+}

+ 4 - 3
src/utils/https.ts

@@ -53,6 +53,7 @@ const isEmptyOrNull = function (exp: any) {
  */
 const get = (url: string, param = {}) => {
     let token = fetchToken() || ""
+    console.log("request,token",token)
     if (!isEmptyOrNull(param)) {
         let params = [];
         for (let key in param) {
@@ -68,7 +69,7 @@ const get = (url: string, param = {}) => {
         header: {
             "Accept": "application/json",
             "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
-            "token": token,
+            "satoken": token,
         },
     };
     return request(options)
@@ -84,7 +85,7 @@ const post = (url: string, param = {}) => {
         header: {
             'X-Requested-With': 'XMLHttpRequest',
             "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8;",
-            "token": token,
+            "satoken": token,
         },
         dataType: 'json'
     };
@@ -102,7 +103,7 @@ const body = (url: string, param = {}) => {
             'X-Requested-With': 'XMLHttpRequest',
             "Accept": "application/json",
             "Content-Type": "application/json; charset=UTF-8",
-            "token": token,
+            "satoken": token,
         },
         dataType: 'json'
     };

+ 45 - 0
src/utils/navigate.ts

@@ -0,0 +1,45 @@
+export function to(path: string) {
+  console.log(path)
+  if (nextPageIsPrevPage(path)) {
+    uni.navigateBack();
+    return;
+  }
+
+  uni.navigateTo({
+    url: path,
+  });
+}
+
+export function back() {
+  uni.navigateBack();
+}
+
+export function redirect(url: string) {
+  uni.redirectTo({
+    url,
+  });
+}
+
+export function reLaunch() {
+  uni.reLaunch({
+    url: "/pages/map/map",
+  });
+}
+
+export function nextPageIsPrevPage(path: string): boolean {
+  const isFull = path[0] === "/";
+  const pages = getCurrentPages();
+  const prevPage = pages.length >= 2 ? pages[pages.length - 2] : undefined;
+  const prevPageQuery = prevPage
+    ? Object.keys(prevPage.options)
+        .map((key) => `${key}=${prevPage.options[key]}`)
+        .join("&")
+    : "";
+  if (prevPage) {
+    return (
+      `${prevPage.route}${prevPageQuery ? "?" + prevPageQuery : ""}` ===
+      (isFull ? path.substring(1) : path)
+    );
+  }
+  return false;
+}

+ 0 - 112
src/utils/storage.ts

@@ -1,112 +0,0 @@
-class Storage {
-  private namespace: string
-
-  constructor(namespace?: string) {
-    this.namespace = `CHONGDIAN_${namespace || 'DEFAULT'}`
-  }
-
-  set<T = any>(key: string, data: T, expire?: number): Promise<void> {
-    const now = new Date().getTime()
-    const _d = {
-      data,
-      expire: expire ? now + expire : 0
-    }
-    return new Promise((resolve, reject) => {
-      uni.setStorage({
-        key: `${this.namespace}_${key}`,
-        data: JSON.stringify(_d),
-        success() {
-          resolve()
-        },
-        fail(err) {
-          reject(err)
-        }
-      })
-    })
-  }
-
-  get<T = any>(key: string, defaultValue?: T): Promise<T | undefined> {
-    return new Promise(resolve => {
-      const _key = `${this.namespace}_${key}`
-      uni.getStorage({
-        key: _key,
-        success(res) {
-          if (res && res.data) {
-            try {
-              const data = JSON.parse(res.data)
-              if (!data.expire) {
-                resolve(data.data)
-                return
-              }
-              const now = new Date().getTime()
-              if (now <= data.expire) {
-                resolve(data.data)
-                return
-              }
-            } catch (error) {
-              // eslint-disable-next-line no-console
-              console.log(error)
-            }
-          }
-          uni.removeStorage({
-            key: _key
-          })
-          resolve(defaultValue ? defaultValue : undefined)
-        },
-        fail(err) {
-          resolve(defaultValue ? defaultValue : undefined)
-          return err
-        }
-      })
-    })
-  }
-
-  clear(key?: string): Promise<void> {
-    if (key) {
-      const _key = `${this.namespace}_${key}`
-      return this.rm(_key)
-    }
-    return new Promise((resolve, reject) => {
-      uni.getStorageInfo({
-        success: res => {
-          if (res.keys && res.keys.length) {
-            const reg = new RegExp(`^${this.namespace.replace(/\^/gi, '\\^')}.+`)
-            const ps: Promise<void>[] = []
-            res.keys.forEach(key => {
-              if (reg.test(key)) {
-                ps.push(this.rm(key))
-              }
-            })
-            Promise.all(ps)
-              .then(() => {
-                resolve()
-                return true
-              })
-              .catch(reject)
-            return
-          }
-          resolve()
-        },
-        fail: err => {
-          reject(err)
-        }
-      })
-    })
-  }
-
-  private rm(key: string): Promise<void> {
-    return new Promise((resolve, reject) => {
-      uni.removeStorage({
-        key,
-        success() {
-          resolve()
-        },
-        fail(err) {
-          reject(err)
-        }
-      })
-    })
-  }
-}
-
-export default Storage