Leo 3 lat temu
rodzic
commit
773f44b158

+ 246 - 0
src/components/vip-card/vip-card.vue

@@ -0,0 +1,246 @@
+<template>
+  <view
+    class="card"
+    :style="{
+      backgroundImage:
+        userInfo && userInfo.card_img ? `url(${userInfo.card_img})` : '',
+    }"
+  >
+    <view class="card-title">VIP会员</view>
+    <view class="card-desc">开通VIP会员专享权益</view>
+    <view class="card-status">
+      <template v-if="userInfo && userInfo.type === '1'">已开通</template>
+      <button
+        class="card-btn"
+        v-else-if="userInfo && userInfo.phone"
+        @click="handlePay"
+      >
+        立即开通
+      </button>
+      <button
+        v-else
+        class="card-btn"
+        open-type="getPhoneNumber"
+        @getphonenumber="handlePhoneLogin"
+      >
+        登录开通
+      </button>
+    </view>
+    <navigator url="/pages/vip/card" v-if="userInfo && userInfo.type === '1'">
+      <image
+        :src="require('@/assets/detail/icon-edit.png')"
+        class="icon-edit"
+      ></image>
+    </navigator>
+  </view>
+</template>
+
+<script>
+import login from "@/lib/utils/login";
+import { getUserInfo } from "@/lib/api/user";
+import { vipPrePay, vipCompletePay, vipQueryPay } from "@/lib/api/pay";
+
+export default {
+  name: "VipCard",
+
+  props: {
+    userInfo: {
+      type: Object,
+      default: () => null,
+    },
+    edit: {
+      type: Boolean,
+      default: false,
+    },
+  },
+
+  data() {
+    return {};
+  },
+
+  created() {
+    console.log(this.userInfo);
+  },
+
+  methods: {
+    async handlePay() {
+      try {
+        await this.wechatPay();
+        const res = await getUserInfo();
+        const userInfo = { ...(this.userInfo || {}), ...res.data };
+        login.setUserInfo(userInfo);
+        this.$emit("login", userInfo);
+      } catch (e) {
+        uni.showToast({
+          icon: "none",
+          title: e.message,
+        });
+      }
+    },
+
+    async wechatPay() {
+      uni.showLoading({
+        title: "加载中",
+        mask: true,
+      });
+
+      const { errno, errmsg, data } = await vipPrePay();
+
+      uni.hideLoading();
+
+      if (errno !== 10000) {
+        throw new Error(errmsg);
+      }
+      const {
+        timeStamp,
+        nonceStr,
+        package: pkg,
+        signType,
+        paySign,
+        order_id,
+      } = data;
+
+      const type = await new Promise((resolve) => {
+        uni.requestPayment({
+          provider: "wxpay",
+          timeStamp,
+          nonceStr,
+          package: pkg,
+          signType,
+          paySign,
+          success: async (res) => {
+            console.log(res);
+            resolve(
+              res.errMsg === "requestPayment:ok"
+                ? 1
+                : res.errMsg === "requestPayment:fail cancel"
+                ? 3
+                : 2
+            );
+          },
+          fail: async (err) => {
+            resolve(err.errMsg === "requestPayment:fail cancel" ? 3 : 2);
+          },
+        });
+      });
+
+      const res = await vipCompletePay({
+        order_id: `${order_id}`,
+        type,
+      }).catch((e) => {
+        console.log(e);
+      });
+
+      if (res.errno !== 10000) throw new Error(res.errmsg);
+
+      if (type !== 1) throw new Error(type === 3 ? "取消支付" : "支付失败");
+
+      return this.loopPayRes("" + order_id);
+    },
+    async loopPayRes(order_id) {
+      uni.showLoading({
+        title: "加载中",
+        mask: true,
+      });
+      const data = await vipQueryPay({
+        order_id,
+      });
+
+      if (data.errno == 90000) {
+        return new Promise((r) => {
+          setTimeout(() => r(), 1000);
+        }).then(() => this.loopPayRes(order_id));
+      }
+
+      uni.hideLoading();
+
+      if (data.errno == 10000) {
+        return data.data;
+      }
+
+      throw new Error("订单查询失败");
+    },
+    async handlePhoneLogin(e) {
+      if (e.detail.code) {
+        login.setPhoneData({
+          phone_code: e.detail.code,
+          callback: async (data) => {
+            const res = await getUserInfo();
+            this.$emit("login", { ...data, ...res.data });
+            if (res.data.type === "1") {
+              return;
+            }
+            this.handlePay();
+          },
+          fail: (e) => {
+            console.log(e);
+          },
+        });
+      }
+    },
+  },
+};
+</script>
+
+<style lang="scss">
+.card {
+  width: 660rpx;
+  height: 392rpx;
+  background: url("~@/assets/vip/card-vip.png") no-repeat center;
+  background-size: contain;
+  box-sizing: border-box;
+  padding: 40rpx;
+  margin: 0 auto;
+  color: rgb(251, 222, 190);
+  overflow: hidden;
+  border-radius: 24rpx;
+  position: relative;
+  &::before {
+    content: "";
+    position: absolute;
+    left: 0;
+    top: 0;
+    bottom: 0;
+    right: 0;
+    background-image: linear-gradient(
+      135deg,
+      rgba(0, 0, 0, 0.4) 0%,
+      transparent 100%
+    );
+  }
+  .card-title {
+    font-size: 56rpx;
+    position: relative;
+  }
+  .card-desc {
+    font-size: 28rpx;
+    margin-top: 20rpx;
+    position: relative;
+  }
+  .card-status {
+    margin-top: 100rpx;
+    text-align: right;
+    line-height: 92rpx;
+    font-size: 36rpx;
+    position: relative;
+  }
+  .card-btn {
+    color: rgb(3, 3, 3);
+    background: rgb(251, 222, 190);
+    display: inline-block;
+    padding: 0 50rpx;
+    border-radius: 100rpx;
+    font-weight: bold;
+    &::after {
+      display: none;
+    }
+  }
+  .icon-edit {
+    position: absolute;
+    top: 20rpx;
+    right: 20rpx;
+    width: 48rpx;
+    height: 48rpx;
+  }
+}
+</style>

