uniapp-app/pages_app/myWelfareCard/myWelfareCard.vue
2026-02-02 17:44:10 +08:00

674 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="navbox">
<view class="status_bar"></view>
<uni-nav-bar
left-icon="left"
title="我的福利卡"
@clickLeft="goBack"
color="#8B2316"
:border="false"
backgroundColor="#eeeeee"
>
</uni-nav-bar>
</view>
<!-- <navBar :title="'我的福利卡'" /> -->
<view class="benefits-page">
<!-- 顶部红色横幅 -->
<view class="top-banner" @click="goWelfare" v-if="hasCard">
<image :src="bgImg" mode="widthFix" class="bg-img"></image>
<view class="banner-text">
<view class="line1">已兑换{{ cardInfo.length }}张</view>
<view class="line2" @click.stop="goWelfare">查看现有权益</view>
</view>
<view class="help-btn" @click.stop="showRules">帮助说明</view>
</view>
<!-- 帮助说明模态框(与兑换页一致的居中弹层) -->
<view v-if="centerVisible" class="center-modal" @click.self="closeCenter">
<view class="center-modal-content">
<view class="center-title">帮助说明</view>
<view class="center-help">
<text>1、点击“兑换福利卡”输入密码即可兑换相应权益</text>
<text>2、每张福利卡仅限兑换一次兑换后权益可在“我的福利-使用福利”中查看</text>
<text>3、福利卡长期有效福利卡不能退换或者折现</text>
<text>4、查找文献权益不限文献类型如指南共识、论文、电子书、课件或者视频</text>
</view>
<view class="center-actions">
<button class="center-btn" @click="closeCenter">知道了</button>
</view>
</view>
</view>
<!-- 有卡展示(多张) -->
<scroll-view
v-if="hasCard"
class="scroll-container"
scroll-y
:refresher-enabled="true"
:refresher-triggered="refreshing"
@refresherrefresh="onRefresh"
@scrolltolower="onLoadMore"
:lower-threshold="50"
>
<view class="card-wrapper" v-for="(card, cIdx) in cardInfo" :key="card.id">
<image :src="cardImg" mode="widthFix" class="card-img"></image>
<view class="cardbox">
<view class="card-header">
<image :src="logoImg" mode="widthFix" class="logo-img"></image>
<view class="headerbox">
<view>卡号:{{ card.idcard }}</view>
<view class="time">兑换时间:{{ card.exchange_date }}</view>
</view>
</view>
<view class="card-body">
<image v-if="card.welfare_list && card.welfare_list.length > 3 && (swiperCurrent[cIdx] || 0) > 0"
:src="rightImg" mode="widthFix" class="left-img" @click="swipeLeft(cIdx)"></image>
<view v-else class="left-img-placeholder"></view>
<!-- 超过3条使用swiper否则直接显示 -->
<swiper v-if="card.welfare_list && card.welfare_list.length > 3"
:class="'welfare-swiper-' + cIdx"
class="welfare-swiper"
:indicator-dots="false"
:autoplay="false"
:circular="false"
:display-multiple-items="1"
:current="swiperCurrent[cIdx] || 0"
@change="onSwiperChange($event, cIdx)">
<swiper-item v-for="(page, pageIdx) in getWelfarePages(card.welfare_list)" :key="pageIdx">
<view class="linebox">
<view class="benefit-line" v-for="(w, idx) in page" :key="idx">
<text class="index">{{ pageIdx * 3 + idx + 1 }}、</text>
<text class="text">{{ w.type_name }}{{ w.num }}{{ w.type_unit }}</text>
</view>
</view>
</swiper-item>
</swiper>
<view v-else class="linebox">
<view class="benefit-line" v-for="(w, idx) in card.welfare_list" :key="idx">
<text class="index">{{ idx + 1 }}</text>
<text class="text">{{ w.type_name }}{{ w.num }}{{ w.type_unit }}</text>
</view>
</view>
<image v-if="card.welfare_list && card.welfare_list.length > 3 && (swiperCurrent[cIdx] || 0) < getWelfarePages(card.welfare_list).length - 1"
:src="rightImg" mode="widthFix" class="right-img" @click="swipeRight(cIdx)"></image>
<view v-else class="right-img-placeholder"></view>
</view>
</view>
</view>
<!-- 加载提示 -->
<view class="loadmore-tip" v-if="isLoading || isLastPage">
<text>{{ isLoading ? '加载中...' : (isLastPage ? '没有更多了' : '') }}</text>
</view>
</scroll-view>
<!-- 无卡空状态 -->
<view v-else class="emptybox">
<empty />
</view>
<!-- 底部导航栏 -->
<view class="bottom-nav">
<view class="nav-item" @click="goPointsDetail">
<up-image :src="jifenImg" width="34rpx" height="34rpx"></up-image>
<text class="nav-text">兑换福利卡</text>
</view>
</view>
</view>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import jifenImg from "@/static/duihuan.png"
import emptyImg from "@/static/icon_empty.png"
import bgImg from '@/static/fulicard_bg.png'
import cardImg from '@/static/carditem_bg.png'
import api from '@/api/api';
import logoImg from '@/static/logo_gdxz.png'
import rightImg from '@/static/right_selsect_big.png'
import empty from '@/components/empty/empty.vue'
import { onLoad,onBackPress } from '@dcloudio/uni-app'
const from=ref('');
onBackPress(() => {
if(!from.value){
plus.runtime.quit();
return true;
}
});
onLoad((options) => {
from.value = options.from;
})
const goWelfare = () => {
uni.setStorageSync('lookWelfare', 'useWelfare');
console.log('6789');
uni.redirectTo({
url: '/pages_app/myWelfare/myWelfare'
});
}
// 是否有福利卡以及示例卡信息
const hasCard = ref(true)
const cardInfo = ref([]);
// 分页状态
const pageNum = ref(1)
const pageSize = ref(10)
const isLastPage = ref(false)
const isLoading = ref(false)
const refreshing = ref(false)
// 存储每个卡片的swiper当前索引
const swiperCurrent = ref({})
const getMyWelfareCard = (opts = { isRefresh: false }) => {
if (isLoading.value) return
isLoading.value = true
api.myWelfareCard({page: pageNum.value}).then(res => {
console.log(res)
if (res.code == 200) {
const list = Array.isArray(res.data.list) ? res.data.list : []
if (opts.isRefresh) {
cardInfo.value = list
} else {
cardInfo.value = pageNum.value === 1 ? list : cardInfo.value.concat(list)
}
hasCard.value = list.length > 0 || cardInfo.value.length > 0
isLastPage.value = !!res.data.isLastPage
}
})
.finally(() => {
isLoading.value = false
refreshing.value = false
})
}
const goBack = () => {
console.log('我的福利卡goBack');
console.log(from.value)
if(!from.value){
plus.runtime.quit();
}else{
uni.navigateBack();
}
}
onMounted(() => {
getMyWelfareCard()
})
// scroll-view 下拉刷新
const onRefresh = () => {
refreshing.value = true
pageNum.value = 1
isLastPage.value = false
getMyWelfareCard({ isRefresh: true })
}
// scroll-view 上拉加载更多
const onLoadMore = () => {
if (isLastPage.value || isLoading.value) return
pageNum.value += 1
getMyWelfareCard()
}
// 方法
const centerVisible = ref(false)
const showRules = () => {
centerVisible.value = true
};
const closeCenter = () => {
centerVisible.value = false
};
const goPointsDetail = () => {
console.log('goPointsDetail')
uni.navigateTo({ url: '/pages_app/myWelfareCard/exchange?num='+cardInfo.value.length })
};
const goMyWelfare = () => {
uni.navigateTo({ url: '/pages_app/myWelfare/myWelfare' })
}
// 将福利列表分组每组最多3条
const getWelfarePages = (welfareList) => {
if (!welfareList || welfareList.length === 0) return []
const pages = []
for (let i = 0; i < welfareList.length; i += 3) {
pages.push(welfareList.slice(i, i + 3))
}
return pages
}
// swiper切换事件
const onSwiperChange = (e, cardIndex) => {
swiperCurrent.value[cardIndex] = e.detail.current
}
// 向左滑动
const swipeLeft = (cardIndex) => {
const current = swiperCurrent.value[cardIndex] || 0
if (current > 0) {
swiperCurrent.value[cardIndex] = current - 1
}
}
// 向右滑动
const swipeRight = (cardIndex) => {
const current = swiperCurrent.value[cardIndex] || 0
const card = cardInfo.value[cardIndex]
if (card && card.welfare_list) {
const pages = getWelfarePages(card.welfare_list)
if (current < pages.length - 1) {
swiperCurrent.value[cardIndex] = current + 1
}
}
}
</script>
<style lang="scss" scoped>
// 变量定义
$bg-color: #f5f6f7;
$text-primary: #333333;
$text-secondary: #666666;
$text-light: #999999;
$border-color: #e5e5e5;
$white: #ffffff;
$theme-color: #e74c3c;
$divider-color: #cccccc;
$nav-height: 140rpx; // 导航栏高度
$segmented-height: 80rpx; // 分段控制器高度
$bottom-nav-height: 120rpx; // 底部导航高度
// 混合器
@mixin flex-center {
display: flex;
align-items: center;
justify-content: center;
}
@mixin flex-between {
display: flex;
align-items: center;
justify-content: space-between;
}
@mixin shadow {
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.1);
}
.benefits-page {
height: 100vh;
.scroll-container {
position: fixed;
top: calc(var(--status-bar-height) + 44px + 286rpx);
left: 0;
right: 0;
bottom: 100rpx;
height: calc(100vh - var(--status-bar-height) - 44px - 286rpx - 100rpx);
box-sizing: border-box;
}
.emptybox{
display: flex;
height: 100vh;
flex-direction:column;
justify-content: center;
align-items: center;
height: 100vh;
.empty_desc{
font-size: 30rpx;
color:#999;
}
}
}
.status-bar {
height: 44rpx;
background-color: $white;
@include flex-between;
padding: 0 30rpx;
font-size: 24rpx;
color: $text-primary;
.status-left {
display: flex;
align-items: center;
gap: 10rpx;
.time {
font-weight: 500;
}
.butterfly {
font-size: 20rpx;
}
}
.status-right {
display: flex;
align-items: center;
gap: 20rpx;
.network-info,
.signal,
.wifi,
.battery {
font-size: 22rpx;
}
}
}
.header {
height: 88rpx;
background-color: $white;
@include flex-between;
padding: 0 30rpx;
border-bottom: 1rpx solid $border-color;
.header-left {
.back-btn {
font-size: 48rpx;
color: $theme-color;
font-weight: bold;
}
}
.header-center {
.title {
font-size: 36rpx;
color: $text-primary;
font-weight: bold;
}
}
.header-right {
.rules-btn {
font-size: 28rpx;
color: $text-primary;
}
}
}
.segmented-control {
position: fixed;
top: $nav-height;
left: 0;
right: 0;
z-index: 10;
height: 80rpx;
background-color: $white;
display: flex;
align-items: center;
padding: 0 30rpx;
border-bottom: 1rpx solid $border-color;
.tab-item {
flex: 1;
@include flex-center;
height: 100%;
position: relative;
.tab-text {
font-size: 28rpx;
color: $text-secondary;
transition: all 0.3s ease;
}
&.active {
.tab-text {
color: #8B2316;
font-size: 30rpx;
}
}
}
.divider {
width: 2rpx;
height: 40rpx;
background-color: $divider-color;
}
}
.benefits-list {
.benefit-card {
background: $white;
border-radius: 20rpx;
padding: 30rpx;
margin-bottom: 30rpx;
position: relative;
overflow: hidden;
border:2rpx solid #fff;
.card-bg {
position: absolute;
top: 0;
right: 20rpx;
left:20rpx;
z-index:0;
}
.card-content {
margin-top: 30rpx;
background:url("@/static/fljifen_big.png") 0 0 no-repeat;
background-size: 100% 100%;
position: relative;
height: 220rpx;
z-index: 1;
.card-title {
font-size: 32rpx;
color: $white;
font-weight: 600;
margin-bottom: 30rpx;
line-height: 1.4;
}
.card-details {
display: flex;
justify-content: space-between;
align-items: center;
padding:0 40rpx;
height: 220rpx;
.left-section,
.right-section {
display: flex;
flex-direction: column;
gap: 8rpx;
.condition,
.reward-type {
font-size: 24rpx;
color: rgba(255, 255, 255, 11);
}
.requirement,
.reward-value {
font-size: 36rpx;
color: $white;
font-weight: bold;
}
.requirement{
margin-top: 40rpx;
}
}
.right-section {
align-items: flex-end;
}
}
}
}
}
/* 顶部横幅与卡片样式 */
.top-banner{
position: fixed;
height: 286rpx;
width:100%;
top: calc(var(--status-bar-height) + 44px);
.bg-img{
position: absolute;
width: 100%;
z-index:0;
height: 286rpx;
}
.banner-text{
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 80rpx;
z-index:1;
color: #fff;
.line1{font-size: 44rpx;}
.line2{font-size: 36rpx;margin-top: 12rpx;}
}
.help-btn{
position: absolute;
right: 30rpx;
top: 20rpx;
background: rgba(255,255,255,.95);
color: #e04835;
border-radius: 999rpx;
padding: 10rpx 24rpx;
font-size: 24rpx;
}
}
.card-wrapper{
position: relative;
margin: 24rpx 30rpx;
border-radius: 16rpx;
overflow: hidden;
.cardbox{
position: relative;
z-index:2;
}
.card-img{
position: absolute;
width: 100%;
z-index:0;
height: 336rpx;
}
.card-header{
color: #fff;
padding: 4rpx 28rpx;
font-size: 26rpx;
display: flex;
align-items: center;
.headerbox{
display: flex;
flex-direction: column;
justify-content: center;
}
.time{opacity:.95}
.logo-img{
width:94rpx;
height: 94rpx;
border-radius: 50%;
overflow: hidden;
margin-right: 20rpx;
}
}
.card-body{
height: 240rpx;
display: flex;
justify-content: center;
align-items: center;
padding:0rpx 28rpx;
.left-img{
width:28rpx;
height: 50rpx;
transform: rotate(180deg);
cursor: pointer;
}
.right-img{
width:28rpx;
height: 50rpx;
cursor: pointer;
}
.left-img-placeholder,
.right-img-placeholder{
width:28rpx;
height: 50rpx;
}
.welfare-swiper{
flex: 1;
height: 100%;
}
.linebox{
min-width: 500rpx;
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
padding:0 20rpx;
height: 100%;
}
.benefit-line{
font-size: 30rpx;
width:355rpx;
color: #8B2316;
line-height: 56rpx;
text-align: left;
.index{color:#8B2316;}
.text{
text-align: left;
}
}
}
}
.bottom-nav {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 10;
height: 100rpx;
background-color: #00cbc0;
border-top: 1rpx solid $border-color;
display: flex;
align-items: center;
justify-content: space-around;
padding: 0 20rpx;
.nav-item {
@include flex-center;
flex-direction: flex;
gap: 8rpx;
.nav-icon {
font-size: 40rpx;
}
.nav-text {
font-size: 32rpx;
color: #fff;
}
}
}
/* 底部加载提示 */
.loadmore-tip{
text-align: center;
color: #999;
font-size: 24rpx;
padding: 20rpx 0 120rpx; // 给底部按钮留出空间
}
/* 居中模态框样式(复用兑换页风格) */
.center-modal{position: fixed;left:0;right:0;top:0;bottom:0;background: rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;z-index: 9999;}
.center-modal-content{width: 640rpx;background:#fff;border-radius:24rpx;overflow:hidden;}
.center-title{font-size: 32rpx;color:#333;text-align:center;padding:28rpx 24rpx 12rpx;font-weight:600;}
.center-help{padding: 0 32rpx;display:flex;flex-direction:column;align-items:center;gap: 16rpx;color:#333;font-size:28rpx;line-height:1.6;}
.center-actions{padding: 24rpx 24rpx 28rpx;}
.center-btn{width:100%;height:88rpx;border-radius:999rpx;background:#e93b2d;color:#fff;font-size:30rpx;}
</style>