Jelajahi Sumber

会员套餐

zhengnaiwen_citu 6 bulan lalu
induk
melakukan
aa758d8304
4 mengubah file dengan 344 tambahan dan 10 penghapusan
  1. 6 0
      pages.json
  2. 5 3
      pages/index/my.vue
  3. 30 7
      pagesA/vip/index.vue
  4. 303 0
      pagesA/vipPackage/index.vue

+ 6 - 0
pages.json

@@ -164,6 +164,12 @@
 						"navigationBarTitleText": "vip权益"
 					}
 				},
+				{
+					"path": "vipPackage/index",
+					"style": {
+						"navigationBarTitleText": "会员套餐"
+					}
+				},
 				{
 					"path": "vip/template/index",
 					"style": {

+ 5 - 3
pages/index/my.vue

@@ -78,7 +78,7 @@ import { getUserAvatar } from '@/utils/avatar'
 import { getAccessToken } from '@/utils/request'
 import layoutPage from '@/layout'
 import { showAuthModal } from '@/hooks/useModal'
-import { onShow, onLoad } from '@dcloudio/uni-app'
+import { onShow, onLoad, onShareAppMessage } from '@dcloudio/uni-app'
 import { getJobAdvertisedShareQrcode } from '@/api/user'
 // 设置自定义tabbar选中值
 onShow(() => {
@@ -104,7 +104,9 @@ const itemList = [
 
 const list = ref([
 	{	title: '我的分享码',	path: 'shareQrCode'	},					
-	{	title: '新用户邀请记录',	path: '/pagesB/inviteRecord/index'	},					
+	{	title: '新用户邀请记录',	path: '/pagesB/inviteRecord/index'	},
+	{	title: '会员套餐', path: '/pagesA/vipPackage/index'	},		
+
 	{	title: '在线简历',	path: '/pagesA/resumeOnline/index'	},					
 	{	title: '附件简历',	path: '/pagesA/resume/index'	},					
 	{ title: '面试管理', path: '/pagesA/interview/index' },
@@ -115,7 +117,7 @@ const list = ref([
 watch(
   () => vip.value, 
   (newVal) => {
-		if (newVal) list.value.splice(2, 0, {	title: 'vip权益', key: 'vip',	path: '/pagesA/vip/index'	})
+		if (newVal) list.value.splice(3, 0, {	title: 'vip权益', key: 'vip',	path: '/pagesA/vip/index'	})
 		else list.value = list.value.filter(e => !e.key || e.key !== 'vip')
   },
   { immediate: true },

+ 30 - 7
pagesA/vip/index.vue

@@ -42,6 +42,7 @@ const useUserStore = userStore()
 const baseInfo = computed(() => useUserStore?.baseInfo)
 const userInfo = computed(() => useUserStore?.userInfo)
 
+
 let list = [
 	{	title: '简历模板', key: 'resumeRefreshCount', show: true,	path: '/pagesA/vip/template/index'	},					
 	{	title: '简历模板', key: 'resumeTemplate', show: false,	path: '/pagesA/vip/template/index'	},					
@@ -49,6 +50,8 @@ let list = [
 ]
 const listKeys = list.map(e => e.key)
 
+const memberList = ref([])
+
 // 权益列表
 const menuList = ref([])
 watch(() => userInfo.value?.entitlement, 
@@ -74,12 +77,13 @@ watch(() => userInfo.value?.entitlement,
 )
 
 const remaining = computed(() => {
-  if (!userInfo.value?.vipExpireDate) return '0'
+  if (!userInfo.value?.vipExpireDate) return ' 0'
   const diffInMs =  (userInfo.value?.vipExpireDate-0) - new Date().getTime()
   const day = diffInMs / (1000 * 60 * 60 * 24)
   return day < 1 ? '今天' : Math.floor(day) + '天'
 })
 
+
 // 列表跳转
 const handleToLink = (item) => {
 	uni.navigateTo({
@@ -89,28 +93,47 @@ const handleToLink = (item) => {
 const pName = ref('')
 let getPNameNum = 0 
 const getPName = () => {
-  if (!useUserStore.userInfo?.vipFlag) {
+  if (!userInfo.value?.vipFlag) {
     getPNameNum++
     if (getPNameNum > 6)
     setTimeout(() => { getPName() }, 1000);
     return
   }
   memberList.value.forEach(e => {
-    if (e.id && e.id.toString() === useUserStore.userInfo?.vipFlag?.toString()) pName.value = e.name
+    if (e.id && e.id.toString() === userInfo.value?.vipFlag?.toString()) pName.value = e.name
   })
 }
 
-const memberList = ref([])
 const getMemberList = async () => {
   try {
-    const res = await getMembershipPackageList()
-    if (!res?.data?.length) return uni.showToast({ title: '查询数据失败,请重试', icon: 'none' })
-    memberList.value = res.data
+    const { data } = await getMembershipPackageList()
+    if (!data || data.length === 0) {
+      return
+    }
+    memberList.value = data
+    // let vipFlagIndex = null
+    // const list = data.map((item, index) => {
+    //   item.id = item.id?.toString()
+    //   if (item.id === userInfo.value?.vipFlag) vipFlagIndex = index // 低于当前套餐的(套餐)不展示
+    //   if (item.recommend) recommend.value = index // 推荐套餐
+    //   return {
+    //     ...item,
+    //     my: vipFlagIndex === index,
+    //     list: JSON.parse(item.text),
+    //     type: 3, // 订单类型 0平台订单|1求职端订单|2招聘端订单|3会员套餐
+    //     loading: false
+    //   }
+    // })
+    // // 低于当前套餐的(套餐)不展示
+    // memberList.value = vipFlagIndex ? list.slice(vipFlagIndex) : list
     getPName()
   } catch (error) {
     uni.showToast({ title: '查询数据失败,请重试', icon: 'none' })
   }
 }
+ 
+
+
 getMemberList()
 
 </script>

+ 303 - 0
pagesA/vipPackage/index.vue

@@ -0,0 +1,303 @@
+<template>
+  <view>
+    <view class="vipBox">
+      <view class="avatar">
+        <img :src="getUserAvatar(baseInfo?.avatar, baseInfo?.sex)" alt="" class="img-box">
+        <image src="/static/svg/vip.svg" class="vipIcon"></image>
+      </view>
+      <view class="nameBox">
+        <view class="name font-weight-bold font-size-16">{{ baseInfo?.name || userInfo?.phone }}</view>
+        <view class="vipInfo font-size-14" v-if="remaining">
+          {{ pName }}
+          <view>将于{{ remaining }}后过期</view>
+        </view>
+      </view>
+    </view>
+    <view>
+      <swiper class="swiper-box" :current="current">
+        <swiper-item v-for="(item, index) in memberListLength" :key="index" class="swiper-items">
+          <view class="swiper-item" v-for="val in item" :key="val.id">
+            <view
+              class="card"
+              :class="{ recommend: val.recommend, vipFlag: val.my, active: val.id === chooseId}"
+              @tap="handleChoose(val.id)"
+            >
+              <text>{{ val.name }}</text>
+              <view>
+                <uni-icons color="#f30" type="icon-renminbi1688" size="16" custom-prefix="iconfont"></uni-icons>
+                <text>{{ val.price }}</text>
+              </view>
+            </view>
+          </view>
+        </swiper-item>				
+      </swiper>
+      <view v-if="typeof chooseId === 'number'" class="itemBox">
+        套餐权益 ( {{ list.name }} )
+        <uni-section
+          v-for="item in list.list"
+          :key="item.id"
+          class="item"
+          :class="{ active: item.active }"
+          titleColor="#774e20"
+          subTitleColor="#774e20"
+          :title="item.text"
+        >
+          <template v-slot:right>
+            <uni-icons color="#774e20" :type="item.active ? 'checkmarkempty' : 'closeempty'" size="20"/>
+          </template>
+        </uni-section>
+      </view>
+    </view>
+    <view class="pay">
+      <view class="pay-box">
+        <view class="price">
+          <uni-icons color="#e68735" type="icon-renminbi1688" size="16" custom-prefix="iconfont"></uni-icons>
+          {{ list.price }}
+        </view>
+        <view class="btn">
+          立刻升级
+        </view>
+        </view>
+    </view>
+  </view>
+</template>
+
+<script setup>
+import { ref, computed, watch } from 'vue'
+
+import { getUserAvatar } from '@/utils/avatar'
+import { userStore } from '@/store/user'
+import { getMembershipPackageList } from '@/api/vip'
+const useUserStore = userStore()
+
+const baseInfo = computed(() => useUserStore?.baseInfo)
+const userInfo = computed(() => useUserStore?.userInfo)
+
+const memberList = ref([])
+const recommend = ref(null)
+const chooseId = ref(null)
+
+const memberListLength = computed(() => {
+  const result = [];  
+  for (let i = 0; i < memberList.value.length; i += 2) {  
+      const pair = memberList.value.slice(i, i + 2)
+      result.push(pair)
+  }
+  return result
+})
+
+const pName = computed(() => {
+  return memberList.value.find(item => +item.id === +userInfo.value?.vipFlag)?.name
+})
+
+const remaining = computed(() => {
+  if (!userInfo.value?.vipExpireDate) return null
+  const diffInMs =  userInfo.value?.vipExpireDate - new Date().getTime()
+  const day = diffInMs / (1000 * 60 * 60 * 24)
+  return day < 1 ? '今天' : Math.floor(day) + '天'
+})
+
+const list = computed(() => {
+  const item = memberList.value.find(item => item.id === chooseId.value)
+  return item ?? {}
+})
+
+const current = ref(0)
+
+const handleChoose = (id) => {
+  chooseId.value = id
+}
+
+const getMemberList = async () => {
+  try {
+    const { data } = await getMembershipPackageList()
+    if (!data || data.length === 0) {
+      return
+    }
+    // memberList.value = data
+    let vipFlagIndex = null
+    const list = data.map((item, index) => {
+      if (+item.id === +userInfo.value?.vipFlag) {
+        vipFlagIndex = index // 低于当前套餐的(套餐)不展示
+      }
+      if (item.recommend) {
+        recommend.value = index // 推荐套餐
+      }
+      return {
+        ...item,
+        my: vipFlagIndex === index,
+        list: JSON.parse(item.text),
+        type: 3, // 订单类型 0平台订单|1求职端订单|2招聘端订单|3会员套餐
+        loading: false
+      }
+    })
+    // 低于当前套餐的(套餐)不展示
+    memberList.value = vipFlagIndex ? list.slice(vipFlagIndex) : list
+    if ((!userInfo.value?.vipFlag || userInfo.value?.vipExpireDate - new Date().getTime() > 0 ) && typeof recommend.value === 'number') {
+      current.value = parseInt(recommend.value / 2)
+      chooseId.value = memberList.value[recommend.value]?.id
+    }
+  } catch (error) {
+    uni.showToast({ title: '查询数据失败,请重试', icon: 'none' })
+  }
+}
+
+getMemberList()
+</script>
+
+<style lang="scss" scoped>
+.vipBox {
+	// color: #a18a0f;
+  padding: 80rpx 50rpx;
+  display: flex;
+  background: linear-gradient(121deg,#fde2c2 29.02%,#c19164 104.03%);
+  .avatar{
+    position: relative;
+    width: 100rpx;
+    height: 100rpx;
+    margin: 0;
+    .img-box {
+      width: 100%;
+      height: 100%;
+      border: 2rpx solid #ccc;
+      border-radius: 50%;
+      border: 1px solid gold;
+    }
+    .vipIcon {
+      position: absolute;
+      width: 50%;
+      height: 50%;
+      bottom: 0;
+      right: 0;
+      transform: translate(0, 30%);
+    }
+  }
+  .nameBox {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-around;
+    margin-left: 30rpx;
+    .name {
+      color: #724d2b;
+    }
+    .vipInfo {
+      color: #572a00;
+    }
+  }
+}
+
+.swiper-box {
+  height: 200rpx;
+  .swiper-items {
+    display: grid;
+    grid-template-columns: 1fr 1fr;
+  }
+  .swiper-item {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    height: 200rpx;
+    padding: 20rpx 10rpx;
+    box-sizing: border-box;
+    .card {
+      color: #774e20;
+      background-color: rgb(255, 251, 248);
+      border: 1px solid #f1b17a;
+      width: 100%;
+      height: 100%;
+      border-radius: 10rpx;
+      padding: 0 20rpx;
+      box-sizing: border-box;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      position: relative;
+      overflow: hidden;
+      &.recommend {
+        &::after {
+          content: '推荐';
+          position: absolute;
+          right: 0;
+          top: 0;
+          padding: 6rpx 10rpx;
+          font-size: 28rpx;
+          background: linear-gradient(121deg,#fde2c2 29.02%,#c19164 104.03%);
+        }
+      }
+      &.vipFlag {
+        &::before {
+          content: '我的套餐';
+          position: absolute;
+          left: 0;
+          top: 0;
+          padding: 6rpx 10rpx;
+          font-size: 28rpx;
+          background: linear-gradient(121deg,#fde2c2 29.02%,#c19164 104.03%);
+        }
+      }
+      &.active {
+        box-shadow: 0 0 18rpx 0 rgb(216 160 82);
+      }
+    }
+  }
+}
+
+.itemBox {
+  padding: 20rpx 40rpx;
+  .item {
+    // padding: 10rpx 0;
+    margin-top: 20rpx;
+    // color: rgba(119,78,32,.5);
+    // &.active {
+      color:#774e20;
+    // }
+  }
+}
+
+.pay {
+  position: sticky;
+  bottom: 0;
+  padding: 0 40rpx 100rpx 40rpx;
+  box-sizing: border-box;
+  &-box {
+    width: 100%;
+    background: linear-gradient(121deg,#fde2c2 29.02%,#c19164 104.03%);
+    border-radius: 180rpx 0 180rpx 0;
+    box-shadow: 3rpx 6rpx 10rpx 0rpx rgb(216 160 82);
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    height: 100rpx;
+    .price {
+      padding: 0 40rpx;
+      font-size: 40rpx;
+      font-weight: 600;
+      color: #e68735;
+    }
+    .btn {
+      height: 100%;
+      display: flex;
+      align-items: center;
+      padding: 0 40rpx;
+      border: 2rpx solid #00897B;
+      background: #00897B;
+      color: #FFF;
+      border-radius: 180rpx 0 180rpx 0;
+      position: relative;
+      // &::after {
+      //   content: '';
+      //   position: absolute;
+      //   width: 50rpx;
+      //   height: 50rpx;
+      //   background: radial-gradient(top right, transparent 50%, #00897B 50%);
+      //   left: 0;
+      //   top: 0;
+      //   margin-left: -25rpx;
+      //   border-radius: 180rpx;
+      // }
+    }
+  }
+}
+
+</style>