zuy 1 год назад
Родитель
Сommit
57753dd0cb

+ 19 - 7
src/components/tab-bar/index.vue

@@ -1,14 +1,26 @@
 <template>
-  <uv-tabbar :value="value" @change="index=>value = index" :border="false"  :fixed="true">
-    <uv-tabbar-item text="首页" icon="home"></uv-tabbar-item>
-    <uv-tabbar-item text="优惠" icon="photo"></uv-tabbar-item>
-    <uv-tabbar-item text="" icon="scan" :iconSize="40"></uv-tabbar-item>
-    <uv-tabbar-item text="订单" icon="play-right"></uv-tabbar-item>
-    <uv-tabbar-item text="我的" icon="account"></uv-tabbar-item>
+  <uv-tabbar :value="value" @change="index=>value = index" :border="false" :fixed="true">
+    <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')"></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>
 </template>
 <script setup lang="ts" name="TabBar">
-import { ref } from 'vue'
+import {ref} from 'vue'
+
 const value = ref(0)
 
+const handleTabbarClick = (tab: string) => {
+  uni.switchTab({
+    url: `/pages/${tab}/index`,
+    success: (e: any) => {
+      console.log("tabbar switch>>>>", e)
+    },
+    fail: (e: any) => {
+      console.error("swtich error >>>>>", JSON.stringify(e))
+    }
+  })
+}
 </script>

+ 79 - 35
src/pages.json

@@ -5,73 +5,117 @@
       "^uv-(.*)": "@climblee/uv-ui/components/uv-$1/uv-$1.vue"
     }
   },
-  //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
   "pages": [
     {
       "path": "pages/index/index",
       "style": {
-        "navigationBarTitleText": "uni-app"
+        "navigationBarTitleText": "Car-Wash"
       }
     },
     {
       "path": "pages/coupon/index",
       "style": {
-        "disableScroll": true
+        "disableScroll": true,
+        "navigationBarTitleText": "卡券中心"
       }
     },
     {
       "path": "pages/map/index",
       "style": {
-        "disableScroll": true
+        "disableScroll": true,
+        "navigationBarTitleText": "站点地图"
       }
     },
     {
-      "path": "pages/order/index"
+      "path": "pages/order/index",
+      "navigationBarTitleText": "订单中心"
     },
     {
-      "path": "pages/user/index"
+      "path": "pages/user/index",
+      "navigationBarTitleText": "个人中心"
     }
   ],
