|
|
<template> <view style="padding-bottom: 20px;"> <view class="top-bar"> <image class="top-bar-bg" src="@/static/images/mingqi-beij@2x.png" mode="aspectFill"></image> <view class="library-info"> <image class="avatar" src="@/static/images/logo.jpg" mode="aspectFill"></image> <view class="library-name">葛店经济技术开发区图书馆</view> </view> <uni-icons class="search-icon" type="search" size="30" @click="onToSearch"></uni-icons> </view>
<view class="status-cards"> <view class="status-card" @click="toBorrowPage(0)"> <view class="status-icon icon-color1" > <uni-icons custom-prefix="iconfont" type="icon-daiban02" size="22"></uni-icons> </view> <view class="status-label">在借中</view> </view> <!-- <view class="status-card" @click="toBorrowPage(2)"> <view class="status-icon icon-color2" > <uni-icons custom-prefix="iconfont" type="icon-zuofei05" size="22"></uni-icons> </view> <view class="status-label">将过期</view> </view> <view class="status-card" @click="toBorrowPage(3)"> <view class="status-icon icon-color3" > <uni-icons custom-prefix="iconfont" type="icon-yuqi04" size="22"></uni-icons> </view> <view class="status-label">已过期</view> </view> --> <view class="status-card" @click="toBorrowPage(1)"> <view class="status-icon icon-color4" > <uni-icons custom-prefix="iconfont" type="icon-a-zhidu4" size="22"></uni-icons> </view> <view class="status-label">历史借阅</view> </view> </view>
<swiper class="banner-swiper" interval="3000" circular :vertical="false" :indicator-dots="true" :autoplay="true"> <swiper-item> <image data-post-id="3" src="https://mmbiz.qpic.cn/mmbiz_jpg/bVyA57fUOMicbQqItawJwQlR2oCoYql1icEbuH45ibSAzZsk2T3aDbUOIdMyOOc2CzkYouok0El5u5U3LONACaeNw/640?wx_fmt=jpeg&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1#imgIndex=1"></image> </swiper-item> <swiper-item> <image data-post-id="4" src="https://mmbiz.qpic.cn/sz_mmbiz_gif/tuyGibvSXrsqqiaNpAFJ7lbfGL5vibHtUdV5SUk1RWnlq3QqDe9liaWhdS91L0orEsFxZMiaHOFxDOzINmkiby24fYmmWstiayUgywfVia1pwMcNpBA/640?wx_fmt=gif&from=appmsg&tp=webp&wxfrom=5&wx_lazy=1#imgIndex=3"></image> </swiper-item> </swiper>
<!-- :indicator-dots="true" --> <swiper class="menu-swiper" interval="6000" :vertical="false" :autoplay="false"> <swiper-item> <view class="menu-grid"> <view class="menu-item" @click="onToSearch"> <view class="menu-icon"> <uni-icons custom-prefix="iconfont" type="icon-ziyuan" size="22"></uni-icons> </view> <view class="menu-label">书目检索</view> </view> <view class="menu-item" @click="onToLendCar"> <view class="menu-icon"> <uni-icons custom-prefix="iconfont" type="icon-z_renew_normal" size="24"></uni-icons> </view> <view class="menu-label">图书续借</view> </view> <!-- <view class="menu-item" > <view class="menu-icon"> <uni-icons custom-prefix="iconfont" type="icon-guanwaizhuanjie1" size="26"></uni-icons> </view> <view class="menu-label">图书转借</view> </view> --> <view class="menu-item" @click="toLibraryCard"> <view class="menu-icon"> <uni-icons custom-prefix="iconfont" type="icon-duzhezheng" size="26"></uni-icons> </view> <view class="menu-label">电子证</view> </view> <view class="menu-item" @click="toRanking"> <view class="menu-icon"> <uni-icons custom-prefix="iconfont" type="icon-paihangbang" size="22"></uni-icons> </view> <view class="menu-label">借阅排行</view> </view> <view class="menu-item" @click="toActivityList"> <view class="menu-icon"> <uni-icons custom-prefix="iconfont" type="icon-remenhuodong" size="26"></uni-icons> </view> <view class="menu-label">活动报名</view> </view> <view class="menu-item" @click="toFeedback"> <view class="menu-icon"> <uni-icons custom-prefix="iconfont" type="icon-duzheliuyan" size="26"></uni-icons> </view> <view class="menu-label">读者留言</view> </view> <view class="menu-item" @click="onToUser"> <view class="menu-icon"> <uni-icons custom-prefix="iconfont" type="icon-yonghuxinxi-gerenxinxi" size="20"></uni-icons> </view> <view class="menu-label">个人中心</view> </view> </view> </swiper-item> </swiper>
<!-- 已有绑定:滑动切换多个借阅证 --> <view v-if="isBindLibraryCard" class="library-card-has"> <view class="section-title">我的借阅证</view> <!-- 左右滑动切换证件 --> <!-- :indicator-dots="readerCardList.length > 1" indicator-color="#d1d1d1" indicator-active-color="#01a4fe" --> <swiper class="card-swiper" :circular="false" > <swiper-item v-for="item in readerCardList" :key="item.id"> <view class="card-item" @click.stop="showQrcode(item.bindValue)"> <image class="card-left-img" src="@/static/images/card-img2.png" mode="widthFix" /> <view class="card-right-info"> <text class="info-title">读者证号</text> <text class="info-num">{{ formatCardNo(item.bindValue) }}</text> </view> <view class="default-tag" v-if="item.bindDefault">默认证</view> <uni-icons class="erweima-style" custom-prefix="iconfont" type="icon-erweima" size="28"></uni-icons> </view> </swiper-item> </swiper> </view>
<!-- 未绑定借阅证 --> <view class="library-card-section" @click="toCheckLogin" v-else> <view class="section-title">借阅证</view> <image class="card-icon" src="@/static/images/card-img2.png"></image> <view class="card-tip">您还没有绑定读者证哦~</view> <button class="bind-btn">立即绑定</button> </view>
<root-portal> <uni-popup ref="popup" type="center" :mask-click="true" @maskClick="closePopup" :custom-style="popupFixedStyle" > <view class="qrcode-popup"> <view class="qrcode-title">读者证二维码</view> <w-qrcode v-if="qrcodeText" :value="qrcodeText" :size="160" foreground="#333" background="#ffffff" /> <view class="qrcode-num">{{ qrcodeText }}</view> <view class="close-btn" @click="closePopup">关闭</view> </view> </uni-popup> </root-portal>
<view class="recommendation-section"> <view class="section-title"> <text class="left-txt">图书推荐</text> <view class="more-link" @click="getMoreBoook" v-if="!(recommendedBooks.length === 0 && !isLoading)"> <text style="margin-right: 5px;">查看更多</text> <uni-icons custom-prefix="iconfont" type="icon-gengduo" size="12"></uni-icons> </view> </view> <view class="recommendation-list"> <uni-load-more status="loading" v-if="isLoading"></uni-load-more> <view v-else class="book-item" v-for="(item,index) in recommendedBooks.slice(0,3)" @click="goToBookDetail(item)" :key="index" > <image class="book-cover" :src="item.base64Cover || '/static/images/default-book.png'" @error="onImgError" ></image> <view class="book-title">{{item.name}}</view> </view> </view> <view class="empty-box" v-if="recommendedBooks.length === 0 && !isLoading"> <uni-icons custom-prefix="iconfont" type="icon-kongshuju" size="80"></uni-icons> <text style="margin-top: 20px;">暂无推荐书籍~</text> </view> </view> </view></template>
<script>import { FetchOpenId, FetchFindAllReaderBindByOpenId} from '@/api/user';import { FetchInitScreenBookRecommend } from '@/api/book';import config from '@/utils/config';import { STORAGE_KEYS } from '@/utils/storage';
export default { data() { return { isLoading: true, recommendedBooks: [], token: "", userInfo: {}, isBindLibraryCard: false, readerCardList: [], // 多个借阅证
baseUrl: config.baseUrl, qrcodeText: '', // 二维码内容
popupFixedStyle: 'position:fixed;top:0;left:0;right:0;bottom:0;' }; }, onLoad() { this.getRecommendBooks(); }, onShow() { this.initUserAndCheckBind(); }, methods:{ // 格式化读者证号
formatCardNo(cardNo) { if (!cardNo) return ''; const str = String(cardNo); const len = str.length;
if (len > 8) { // 前2位 + 中间全部* + 后2位
const front = str.substring(0, 2); const end = str.substring(len - 2); const star = '*'.repeat(len - 4); // 中间全部隐藏
return front + star + end; } else { // 小于等于8:*** + 后2位
return '***' + str.substring(len - 2); } }, onImgError(e) { e.target.src = "/static/images/default-book.png"; }, // 初始化:登录 → 获取openid → 查是否绑定
async initUserAndCheckBind() { try { // 1. 先看缓存有没有 openId
let openId = uni.getStorageSync('wx_login_code'); // 2. 没有 → 走微信登录流程
if (!openId) { const loginRes = await new Promise((resolve, reject) => { uni.login({ success: resolve, fail: reject }); });
if (!loginRes.code) { uni.showToast({ title: '授权失败', icon: 'none' }); return; }
// 3. 获取 openId
const openRes = await FetchOpenId({ libcode: '1201', code: loginRes.code });
if (openRes.code !== 200 || !openRes.data) { return; }
openId = openRes.data; uni.setStorageSync('wx_login_code', openId); }
// 4. 有了 openId → 查绑定状态
const res = await FetchFindAllReaderBindByOpenId({ libcode: '1201', openId: openId });
if (res.code === 200 && res.data.length > 0) { this.isBindLibraryCard = true; // 👉 默认证排第一位
const defaultCard = res.data.find(item => item.bindDefault === true); const otherCards = res.data.filter(item => !item.bindDefault); // 合并:默认在前,其他在后
this.readerCardList = defaultCard ? [defaultCard, ...otherCards] : res.data; uni.setStorageSync(STORAGE_KEYS.READER_CARD_LIST, this.readerCardList); uni.setStorageSync(STORAGE_KEYS.CURRENT_READER_CARD, defaultCard); } else { this.isBindLibraryCard = false; this.readerCardList = []; uni.setStorageSync(STORAGE_KEYS.READER_CARD_LIST, []); uni.setStorageSync(STORAGE_KEYS.CURRENT_READER_CARD, null); }
} catch (err) { console.error('初始化失败:', err); const list = uni.getStorageSync(STORAGE_KEYS.READER_CARD_LIST) || []; // 同样默认排第一
const defaultCard = list.find(item => item.bindDefault === true); const otherCards = list.filter(item => !item.bindDefault); this.readerCardList = defaultCard ? [defaultCard, ...otherCards] : list;
this.isBindLibraryCard = list.length > 0; } }, // 获取图书推荐 + 封面转 base64
async getRecommendBooks() { try { const res = await FetchInitScreenBookRecommend({ libcode: '1201' }); let books = res.data || [];
// 只处理并展示前3条,避免setData数据过大
const limit = 3; const displayBooks = books.slice(0, limit); for (let i = 0; i < displayBooks.length; i++) { let item = displayBooks[i]; if (item.imgPath) { const imageUrl = this.baseUrl + '/api/fileRelevant/getImg?imgType=2&imgId=' + item.imgPath; try { const base64 = await this.urlToBase64(imageUrl); item.base64Cover = base64; } catch (err) { item.base64Cover = ''; } } else { item.base64Cover = ''; } }
// 只将展示所需的前3条数据放入响应式,减少setData传输量
this.recommendedBooks = displayBooks; this.isLoading = false; } catch (err) { console.error('获取图书推荐失败:', err); this.isLoading = false; } }, goToBookDetail(item) { // 把整个图书对象 转成字符串 带过去
uni.navigateTo({ url: "/subpkg/pages/book-detail/book-detail?bookData=" + encodeURIComponent(JSON.stringify(item)) + "&fromRecommend=true" }) }, // 查看更多 → 进入图书列表页
getMoreBoook(){ uni.navigateTo({ url: "/subpkg/pages/book-list/book-list" }) }, // 去图书检索页
onToSearch() { uni.switchTab({ url: "/pages/search/search" }); }, // 去图书借阅车页
onToLendCar() { this.checkBindAndNavigate("/pages/lendCar/lendCar", "请您绑定读者证", true); }, // 点击未绑定借阅证区域 触发跳转
toCheckLogin() { uni.navigateTo({ url: "/pages/login/login" }); }, toRanking(){ uni.navigateTo({ url: "/subpkg/pages/ranking/ranking" }) }, toActivityList(){ this.checkBindAndNavigate("/subpkg/pages/activity-list/activity-list", "请您绑定读者证"); }, toBorrowPage(index) { if (this.isBindLibraryCard) { uni.setStorageSync('switch_tab_index', index); uni.navigateTo({ url: '/subpkg/pages/myLending/myLending' }); } else { uni.showModal({ title: '提示', content: '请您绑定读者证', confirmText: '去绑定', cancelText: '取消', success: (res) => { if (res.confirm) { uni.navigateTo({ url: "/pages/login/login" }); } } }); } }, toBorrowCar() { uni.switchTab({ url: '/pages/lendCar/lendCar' }); }, toFeedback() { this.checkBindAndNavigate("/subpkg/pages/feedback/feedback", "请您绑定读者证"); }, // 去借阅证列表页
toLibraryCard() { // 已绑定 → 进列表
if (this.isBindLibraryCard) { uni.navigateTo({ url: '/subpkg/pages/reader-card/reader-card' }); } // 未绑定 → 进绑定页
else { uni.navigateTo({ url: "/pages/login/login" }); } }, // 去个人中心页
onToUser() { this.checkBindAndNavigate("/pages/user/user", "请您绑定读者证", true); }, checkBindAndNavigate(url, message, isSwitchTab = false) { if (this.isBindLibraryCard) { if (isSwitchTab) { uni.switchTab({ url }); } else { uni.navigateTo({ url }); } } else { uni.showModal({ title: '提示', content: message, confirmText: '去绑定', cancelText: '取消', success: (res) => { if (res.confirm) { uni.navigateTo({ url: "/pages/login/login" }); } } }); } }, showQrcode(bindValue) { this.qrcodeText = bindValue; this.$refs.popup.open(); }, closePopup() { console.log('关闭弹窗'); this.qrcodeText = ''; this.$refs.popup.close(); }, urlToBase64(url) { return new Promise((resolve, reject) => { uni.request({ url, method: 'GET', responseType: 'arraybuffer', success: (res) => { try { const buffer = new Uint8Array(res.data); let binary = ''; for (let i = 0; i < buffer.length; i++) { binary += String.fromCharCode(buffer[i]); } const base64 = uni.arrayBufferToBase64(res.data); const dataUri = 'data:image/jpeg;base64,' + base64; resolve(dataUri); } catch (e) { reject(e); } }, fail: reject }); }); }, }}</script>
<style lang="scss" scoped>.top-bar{ .search-icon{ position: absolute; right: 16px; top: 15px; z-index: 22; ::v-deep .uni-icons{ color: #fff !important; } }}
.status-cards { display: flex; background-color: #fff; margin: 10px; border-radius: 8px; padding: 20px 10px; box-shadow: 0 1px 5px rgba(0, 0, 0, 0.05); .status-card { flex: 1; display: flex; flex-direction: column; align-items: center; } .status-icon { display: flex; justify-content: center; align-items: center; width: 40px; height: 40px; margin-bottom: 6px; border-radius: 50%; } .icon-color1{ background-color: #e4f2ff; } .icon-color2{ background-color: #ffeff0; } .icon-color3{ background-color: #e4fff4; } .icon-color4{ background-color: #fef8e2; } .status-label { font-size: 12px; color: #333; }}
swiper.banner-swiper{ width: 100%; height: 130px;}swiper.banner-swiper image{ width: 100%; height: 130px;}swiper.menu-swiper{ width:100%; margin-top: 10px; background-color: #fff;}
.menu-grid { display: grid; grid-template-columns: repeat(4, 1fr); .menu-item { flex: 1; display: flex; flex-direction: column; align-items: center; padding: 10px 0; .menu-icon{ display: flex; flex-direction: column; justify-content: center; height: 30px; ::v-deep .uni-icons{ color: #01a4fe !important; } } .menu-label { font-size: 12px; color: #333; text-align: center; } }}
.library-card-section { display: flex; flex-direction: column; justify-content: space-between; align-items: center; width: 100%; padding: 20px 0; .section-title { font-size: 22px; font-weight: bold; background: linear-gradient(140deg, #01a4ff, #2ec8fe); -webkit-background-clip: text; color: transparent; letter-spacing: 0.1em; margin-bottom: 5px; } .card-icon { width: 80px; height: 80px; } .card-tip { font-size: 12px; color: #999; margin: 5px 0; } .bind-btn { display: flex; flex-direction: row; align-items: center; justify-content: center; border: 1px solid #06a8ff ; width: 128px !important; height: 28px; border-radius: 28px; background: linear-gradient(140deg, #01a4ff, #2ec8fe); font-size: 14px; color: #fff; line-height: 28px; }}
.recommendation-section { background-color: #fff; margin: 10px; border-radius: 8px; padding: 0 0 10px 0; box-shadow: 0 1px 5px rgba(0, 0, 0, 0.05); .section-title{ display: flex; flex-direction: row; justify-content: space-between; align-items: center; height: 40px; padding: 0 10px; .left-txt{ color: #343434; font-size: 15px; font-weight: 700; } .more-link{ display: flex; flex-direction: row; justify-content: flex-start; align-items: center; color: #999; font-size: 11px; } }
}
.library-card-has { width: 100%; padding: 20px 10px; box-sizing: border-box; .section-title { font-size: 22px; font-weight: bold; background: linear-gradient(140deg, #01a4ff, #2ec8fe); -webkit-background-clip: text; color: transparent; letter-spacing: 0.1em; margin-bottom: 10px; padding-left: 5px; }
.card-list { width: 100%; }}
.card-swiper { height: 106px; .card-item{ display: flex; justify-content: space-between; align-items: center; padding: 10px; border: 2px solid #C6C6E2; border-radius: 8px; background: rgba(241,241,249,0.4); cursor: pointer; &.active{ border-color: #01a4fe; background: rgba(1, 164, 254, 0.1); } .card-left-img{ width: 80px; margin-right: 12px; display: block; } .card-right-info{ flex: 1; display: flex; flex-direction: column; .info-title{ font-size: 16px; color: #333; font-weight: bold; padding-bottom: 12px; } .info-num{ font-size: 14px; color: #999; } }
.default-tag { position: absolute; right: 12px; top: 12px; font-size: 11px; color: #01a4fe; border: 1px solid #01a4fe; border-radius: 4px; padding: 2px 6px; } }}
.erweima-style{ position: absolute; right: 12px; bottom: 22px; ::v-deep .icon-erweima{ // font-weight: bold;
color: #999 !important; }}
/* 空状态 */.empty-box { display: flex; flex-direction: column; justify-content: center; align-items: center; color: #999; font-size: 15px; padding: 20px;}</style>
|