+ 15 - 0
src/lib/api/vip.js

@@ -13,3 +13,18 @@ export const getVipList = () => request.get("/weapp/legals/list");
  * [api](https://console-docs.apipost.cn/preview/888dcf083e39e4e4/ae9a5ffd745e57d1?target_id=6deab440-b9f9-44ca-b0f9-1e06be8156cb)
  */
 export const getVipDetail = (id) => request.get(`/weapp/legals/${id}`);
+
+/**
+ * vip卡片背景图片列表
+ *
+ * [api](https://console-docs.apipost.cn/preview/888dcf083e39e4e4/ae9a5ffd745e57d1?target_id=36501e69-3d2f-4e18-8725-4886aba271b6)
+ */
+export const getCardStyleList = () => request.get(`/weapp/cardStyle/list`);
+
+/**
+ * 设置我的vip卡片背景图片
+ *
+ * [api](https://console-docs.apipost.cn/preview/888dcf083e39e4e4/ae9a5ffd745e57d1?target_id=6deab440-b9f9-44ca-b0f9-1e06be8156cb)
+ */
+export const useCardStyle = (data) =>
+  request.post(`/weapp/cardStyle/use`, data);

+ 52 - 26
src/lib/utils/login.js

@@ -3,6 +3,28 @@ import request from "./request";
 // 全局变量
 let loginData = {};
 
+function getUserInfoCache() {
+  return new Promise((resolve) => {
+    let userInfo = null;
+    const uinfoStr = uni.getStorageSync("userinfo");
+    if (uinfoStr) {
+      userInfo = JSON.parse(uinfoStr);
+    }
+    if (userInfo) {
+      resolve(userInfo);
+    } else {
+      wxLogin(resolve);
+    }
+  });
+}
+
+function setUserInfoCache(userInfo) {
+  uni.setStorageSync(
+    "userinfo",
+    typeof userInfo === "string" ? userInfo : JSON.stringify(userInfo)
+  );
+}
+
 // 进行登录
 function getUserInfo(data) {
   return new Promise((resolve, reject) => {
@@ -14,9 +36,9 @@ function getUserInfo(data) {
       .then((res) => {
         if (res.errno == 10000 && res.data) {
           uni.setStorageSync("userinfo", JSON.stringify(res.data));
-          resolve({ ...res.data, coupons: res.coupons || null });
+          resolve(res.data);
         } else {
-          reject({ errMsg: res.errmsg });
+          reject({ errmsg: res.errmsg });
         }
       })
       .catch((e) => {
@@ -35,7 +57,7 @@ function setPhoneNumber(data) {
           uni.setStorageSync("userinfo", JSON.stringify(res.data));
           resolve(res.data);
         } else {
-          reject({ errMsg: res.errmsg });
+          reject({ errmsg: res.errmsg });
         }
       })
       .catch((e) => {
@@ -54,7 +76,7 @@ function wxLogout() {
 
 //
 function tryLogin() {
-  if (loginData.userInfo && loginData.code) {
+  if (loginData.code) {
     const xdata = loginData;
     loginData = {};
     getUserInfo(xdata)
@@ -88,8 +110,10 @@ function tryLogin() {
 // 微信授权获取用户手机号
 function setPhoneData(params) {
   if (params.phone_code) {
-    loginData = params;
-    tryLogin("phone");
+    wxLogin(function (data) {
+      loginData = { ...params, session: data.session };
+      tryLogin("phone");
+    });
   } else {
     uni.showToast({
       icon: "none",
@@ -100,28 +124,28 @@ function setPhoneData(params) {
 
 // 微信授权获取用户信息
 function wxLogin(callback) {
-  loginData.userInfo = null;
+  // loginData.userInfo = null;
   loginData.code = null;
 
   loginData.callback = callback;
-  uni.getUserProfile({
-    desc: "获取你的昵称、头像、地区及性别",
-    success(data) {
-      loginData.userInfo = {
-        signature: data.signature,
-        encryptedData: data.encryptedData,
-        iv: data.iv,
-        rawData: data.rawData,
-      };
-      tryLogin("userProfile");
-    },
-    fail() {
-      uni.showToast({
-        icon: "none",
-        title: "授权失败",
-      });
-    },
-  });
+  // uni.getUserProfile({
+  //   desc: "获取你的昵称、头像、地区及性别",
+  //   success(data) {
+  //     loginData.userInfo = {
+  //       signature: data.signature,
+  //       encryptedData: data.encryptedData,
+  //       iv: data.iv,
+  //       rawData: data.rawData,
+  //     };
+  //     tryLogin("userProfile");
+  //   },
+  //   fail() {
+  //     uni.showToast({
+  //       icon: "none",
+  //       title: "1授权失败",
+  //     });
+  //   },
+  // });
 
   uni.login({
     success(res) {
@@ -138,7 +162,7 @@ function wxLogin(callback) {
     fail() {
       uni.showToast({
         icon: "none",
-        title: "授权失败",
+        title: "2授权失败",
       });
     },
   });
@@ -148,4 +172,6 @@ export default {
   logout: wxLogout,
   setPhoneData: setPhoneData,
   wxLogin: wxLogin,
+  getUserInfo: getUserInfoCache,
+  setUserInfo: setUserInfoCache,
 };

+ 1 - 1
src/lib/utils/request.js

@@ -19,7 +19,7 @@ function getCommonHeader() {
   if (info.session) {
     header.session = info.session;
   }
-  header.session = "375ac5dd70ebc9af27864ecfc91e9181";
+  // header.session = "375ac5dd70ebc9af27864ecfc91e9181";
   return header;
 }
 // todo 这里的问题,先注释掉

+ 13 - 0
src/pages.json

@@ -112,6 +112,15 @@
         "navigationBarBackgroundColor": "#000",
         "backgroundColor": "#000"
       }
+    },
+    {
+      "path": "pages/vip/card",
+      "style": {
+        "navigationBarTitleText": "VIP会员卡",
+        "navigationBarTextStyle": "white",
+        "navigationBarBackgroundColor": "#000",
+        "backgroundColor": "#000"
+      }
     }
     // {
     //   "path": "pages/help/help_about",
@@ -312,6 +321,10 @@
       {
         "name": "卡券",
         "path": "pages/my/coupon"
+      },
+      {
+        "name": "vip卡片",
+        "path": "pages/vip/card"
       }
     ]
   }

+ 5 - 6
src/pages/activity/detail.vue

@@ -61,15 +61,14 @@ export default {
   },
   computed: {
     isLogin() {
-      return !!this.userInfo && !!this.userInfo.session;
+      return (
+        !!this.userInfo && !!this.userInfo.session && !!this.userInfo.phone
+      );
     },
   },
-  onLoad(data) {
+  async onLoad(data) {
     this.id = data.id;
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-    }
+    this.userInfo = await login.getUserInfo();
   },
   onShow() {
     this.loadDetail();

+ 5 - 6
src/pages/address/add.vue

@@ -63,6 +63,7 @@
 <script>
 import api from "@/lib/api/api";
 import addressPicker from "@/components/wangding-pickerAddress/wangding-pickerAddress";
+import login from "@/lib/utils/login";
 export default {
   name: "PageAddressAdd",
   components: {
@@ -86,7 +87,7 @@ export default {
       id: "",
     };
   },
-  onLoad(data) {
+  async onLoad(data) {
     if (data.info) {
       const info = JSON.parse(decodeURI(data.info));
       this.planLocate = info.city;
@@ -96,12 +97,10 @@ export default {
       this.info.linkAddress = info.address;
       this.info.defaulted = "" + info.is_default;
     }
-    //
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
+    this.userInfo = await login.getUserInfo();
+    if (this.userInfo.session) {
       api
-        .addressList(data.session)
+        .addressList(this.userInfo.session)
         .then((data) => {
           if (data.data) {
             this.datas = data.data;

+ 4 - 5
src/pages/address/address.vue

@@ -84,6 +84,7 @@
 
 <script>
 import api from "@/lib/api/api";
+import login from "@/lib/utils/login";
 export default {
   name: "PageAddress",
   data() {
@@ -97,14 +98,12 @@ export default {
   onLoad(data) {
     this.action = data.action;
   },
-  onShow() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
+  async onShow() {
+    this.userInfo = await login.getUserInfo();
+    if (this.userInfo && this.userInfo.session) {
       this.refresh();
     } else {
       this.loginsuc = false;
-      this.userInfo = {};
     }
   },
   methods: {

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

@@ -76,6 +76,7 @@
   </view>
 </template>
 <script>
+import login from "@/lib/utils/login";
 import { homeModules } from "@/lib/api/home";
 import { getSingInfo } from "@/lib/api/task";
 import listItem from "@/components/list-item/list-item.vue";
@@ -96,11 +97,8 @@ export default {
       showTask: false,
     };
   },
-  onLoad() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-    }
+  async onLoad() {
+    this.userInfo = await login.getUserInfo();
     uni.showLoading({
       title: "加载中",
     });
@@ -109,12 +107,6 @@ export default {
     });
   },
   onShow() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-    } else {
-      this.userInfo = {};
-    }
     this.getSingInfo();
   },
   onShareAppMessage() {

+ 4 - 10
src/pages/my/coupon.vue

@@ -32,6 +32,7 @@
 </template>
 
 <script>
+import login from "@/lib/utils/login";
 import coupon from "@/components/coupon/coupon.vue";
 import { getMySkuList, useMySku } from "@/lib/api/shop";
 export default {
@@ -47,10 +48,9 @@ export default {
       hisList: [],
     };
   },
-  onLoad() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
+  async onLoad() {
+    this.userInfo = await login.getUserInfo();
+    if (this.userInfo && this.userInfo.session) {
       uni.showLoading({
         title: "加载中",
         mask: true,
@@ -61,12 +61,6 @@ export default {
         icon: "none",
       });
     }
-  },
-  onShow() {
-    if (!this.userInfo) {
-      return;
-    }
-
     this.initList();
   },
   methods: {

+ 2 - 8
src/pages/my/invite.vue

@@ -104,14 +104,8 @@ export default {
       info: {},
     };
   },
-  onShow() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-      this.initData();
-    } else {
-      this.userInfo = {};
-    }
+  async onShow() {
+    this.userInfo = await login.getUserInfo();
   },
   onShareAppMessage() {
     return {

+ 5 - 8
src/pages/my/messages.vue

@@ -23,6 +23,7 @@
 
 <script>
 import api from "@/lib/api/api";
+import login from "@/lib/utils/login";
 import jumpToUrl from "@/lib/utils/jumpToUrl";
 
 export default {
@@ -36,14 +37,10 @@ export default {
       messages: [],
     };
   },
-  onShow() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-      this.getMessage();
-    } else {
-      this.userInfo = null;
-    }
+
+  async onShow() {
+    this.userInfo = await login.getUserInfo();
+    if (this.userInfo && this.userInfo.session) this.getMessage();
   },
 
   onPullDownRefresh() {

+ 42 - 38
src/pages/my/my.vue

@@ -1,7 +1,10 @@
 <template>
   <view class="profile">
     <view class="user-header">
-      <view v-if="userInfo.show_id && userInfo.session" class="user-box">
+      <view
+        v-if="userInfo.show_id && userInfo.session && userInfo.phone"
+        class="user-box"
+      >
         <image class="avatar" :src="userInfo.avatar" mode=""></image>
         <view class="user-body">
           <text class="user-name">
@@ -19,7 +22,13 @@
           :src="require('@/assets/my/userimg.png')"
           mode=""
         ></image>
-        <button class="user-btn" @tap="onLoginTap">点击登录</button>
+        <button
+          class="user-btn"
+          open-type="getPhoneNumber"
+          @getphonenumber="handlePhoneLogin"
+        >
+          点击登录
+        </button>
       </view>
       <view class="my-balance">
         <view class="my-balance-item" @click="jump('../task/index')">
@@ -34,7 +43,8 @@
         </view>
       </view>
     </view>
-    <view class="my-main">
+    <vip-card :user-info="userInfo" @login="handleLogin" />
+    <!-- <view class="my-main">
       <view class="my-title">
         <text>我的订单</text>
         <view class="my-title-sub" @click="jump('../order/order?tabIndex=1')">
@@ -72,16 +82,18 @@
           {{ item.name }}
         </view>
       </view>
-    </view>
+    </view> -->
   </view>
 </template>
 
 <script>
 import login from "@/lib/utils/login";
 import { getUserInfo } from "@/lib/api/user";
+import VipCard from "@/components/vip-card/vip-card.vue";
 
 export default {
   name: "PageMy",
+  components: { VipCard },
   data() {
     return {
       testInt: 1,
@@ -158,21 +170,19 @@ export default {
       ],
     };
   },
-  onShow() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-      this.getUserInfo();
-    } else {
-      this.userInfo = {};
-    }
+  async onShow() {
+    this.userInfo = await login.getUserInfo();
+    this.getUserInfo();
   },
-  onPullDownRefresh() {
+  async onPullDownRefresh() {
     if (JSON.stringify(this.userInfo) == "{}") {
       uni.stopPullDownRefresh(); //得到数据后停止下拉刷新
       return;
     }
-    this.getUserInfo();
+    try {
+      await this.getUserInfo();
+    } catch (e) {}
+    uni.stopPullDownRefresh(); //得到数据后停止下拉刷新
   },
   methods: {
     //获取个人信息
@@ -180,8 +190,7 @@ export default {
       getUserInfo()
         .then((data) => {
           this.userInfo = { ...this.userInfo, ...data.data };
-          uni.setStorageSync("userinfo", JSON.stringify(this.userInfo));
-          uni.stopPullDownRefresh(); //得到数据后停止下拉刷新
+          login.setUserInfo(this.userInfo);
         })
         .catch((e) => {
           console.error(e);
@@ -191,29 +200,19 @@ export default {
       login.logout();
       this.userInfo = {};
     },
-    // 获取用户头像和昵称
-    onLoginTap() {
-      return new Promise((resolve, reject) => {
-        login.wxLogin((userInfo) => {
-          if (userInfo.session) {
-            this.userInfo = userInfo;
+    async handlePhoneLogin(e) {
+      if (e.detail.code) {
+        login.setPhoneData({
+          phone_code: e.detail.code,
+          callback: (data) => {
+            this.userInfo = data;
             this.getUserInfo();
-            if (userInfo.coupons && userInfo.coupons.is_bind_coupon === 1) {
-              uni.showToast({
-                icon: "none",
-                title: userInfo.coupons.is_bind_info || "登录成功~",
-                duration: 2e3,
-                mask: true,
-              });
-              setTimeout(() => {
-                resolve();
-              }, 2000);
-            } else {
-              resolve();
-            }
-          } else reject();
+          },
+          fail: (e) => {
+            console.log(e);
+          },
         });
-      });
+      }
     },
     async jump(url) {
       try {
@@ -222,7 +221,7 @@ export default {
             title: "请先登录",
             icon: "none",
           });
-          await this.onLoginTap();
+          return;
         }
 
         uni.navigateTo({
@@ -236,6 +235,10 @@ export default {
         data: this.userInfo.show_id,
       });
     },
+
+    handleLogin(userInfo) {
+      this.userInfo = userInfo;
+    },
   },
 };
 </script>
@@ -252,6 +255,7 @@ export default {
     position: relative;
     overflow: hidden;
     padding: 30rpx 30rpx 0;
+    margin-bottom: 30rpx;
   }
   .user-box {
     display: flex;

+ 5 - 8
src/pages/my/recharge.vue

@@ -119,15 +119,12 @@ export default {
       });
     },
   },
-  onShow() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-      this.getUserInfo();
-    } else {
-      this.userInfo = {};
-    }
+
+  async onShow() {
+    this.userInfo = await login.getUserInfo();
+    if (this.userInfo && this.userInfo.session) this.getUserInfo();
   },
+
   onPullDownRefresh() {
     if (JSON.stringify(this.userInfo) == "{}") {
       uni.stopPullDownRefresh(); //得到数据后停止下拉刷新

+ 4 - 8
src/pages/my/wallet.vue

@@ -39,6 +39,7 @@
 
 <script>
 import api from "@/lib/api/api";
+import login from "@/lib/utils/login";
 
 export default {
   name: "PageMyWallet",
@@ -49,17 +50,12 @@ export default {
       userInfo: {},
     };
   },
-  onShow() {
+  async onShow() {
     const t = uni.getMenuButtonBoundingClientRect();
     this.top = t.top + 5 + "px";
 
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-      this.refresh();
-    } else {
-      this.userInfo = {};
-    }
+    this.userInfo = await login.getUserInfo();
+    if (this.userInfo && this.userInfo.session) this.refresh();
   },
   methods: {
     refresh() {

+ 8 - 14
src/pages/order/order.vue

@@ -99,6 +99,7 @@
 
 <script>
 import api from "@/lib/api/api";
+import login from "@/lib/utils/login";
 export default {
   name: "PageOrder",
   data() {
@@ -114,21 +115,14 @@ export default {
   },
   onLoad(options) {
     this.navIndex = options.tabIndex;
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-    } else {
-      uni.showToast({
-        title: "请先登录",
-        icon: "none",
-      });
-      return;
-    }
   },
-  onShow() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
+
+  async onShow() {
+    const t = uni.getMenuButtonBoundingClientRect();
+    this.top = t.top + 5 + "px";
+
+    this.userInfo = await login.getUserInfo();
+    if (this.userInfo && this.userInfo.session) {
       api
         .balanceRecords(this.userInfo.session)
         .then((data) => {

+ 5 - 5
src/pages/order/sended.vue

@@ -92,6 +92,7 @@
 
 <script>
 import api from "@/lib/api/api";
+import login from "@/lib/utils/login";
 export default {
   name: "PageOrderSended",
   data() {
@@ -113,11 +114,10 @@ export default {
     };
   },
 
-  onLoad() {
-    //
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
+  async onLoad() {
+    this.userInfo = await login.getUserInfo();
+
+    if (this.userInfo && this.userInfo.session) {
       api
         .sendList(this.userInfo.session)
         .then((data) => {

+ 5 - 17
src/pages/order/unsend.vue

@@ -227,6 +227,7 @@
 
 <script>
 import api from "@/lib/api/api";
+import login from "@/lib/utils/login";
 export default {
   name: "PageOrderUnsend",
   data() {
@@ -254,26 +255,13 @@ export default {
   onShow() {
     const e = getCurrentPages();
     this.address = e[e.length - 1].data.address;
-    //
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-    } else {
-      this.userInfo = {};
-      uni.showToast({
-        title: "请先登录",
-        icon: "none",
-      });
-      return;
-    }
   },
-  onLoad() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
+  async onLoad() {
+    this.userInfo = await login.getUserInfo();
+
+    if (this.userInfo && this.userInfo.session) {
       this.loadData();
     }
-    //
   },
   methods: {
     // 页面刷新

+ 5 - 5
src/pages/reward/detail.vue

@@ -498,13 +498,13 @@ export default {
     },
   },
   watch: {},
-  onLoad(data) {
+
+  async onLoad(data) {
     this.params = data;
     this.id = data.id;
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-    }
+
+    this.userInfo = await login.getUserInfo();
+
     this.refresh();
   },
   onShow() {

+ 6 - 13
src/pages/shop/index.vue

@@ -32,11 +32,9 @@ export default {
       showTask: false,
     };
   },
-  onLoad() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-    }
+  async onLoad() {
+    this.userInfo = await login.getUserInfo();
+
     uni.showLoading({
       title: "加载中",
     });
@@ -44,14 +42,9 @@ export default {
       uni.hideLoading();
     });
   },
-  onShow() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-      this.getUserInfo();
-    } else {
-      this.userInfo = {};
-    }
+  async onShow() {
+    this.userInfo = await login.getUserInfo();
+    this.getUserInfo();
   },
   onShareAppMessage() {
     return {

+ 46 - 25
src/pages/task/index.vue

@@ -14,12 +14,30 @@
       ></image> -->
     </view>
     <view class="task-box">
-      <view class="task-btns">
+      <view class="task-btns" v-if="userInfo && userInfo.phone">
         <button class="task-btn" @click="uploadFiles">拍照积分</button>
         <button class="task-btn" :disabled="isSing" @click="handleSing">
           {{ isSing ? "已签到" : "签到积分" }}
         </button>
       </view>
+      <view class="task-btns" v-else>
+        <button
+          class="task-btn"
+          @click="uploadFiles"
+          open-type="getPhoneNumber"
+          @getphonenumber="handlePhoneLogin"
+        >
+          拍照积分
+        </button>
+        <button
+          class="task-btn"
+          :disabled="isSing"
+          open-type="getPhoneNumber"
+          @getphonenumber="handlePhoneLogin($event, 'sing')"
+        >
+          {{ isSing ? "已签到" : "签到积分" }}
+        </button>
+      </view>
     </view>
     <view class="task-box" v-if="photoList.length">
       <view class="task-box-title">拍照积分记录</view>
@@ -100,16 +118,22 @@ export default {
     };
   },
 
-  onShow() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
-      this.getSingInfo();
-      this.getMyPhotoList();
+  async onShow() {
+    this.userInfo = await login.getUserInfo();
+    if (this.userInfo && this.userInfo.session) {
+      this.init();
     }
   },
 
   methods: {
+    init() {
+      return Promise.all([
+        this.getUserInfo(),
+        this.getSingInfo(),
+        this.getMyPhotoList(),
+      ]);
+    },
+
     async getUserInfo() {
       const data = await getUserInfo();
       this.userInfo = { ...this.userInfo, ...data.data };
@@ -181,27 +205,24 @@ export default {
       });
     },
 
-    login() {
-      return new Promise((resolve, reject) => {
-        login.wxLogin(async (userInfo) => {
-          if (userInfo.session) {
-            this.userInfo = userInfo;
-            if (userInfo.coupons && userInfo.coupons.is_bind_coupon === 1) {
-              uni.showToast({
-                icon: "none",
-                title: userInfo.coupons.is_bind_info || "登录成功~",
-                duration: 2e3,
-                mask: true,
-              });
-              await this.getTaskInfo();
-
-              resolve();
+    async handlePhoneLogin(e, type) {
+      if (e.detail.code) {
+        login.setPhoneData({
+          phone_code: e.detail.code,
+          callback: async (data) => {
+            this.userInfo = data;
+            await this.init();
+            if (type === "sing") {
+              this.handleSing();
             } else {
-              resolve();
+              this.uploadFiles();
             }
-          } else reject();
+          },
+          fail: (e) => {
+            console.log(e);
+          },
         });
-      });
+      }
     },
   },
 };

+ 90 - 0
src/pages/vip/card.vue

@@ -0,0 +1,90 @@
+<template>
+  <view class="page">
+    <view class="item" v-for="item in list" :key="item.id">
+      <image
+        :src="item.img"
+        @click="handleUse(item)"
+        class="card"
+        mode="widthFix"
+      ></image>
+      <image
+        :src="require('@/assets/detail/card-checked.png')"
+        v-if="item.is_use"
+        class="checked"
+      ></image>
+    </view>
+  </view>
+</template>
+
+<script>
+import login from "@/lib/utils/login";
+import { getUserInfo } from "@/lib/api/user";
+import { getCardStyleList, useCardStyle } from "@/lib/api/vip";
+
+export default {
+  name: "VipCard",
+  data() {
+    return {
+      id: 0,
+      userInfo: null,
+      list: [],
+    };
+  },
+
+  async onShow() {
+    this.userInfo = await login.getUserInfo();
+    if (this.userInfo && this.userInfo.session) {
+      this.getUserInfo();
+      this.getList();
+    }
+  },
+  methods: {
+    async getUserInfo() {
+      const res = await getUserInfo();
+      this.userInfo = { ...this.userInfo, ...res.data };
+    },
+    async getList() {
+      const res = await getCardStyleList();
+      this.list = res.data;
+    },
+    async handleUse(item) {
+      if (item.is_use) return;
+      const res = await useCardStyle({ card_id: item.id });
+      this.list = res.data;
+    },
+  },
+};
+</script>
+
+<style lang="scss">
+page {
+  background: #000;
+}
+.page {
+  background: url("~@/assets/vip/bg.png") no-repeat center top #000;
+  background-size: contain;
+  padding: 40rpx 20rpx;
+  color: rgb(251, 222, 190);
+  box-sizing: border-box;
+  min-height: 100vh;
+  display: flex;
+  flex-wrap: wrap;
+  align-items: flex-start;
+}
+.item {
+  box-sizing: border-box;
+  width: 50%;
+  padding: 20rpx;
+  position: relative;
+  .card {
+    width: 100%;
+  }
+  .checked {
+    position: absolute;
+    right: 20rpx;
+    top: 20rpx;
+    width: 40rpx;
+    height: 40rpx;
+  }
+}
+</style>

+ 10 - 142
src/pages/vip/vip.vue

@@ -1,13 +1,6 @@
 <template>
   <view class="page">
-    <view class="card">
-      <view class="card-title">VIP会员</view>
-      <view class="card-desc">开通VIP会员专享权益</view>
-      <view class="card-status">
-        <template v-if="userInfo && userInfo.type === '1'">已开通</template>
-        <button class="card-btn" v-else @click="handlePay">立即开通</button>
-      </view>
-    </view>
+    <vip-card :user-info="userInfo" @login="handleLogin" />
     <view class="list-title">VIP会员专享{{ list.length }}项权益</view>
     <view class="list">
       <view class="item" v-for="item in list" :key="item.name">
@@ -19,11 +12,13 @@
 </template>
 
 <script>
+import login from "@/lib/utils/login";
 import { getUserInfo } from "@/lib/api/user";
-import { vipPrePay, vipCompletePay, vipQueryPay } from "@/lib/api/pay";
+import VipCard from "@/components/vip-card/vip-card.vue";
 
 export default {
   name: "VipVip",
+  components: { VipCard },
   data() {
     return {
       id: 0,
@@ -56,112 +51,20 @@ export default {
       ],
     };
   },
-  onShow() {
-    const uinfoStr = uni.getStorageSync("userinfo");
-    if (uinfoStr) {
-      this.userInfo = JSON.parse(uinfoStr);
+
+  async onShow() {
+    this.userInfo = await login.getUserInfo();
+    if (this.userInfo && this.userInfo.session) {
       this.getUserInfo();
-    } else {
-      this.userInfo = {};
     }
   },
   methods: {
     async getUserInfo() {
       const res = await getUserInfo();
       this.userInfo = { ...this.userInfo, ...res.data };
-      uni.setStorageSync("userinfo", JSON.stringify(this.userInfo));
     },
-
-    async handlePay() {
-      try {
-        await this.wechatPay();
-        this.getUserInfo();
-      } catch (e) {
-        uni.showToast({
-          icon: "none",
-          title: e.message,
-        });
-      }
-    },
-
-    async wechatPay() {
-      uni.showLoading({
-        title: "加载中",
-        mask: true,
-      });
-
-      const { errno, errmsg, data } = await vipPrePay();
-
-      uni.hideLoading();
-
-      if (errno !== 10000) {
-        throw new Error(errmsg);
-      }
-      const {
-        timeStamp,
-        nonceStr,
-        package: pkg,
-        signType,
-        paySign,
-        order_id,
-      } = data;
-
-      const type = await new Promise((resolve) => {
-        uni.requestPayment({
-          provider: "wxpay",
-          timeStamp,
-          nonceStr,
-          package: pkg,
-          signType,
-          paySign,
-          success: async (res) => {
-            resolve(
-              res.errMsg === "requestPayment:ok"
-                ? "1"
-                : res.errMsg === "requestPayment:fail cancel"
-                ? "3"
-                : "2"
-            );
-          },
-          fail: async (err) => {
-            resolve(err.errMsg === "requestPayment:fail cancel" ? "3" : "2");
-          },
-        });
-      });
-
-      await vipCompletePay({
-        order_id,
-        type,
-      }).catch((e) => {
-        console.log(e);
-      });
-
-      if (type !== "1") throw new Error(type === "3" ? "取消支付" : "支付失败");
-
-      return this.loopPayRes("" + order_id);
-    },
-    async loopPayRes(order_id) {
-      uni.showLoading({
-        title: "加载中",
-        mask: true,
-      });
-      const data = await vipQueryPay({
-        order_id,
-      });
-
-      if (data.errno == 90000) {
-        return new Promise((r) => {
-          setTimeout(() => r(), 1000);
-        }).then(() => this.loopPayRes(order_id));
-      }
-
-      uni.hideLoading();
-
-      if (data.errno == 10000) {
-        return data.data;
-      }
-
-      throw new Error("订单查询失败");
+    handleLogin(userInfo) {
+      this.userInfo = userInfo;
     },
   },
 };
@@ -177,41 +80,6 @@ page {
   padding: 40rpx 20rpx;
   color: rgb(251, 222, 190);
 }
-.card {
-  width: 660rpx;
-  height: 392rpx;
-  background: url("~@/assets/vip/card-vip.png") no-repeat center;
-  background-size: contain;
-  box-sizing: border-box;
-  padding: 40rpx;
-  margin: 0 auto;
-  color: rgb(251, 222, 190);
-  overflow: hidden;
-  .card-title {
-    font-size: 56rpx;
-  }
-  .card-desc {
-    font-size: 28rpx;
-    margin-top: 20rpx;
-  }
-  .card-status {
-    margin-top: 100rpx;
-    text-align: right;
-    line-height: 92rpx;
-    font-size: 36rpx;
-  }
-  .card-btn {
-    color: rgb(3, 3, 3);
-    background: rgb(251, 222, 190);
-    display: inline-block;
-    padding: 0 50rpx;
-    border-radius: 100rpx;
-    font-weight: bold;
-    &::after {
-      display: none;
-    }
-  }
-}
 .list-title {
   font-size: 36rpx;
   margin-top: 40rpx;