-  "subPackages": [{
-    "root": "pages-common/",
-    "pages": [
-      {
-        "path": "profile/index",
-        "style": {
-          "navigationStyle": "default",
-          "navigationBarTitleText": "我的信息",
-          "navigationBarBackgroundColor": "#ffffff"
+  "subPackages": [
+    {
+      "root": "pages/z-common",
+      "pages": [
+        {
+          "path": "profile/index",
+          "style": {
+            "navigationStyle": "default",
+            "navigationBarTitleText": "我的信息",
+            "navigationBarBackgroundColor": "#ffffff"
+          }
+        },
+        {
+          "path": "contact/index",
+          "style": {
+            "navigationStyle": "default",
+            "navigationBarTitleText": "联系我们",
+            "navigationBarBackgroundColor": "#ffffff"
+          }
+        },
+        {
+          "path": "faq/index",
+          "style": {
+            "navigationStyle": "default",
+            "navigationBarTitleText": "常见问题",
+            "navigationBarBackgroundColor": "#ffffff"
+          }
+        },
+        {
+          "path": "fav/index",
+          "style": {
+            "navigationStyle": "default",
+            "navigationBarTitleText": "我的收藏",
+            "navigationBarBackgroundColor": "#ffffff"
+          }
         }
+      ]
+    }
+  ],
+  "tabBar": {
+    "color": "#7A7E83",
+    "selectedColor": "#3cc51f",
+    "borderStyle": "black",
+    "backgroundColor": "#ffffff",
+    "backgroundImage": "static/tabbar/bg.png",
+    "list": [
+      {
+        "pagePath": "pages/index/index",
+        "iconPath": "static/tabbar/1.png",
+        "selectedIconPath": "static/tabbar/1-1.png",
+        "text": "首页"
       },
       {
-        "path": "contact/index",
-        "style": {
-          "navigationStyle": "default",
-          "navigationBarTitleText": "联系我们",
-          "navigationBarBackgroundColor": "#ffffff"
-        }
+        "pagePath": "pages/coupon/index",
+        "iconPath": "static/tabbar/1.png",
+        "selectedIconPath": "static/tabbar/1-1.png",
+        "text": "优惠"
       },
       {
-        "path": "faq/index",
-        "style": {
-          "navigationStyle": "default",
-          "navigationBarTitleText": "常见问题",
-          "navigationBarBackgroundColor": "#ffffff"
-        }
+        "pagePath": "pages/map/index",
+        "iconPath": "static/tabbar/2.png",
+        "selectedIconPath": "static/tabbar/2.png",
+        "text": "站点"
       },
       {
-        "path": "fav/index",
-        "style": {
-          "navigationStyle": "default",
-          "navigationBarTitleText": "我的收藏",
-          "navigationBarBackgroundColor": "#ffffff"
-        }
+        "pagePath": "pages/order/index",
+        "iconPath": "static/tabbar/3.png",
+        "selectedIconPath": "static/tabbar/3-1.png",
+        "text": "订单"
+      },
+      {
+        "pagePath": "pages/user/index",
+        "iconPath": "static/tabbar/4.png",
+        "selectedIconPath": "static/tabbar/4-1.png",
+        "text": "我的"
       }
     ]
-  }],
+  },
   "globalStyle": {
     "navigationBarTextStyle": "black",
-    "navigationBarTitleText": "uni-app",
+    "navigationBarTitleText": "洗车",
     "navigationBarBackgroundColor": "#F8F8F8",
     "backgroundColor": "#F8F8F8"
   }

+ 121 - 12
src/pages/index/index.vue

@@ -1,33 +1,125 @@
 <template>
   <view class="content">
-    <image class="logo" src="/static/logo.png"/>
-    <view class="text-area">
-      <text class="title">{{ title }}</text>
+    <!--    <image class="logo" src="/static/logo.png"/>
+        <view class="text-area">
+          <text class="title">{{ title }}</text>
+        </view>-->
+    <view style="width: 100%;" class="swiper-content">
+      <uv-swiper
+          class="swiper-item-1"
+          style="width: 100%"
+          :list="state.swiperList"
+          previousMargin="30"
+          nextMargin="30"
+          circular
+          :autoplay="true"
+          radius="5"
+          bgColor="#ffffff">
+      </uv-swiper>
     </view>
-    <uv-button type="primary" text="确定"></uv-button>
-    <uv-calendars insert @change="change"/>
-    <uv-image src="https://cdn.uviewui.com/uview/album/1.jpg" mode="widthFix"></uv-image>
-    <uv-qrcode ref="qrcode" size="300px" value="https://h5.uvui.cn"></uv-qrcode>
-    <uv-switch v-model="open" loading></uv-switch>
+    <uv-line color="#2979ff"></uv-line>
+    <uv-divider :dashed="true"></uv-divider>
 
-    <tab-bar></tab-bar>
+    <view class="menu-content w100">
+      <uv-grid :border="false" :col="3">
+        <uv-grid-item v-for="(item,index) in state.menuList" :key="index">
+          <uv-icon :customStyle="{paddingTop:20+'rpx'}" :name="item.name" :size="22"></uv-icon>
+          <text class="grid-text">{{ item.title }}</text>
+        </uv-grid-item>
+      </uv-grid>
+    </view>
+
+    <view class="qrcode-content">
+      <uv-qrcode ref="qrcode_ref" value="https://h5.uvui.cn" :options="state.qrcodeOption"></uv-qrcode>
+      <uv-button size="large" :custom-style="state.customStyle" text="扫码洗车"
+                 color="linear-gradient(to right, rgb(66, 83, 216), rgb(213, 51, 186))"></uv-button>
+
+    </view>
+
+    <view>
+      <uv-alert title="提示" type="warning" description="将二维码置于洗车机扫描口启动洗车"></uv-alert>
+    </view>
+
+
+    <!--    <uv-button type="primary" text="确定"></uv-button>
+        <uv-calendars insert @change="change"/>
+        <uv-image src="https://cdn.uviewui.com/uview/album/1.jpg" mode="widthFix"></uv-image>
+        <uv-qrcode ref="qrcode" size="300px" value="https://h5.uvui.cn"></uv-qrcode>
+        <uv-switch v-model="open" loading></uv-switch>-->
+
+    <!--    <tab-bar></tab-bar>-->
   </view>
 </template>
 
 <script setup lang="ts">
-import {ref} from 'vue'
-import TabBar from "@/components/tab-bar";
+import {reactive, ref} from 'vue'
+import {onHide, onShow} from "@dcloudio/uni-app";
 
 const title = ref('Hello')
-const open = ref(false)
+const qrcode_ref = ref()
 
 const change = () => {
   console.log("change")
 }
+
+const initState = () => ({
+  swiperList: [
+    'https://cdn.uviewui.com/uview/swiper/swiper3.png',
+    'https://cdn.uviewui.com/uview/swiper/swiper2.png',
+    'https://cdn.uviewui.com/uview/swiper/swiper1.png'
+  ],
+  menuList: [
+    {name: "photo", title: "洗车"},
+    {name: "lock", title: "充值"},
+    {name: "star", title: "卡券"},
+  ],
+  qrcodeOption: {
+    style: 'round',
+    // 指定二维码前景,一般可在中间放logo
+    foregroundImageSrc: 'https://www.uvui.cn/common/logo.png'
+  },
+  customStyle: {
+    'margin-top': '40rpx',
+    height: '80rpx',
+    width: '80%',
+    borderRadius: '40rpx',//圆角
+    // nvue中必须是下方的写法
+    'border-top-right-radius': '40rpx',
+    'border-bottom-left-radius': '40rpx',
+    'border-bottom-right-radius': '40rpx'
+  }
+})
+
+const state = reactive(initState())
+
+onShow(() => {
+  let gd = getApp<any>().globalData;
+  if (!gd.token) {
+    console.log(gd)
+  }
+  setInterval(()=>refreshQrcode(), 10000)
+});
+
+onHide(() => {
+  Object.assign(state, initState());
+})
+
+const refreshQrcode = () => {
+  qrcode_ref.value?.remake({
+    success: () => {
+      console.log("success")
+    },
+    fail: () => {
+      console.log("fail")
+    }
+  })
+}
+
 </script>
 
 <style>
 .content {
+  width: 100%;
   display: flex;
   flex-direction: column;
   align-items: center;
@@ -52,4 +144,21 @@ const change = () => {
   font-size: 36rpx;
   color: #8f8f94;
 }
+
+.menu-content {
+  width: 100%;
+  margin-top: 40rpx;
+  padding: 0 20rpx;
+}
+
+.qrcode-content {
+  margin-top: 40rpx;
+  padding: 0 20rpx;
+  width: 100%;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  align-content: center;
+  justify-content: center;
+}
 </style>

+ 3 - 0
src/pages/user/index.vue

@@ -9,11 +9,14 @@
     <uv-image src="https://cdn.uviewui.com/uview/album/1.jpg" mode="widthFix"></uv-image>
     <uv-qrcode ref="qrcode" size="300px" value="https://h5.uvui.cn"></uv-qrcode>
     <uv-switch v-model="open" loading></uv-switch>
+
+<!--    <tab-bar></tab-bar>-->
   </view>
 </template>
 
 <script setup lang="ts">
 import { ref } from 'vue'
+// import TabBar from "@/components/tab-bar";
 const title = ref('Hello')
 const open = ref(false)
 

+ 0 - 0
src/pages-common/account/index.vue → src/pages/z-common/account/index.vue


+ 0 - 0
src/pages-common/contact/index.vue → src/pages/z-common/contact/index.vue


+ 0 - 0
src/pages-common/faq/index.vue → src/pages/z-common/faq/index.vue


+ 0 - 0
src/pages-common/fav/index.vue → src/pages/z-common/fav/index.vue


+ 0 - 0
src/pages-common/profile/index.vue → src/pages/z-common/profile/index.vue


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


BIN
src/static/tabbar/1.png


BIN
src/static/tabbar/2.png


BIN
src/static/tabbar/3-1.png


BIN
src/static/tabbar/3.png


BIN
src/static/tabbar/4-1.png


BIN
src/static/tabbar/4.png


BIN
src/static/tabbar/bg.png


+ 148 - 1
src/uni.scss

@@ -75,4 +75,151 @@ $uni-font-size-title: 20px;
 $uni-color-subtitle: #555; // 二级标题颜色
 $uni-font-size-subtitle: 18px;
 $uni-color-paragraph: #3f536e; // 文章段落颜色
-$uni-font-size-paragraph: 15px;
+$uni-font-size-paragraph: 15px;
+
+///* flex布局 */
+.flex {
+  display: flex;
+}
+
+.flex-inline {
+  display: inline-flex;
+}
+
+
+.flex-auto {
+  flex: 1;
+  overflow: hidden;
+}
+
+.flex-center {
+  @extend .flex;
+  flex-direction: column;
+  width: 100%;
+  overflow: hidden;
+}
+
+.flex-margin {
+  margin: auto;
+}
+
+.flex-warp {
+  display: flex;
+  flex-wrap: wrap;
+  align-content: flex-start;
+  margin: 0 -5px;
+
+  .flex-warp-item {
+    padding: 5px;
+
+    .flex-warp-item-box {
+      width: 100%;
+      height: 100%;
+    }
+  }
+}
+
+.flex-just-between {
+  justify-content: space-between;
+}
+
+.flex-just-around {
+  justify-content: space-around;
+}
+
+.flex-justify-center {
+  justify-content: center;
+}
+
+.flex-align-items-center {
+  align-items: center;
+  align-content: center;
+}
+
+.flex-just-end {
+  justify-content: flex-end;
+}
+
+
+@for $i from 0 through 30 {
+  .wd#{100+$i*10} {
+    width: #{100+$i*10}px !important;
+  }
+}
+
+
+.w50 {
+  width: 50% !important;
+}
+
+.w100 {
+  width: 100% !important;
+}
+
+.h100 {
+  height: 100% !important;
+}
+
+.vh100 {
+  height: 100vh !important;
+}
+
+
+/* 字体大小全局样式
+------------------------------- */
+@for $i from 10 through 32 {
+  .font#{$i} {
+    font-size: #{$i}px !important;
+  }
+}
+
+/* 外边距、内边距全局样式
+------------------------------- */
+@for $i from 1 through 35 {
+  .mt#{$i} {
+    margin-top: #{$i}px !important;
+  }
+  .mr#{$i} {
+    margin-right: #{$i}px !important;
+  }
+  .mb#{$i} {
+    margin-bottom: #{$i}px !important;
+  }
+  .ml#{$i} {
+    margin-left: #{$i}px !important;
+  }
+  .pt#{$i} {
+    padding-top: #{$i}px !important;
+  }
+  .pr#{$i} {
+    padding-right: #{$i}px !important;
+  }
+  .pb#{$i} {
+    padding-bottom: #{$i}px !important;
+  }
+  .pl#{$i} {
+    padding-left: #{$i}px !important;
+  }
+  .pv#{$i} {
+    padding: #{$i}px auto !important;
+  }
+
+  .ph#{$i} {
+    padding: auto #{$i}px !important;
+  }
+
+  .pd#{$i} {
+    padding: #{$i}px !important;
+  }
+
+  .mv#{$i} {
+    margin: #{$i}px auto !important;
+  }
+
+  .mh#{$i} {
+    margin: auto #{$i}px !important;
+  }
+  .mg#{$i} {
+    margin: #{$i}px #{$i}px !important;
+  }
+}

