图书馆小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

342 lines
8.8 KiB

<template>
<view class="detail-container">
<!-- 书籍头部信息 -->
<view class="article-detail-container">
<view class="article-detail-left">
<view class="article-detail-title">{{ bookInfo.title || bookInfo.name || '暂无书名' }}</view>
<view class="article-detail-info">
<view class="article-detail-author">作者{{ bookInfo.author || '暂无' }}</view>
<view class="article-detail-time">出版社{{ bookInfo.publisher || '暂无' }}</view>
<view class="article-detail-time">ISBN{{ bookInfo.isbn || '暂无' }}</view>
<!-- <view class="article-detail-time">出版时间{{ bookInfo.publishdate || '暂无' }}</view> -->
</view>
</view>
<view class="article-detail-right">
<!-- <image
:src="bookInfo.imgPath
? baseUrl + '/api/fileRelevant/getImg?imgType=2&imgId=' + bookInfo.imgPath
: bookInfo.cover || '/static/images/default-book.png'"
mode="widthFix"
/> -->
<image
class="img-item"
:src="bookInfo.cover || (bookInfo.imgPath ? baseUrl + '/api/fileRelevant/getImg?imgType=2&imgId=' + bookInfo.imgPath : '/static/images/default-book.png')"
mode="widthFix"
@error="onImgError"
></image>
</view>
</view>
<!-- 馆藏信息 -->
<view class="book-store-info">
<view class="book-store-info-item">
<text class="store-txt1">{{ bookInfo.orglib || '暂无' }}</text>
<text class="store-txt2">所属馆</text>
</view>
<view class="book-store-info-item">
<text class="store-txt1">{{ bookInfo.loancount || 0 }}</text>
<text class="store-txt2">在馆</text>
</view>
<!-- 编目=1,在馆=2,借出=3,丢失=4,剔除=5,交换=6,赠送=7,装订=8,锁定=9,预借=10 清点=12 -->
<view class="book-store-info-item">
<text class="store-txt1">{{ stateText }}</text>
<text class="store-txt2">馆藏状态</text>
</view>
</view>
<!-- 索书号/条码号 -->
<view v-if="bookInfo.collection" class="store-info-list">
<view class="store-info-item" v-for="(item, index) in bookInfo.collection" :key="index">
<view>
<text>索书号</text>
<text>{{ item.callno || '暂无' }}</text>
</view>
<view>
<text>条码号</text>
<text>{{ item.barcode || '暂无' }}</text>
</view>
</view>
</view>
<!-- TAB 选项卡 -->
<view class="content-tab">
<view class="tab-item" :class="{active: currentTab === 0}" @click="currentTab = 0">
内容简介
</view>
<view class="tab-item" :class="{active: currentTab === 1}" @click="currentTab = 1">
作者简介
</view>
</view>
<!-- TAB 内容 -->
<view class="content-item" v-if="currentTab === 0">
{{ bookInfo.summary || bookInfo.explain || '暂无内容简介' }}
</view>
<view class="content-item" v-if="currentTab === 1">
{{ bookInfo.authorbio || '暂无作者简介' }}
</view>
<view class="detail-bottom">
<button open-type="share" class="handle-btn">
<uni-icons custom-prefix="iconfont" type="icon-fenxiang01" size="20"></uni-icons>
<text class="share-text">分享</text>
</button>
<button class="handle-btn" @click="toggleCollect">
<uni-icons :type="isCollected ? 'heart-filled' : 'heart'" size="20" color="#ff4444"></uni-icons>
<text class="share-text">{{ isCollected ? '已收藏' : '收藏' }}</text>
</button>
</view>
</view>
</template>
<script>
import { FetchInitScreenSetting } from '@/api/user';
import { FetchFindbookByQuery } from '@/api/book';
import config from '@/utils/config';
export default {
data() {
return {
baseUrl: config.baseUrl,
currentTab: 0,
isCollected: false,
bookrecno: '',
opacUrl: '',
bookInfo: {} // 图书详情
};
},
onLoad(options) {
// 接收从首页带过来的完整图书数据
if (options.bookData) {
const bookData = JSON.parse(decodeURIComponent(options.bookData));
this.bookInfo = bookData; // 直接赋值渲染
this.bookrecno = bookData.bookrecno || "";
this.checkCollectStatus();
return;
}
// 如果是从检索页过来(走bookrecno请求)
this.bookrecno = options.bookrecno || "";
this.getOpacUrl();
},
computed: {
// 馆藏状态转换:数字 → 文字
stateText() {
const state = this.bookInfo.state || 0
const map = {
1: '编目',
2: '在馆',
3: '借出',
4: '丢失',
5: '剔除',
6: '交换',
7: '赠送',
8: '装订',
9: '锁定',
10: '预借',
12: '清点'
}
return map[state] || '未知'
}
},
methods: {
onImgError(e) {
e.target.src = "/static/images/default-book.png";
},
// 获取配置
async getOpacUrl() {
try {
const res = await FetchInitScreenSetting({ libcode: '1201' });
this.opacUrl = res.data.opac_url?.context || '';
this.getBookDetail();
} catch (err) {}
},
// 获取图书详情
async getBookDetail() {
if (!this.bookrecno || !this.opacUrl) return;
uni.showLoading({ title: '加载中...' });
try {
const params = {
opacUrl: this.opacUrl,
bookrecno: this.bookrecno
};
const res = await FetchFindbookByQuery(params);
// 解析数据
let detail = {};
if (typeof res.data === 'string') {
detail = JSON.parse(res.data);
} else {
detail = res.data || {};
}
this.bookInfo = detail;
this.checkCollectStatus();
} catch (err) {
} finally {
uni.hideLoading();
}
},
// 收藏逻辑
checkCollectStatus() {
const list = uni.getStorageSync('collectList') || [];
this.isCollected = list.includes(this.bookrecno);
},
toggleCollect() {
let list = uni.getStorageSync('collectList') || [];
if (this.isCollected) {
list = list.filter(i => i !== this.bookrecno);
uni.showToast({ title: '取消收藏', icon: 'success' });
} else {
list.push(this.bookrecno);
uni.showToast({ title: '收藏成功', icon: 'success' });
}
uni.setStorageSync('collectList', list);
this.isCollected = !this.isCollected;
}
},
onShareAppMessage() {
return {
title: this.bookInfo.title || '图书详情',
path: '/subpkg/pages/book-detail/book-detail?bookrecno=' + this.bookrecno,
imageUrl: this.bookInfo.cover
};
}
};
</script>
<style lang="scss" scoped>
.detail-container {
padding: 15px;
background-color: #f5f5f5;
min-height: 100vh;
padding-bottom: 60px;
}
/* 书籍信息 */
.article-detail-container {
display: flex;
background-color: #fff;
border-radius: 10px;
padding: 20px;
margin-bottom: 12px;
}
.article-detail-left {
flex: 1;
}
.article-detail-title {
font-size: 20px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.article-detail-info {
font-size: 14px;
color: #666;
line-height: 1.5;
}
.article-detail-right {
width: 110px;
height: 150px;
margin-left: 15px;
}
.article-detail-right image {
width: 100%;
height: 100%;
border-radius: 6px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
/* 馆藏统计 */
.book-store-info {
background-color: #fff;
border-radius: 10px;
padding: 20px;
display: flex;
justify-content: space-around;
margin-bottom: 12px;
}
.book-store-info-item {
display: flex;
flex-direction: column;
align-items: center;
}
.store-txt1 {
font-size: 22px;
font-weight: bold;
color: #2b85e4;
}
.store-txt2 {
font-size: 13px;
color: #999;
margin-top: 4px;
}
/* 索书号 */
.store-info-list {
background-color: #fff;
border-radius: 10px;
padding: 20px;
margin-bottom: 15px;
}
.store-info-item {
display: flex;
justify-content: space-between;
font-size: 14px;
color: #666;
}
.store-info-item view {
display: flex;
flex-direction: column;
align-items: center;
}
/* TAB */
.content-tab {
display: flex;
background-color: #fff;
border-radius: 10px;
overflow: hidden;
margin-bottom: 12px;
}
.tab-item {
flex: 1;
text-align: center;
padding: 15px 0;
font-size: 15px;
color: #666;
position: relative;
}
.tab-item.active {
color: #2b85e4;
font-weight: bold;
}
.tab-item.active::after {
content: "";
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 30px;
height: 3px;
background-color: #2b85e4;
border-radius: 2px;
}
/* 内容区域 */
.content-item {
background-color: #fff;
border-radius: 10px;
padding: 20px;
font-size: 15px;
color: #333;
line-height: 1.6;
}
.detail-bottom{
justify-content: space-around;
}
</style>