+ 177 - 0
src/utils/auth.ts

@@ -0,0 +1,177 @@
+import { host } from "../utils/constant";
+import Storage from "../utils/storage";
+
+const _tokenStorage = new Storage("AUTH");
+
+const _tokenQueue: {
+  pending: boolean;
+  list: {
+    resolve: (value: string) => void;
+    reject: (err: any) => void;
+  }[];
+} = {
+  pending: false,
+  list: [],
+};
+
+let _onTokenListener: {
+  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 = [];
+};
+
+export function login(e: any): Promise<string> {
+  return new Promise((resolve, reject) => {
+    if (/deny|cancel/.test(e.detail.errMsg)) {
+      reject();
+      return;
+    }
+    if (!e.detail.code) {
+      uni.showModal({
+        title: `${e.detail.errMsg},请重试`,
+      });
+      reject();
+      return;
+    }
+    _tokenQueue.list.push({
+      resolve,
+      reject,
+    });
+    if (_tokenQueue.pending) {
+      return;
+    }
+    _tokenQueue.pending = true;
+    uni.showLoading({
+      title: "登录中",
+      mask: true,
+    });
+    uni.login({
+      success: (res) => {
+        uni.request<any>({
+          url: `${host}/user/wxLogin`,
+          method: "POST",
+          dataType: "json",
+          data: {
+            phoneCode: e.detail.code,
+            code: res.code,
+            avatar: "",
+            nickname: "",
+          },
+          success: (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)}`,
+              });
+            }
+          },
+          fail: _resolveTokenQueue,
+        });
+      },
+      fail: _resolveTokenQueue,
+    });
+  });
+}
+
+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/map",
+        });
+      } else {
+        getApp<any>().globalData.token = "";
+        _tokenStorage.clear("token");
+        uni.request({
+          url: `${host}/user/refresh`,
+          method: "GET",
+          dataType: "json",
+          header: {
+            Authorization: token,
+          },
+          success: (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/map",
+                });
+              }
+              reject({
+                errMsg: `${JSON.stringify(res)}`,
+              });
+            }
+          },
+          fail: reject,
+        });
+      }
+    });
+  });
+}
+
+export function onLogin(cb: (token: string) => void) {
+  _onTokenListener.push({
+    cb,
+  });
+}
+
+export function fetchToken() {
+  return _tokenStorage.get("token");
+}
+
+export function setToken(token: string) {
+  getApp<any>().globalData.token = token;
+  return _tokenStorage.set("token", token);
+}
+
+export function clearToken() {
+  getApp<any>().globalData.token = "";
+  return _tokenStorage.clear("token");
+}

+ 2 - 24
src/utils/https.ts

@@ -1,3 +1,4 @@
+// @ts-ignore
 const env = process?.env.NODE_ENV === "development" ? "dev" : "prd";
 let apis = {
     dev: {
@@ -15,7 +16,7 @@ let apis = {
 };
 const cfg = {
     key: {
-        token: 'npt.token'
+        token: 'wash.token'
     },
     env: env,
     api: {
@@ -28,29 +29,6 @@ const cfg = {
 const serverUrl = cfg.api.serverUrl;
 const fileUrl = cfg.api.fileUrl;
 
-let source = -1;
-// #ifdef APP-PLUS
-source = 5;
-// #endif
-// #ifdef H5
-source = 3;
-// #endif
-// #ifdef MP-WEIXIN
-source = 2;
-// #endif
-// #ifdef MP-ALIPAY
-source = 7;
-// #endif
-// #ifdef MP-BAIDU
-source = 6;
-// #endif
-// #ifdef MP-QQ
-source = 9;
-// #endif
-// #ifdef MP-TOUTIAO
-source = 8;
-// #endif
-
 const isEmptyOrNull = function (exp: any) {
     return !exp || typeof (exp) == "undefined" || exp.length === 0 || exp === '' || JSON.stringify(exp) === "{}";
 };