小说网站前端代码仓库
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.
 
 
 
 

479 lines
17 KiB

<template>
<div class="book-detail-container">
<!-- 小说基本信息部分 -->
<div class="book-info-wrapper">
<div class="book-info">
<div class="book-cover">
<img :src="book.cover" :alt="book.title">
</div>
<div class="book-details">
<h1 class="book-title">{{ book.title }}</h1>
<div class="book-meta">
<div class="meta-item">
<span class="label">作者</span>
<span class="value">{{ book.author }}</span>
</div>
<div class="meta-item book-status-row">
<span class="status-badge">{{ book.status }}</span>
<span class="dot">·</span>
<span class="reading-tip">大家都在读</span>
</div>
</div>
<div class="book-user-info">
<div class="user-badges">
<img class="level-icon" src="@/assets/images/book/level.png" alt="我的等级" />
<span class="badge-label">我的等级</span>
</div>
<div class="user-medal">
<img class="medal-icon" src="@/assets/images/image-1.png" alt="勋章" />
</div>
<div class="user-avatar-block">
<img class="user-avatar" src="@/assets/images/center/headImage.png" alt="用户头像" />
<span class="user-name">小巴</span>
<span class="dot">·</span>
<span class="user-title">VIP会员</span>
</div>
<span class="user-intimacy">1000 累计亲密值</span>
</div>
<div class="action-buttons">
<div class="action-btn-group">
<el-button class="reward-btn" plain @click="showRewardDialog">互动打赏</el-button>
</div>
<div class="action-btn-group">
<el-button
:class="['add-to-shelf-btn', isInShelf ? 'in-shelf' : '']"
:type="isInShelf ? '' : 'primary'"
@click="toggleShelf"
>{{ isInShelf ? '已加入书架' : '加入书架' }}</el-button>
</div>
<div class="action-btn-group">
<el-button class="read-btn"
@click="goToChapter(1)"
style="background:#0A2463;color:#fff;border:none;">点击阅读</el-button>
</div>
</div>
</div>
</div>
</div>
<!-- 主体内容区域左右分栏 -->
<div class="book-main-content">
<div class="main-left">
<!-- 推荐票/亲密值统计 -->
<BookStats :book-id="book.id" />
<!-- 小说介绍 -->
<BookIntro :book-data="book" />
<!-- 目录 -->
<BookCatalog :book-id="book.id" />
<!-- 评论 -->
<BookComments :book-id="book.id" />
</div>
<div class="main-right">
<!-- 读者亲密值榜单 -->
<IntimacyRanking :book-id="book.id" />
</div>
</div>
</div>
<!-- 互动打赏弹窗 -->
<InteractiveReward
v-model:visible="rewardDialogVisible"
:book-id="book.id"
@reward-success="handleRewardSuccess"
/>
</template>
<script>
import { ref, reactive, onMounted, onBeforeUnmount } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import BookCard from '@/components/common/BookCard.vue';
import BookStats from '@/components/book/BookStats.vue';
import BookIntro from '@/components/book/BookIntro.vue';
import BookCatalog from '@/components/book/BookCatalog.vue';
import BookComments from '@/components/book/BookComments.vue';
import IntimacyRanking from '@/components/ranking/IntimacyRanking.vue';
import InteractiveReward from '@/components/book/InteractiveReward.vue';
export default {
name: 'BookDetail',
components: {
BookCard,
BookStats,
BookIntro,
BookCatalog,
BookComments,
IntimacyRanking,
InteractiveReward
},
setup() {
const route = useRoute();
const router = useRouter();
const bookId = route.params.id;
const book = reactive({
id: bookId,
title: '重生之财源滚滚',
author: '老鹰的沙',
category: '都市小说',
status: '已完结',
userGroup: '638781087(网友交流群)',
cover: 'https://bookcover.yuewen.com/qdbimg/349573/1041637443/150.webp',
description: `<p>当那一世——</p>
<p>贺季宁曾经是A市土豪公司的金牌经理,工资高福利好,女友漂亮车位靓,最重要的是老板信任他。但是贺季宁的对手不服,老板娘不喜欢他,不怀好意的对手们联合一起,终于把他拉下台了,他失去工作,更可悲的是,他连公司配他的贷款的房子都搭进去了,欠了几百万的债,女友也离他而去。</p>
<p>临终前,他喃喃自语:如果老天给我重来一次的机会,我一定要好好做人,赚很多钱,让那帮人看着我过得好就比他们难受!</p>`,
userGroup: '638781087(网友交流群)',
chapters: [
{ id: '1', title: '第一章 重回2004', isNew: false },
{ id: '2', title: '第二章 旧车旧房', isNew: false },
{ id: '3', title: '第三章 再拼一把', isNew: false },
{ id: '4', title: '第四章 带女朋友逛街', isNew: false },
{ id: '5', title: '第五章 小刺激', isNew: false },
{ id: '6', title: '第六章 老王的门道', isNew: false },
{ id: '7', title: '第七章 正中家门', isNew: false },
{ id: '8', title: '第八章 被逼迫的交易', isNew: false },
{ id: '9', title: '第九章 意外惊喜', isNew: false },
{ id: '10', title: '第十章 生意的桥梁', isNew: true },
{ id: '11', title: '第十一章 家族分崩离析', isNew: false },
{ id: '12', title: '第十二章 老张没来', isNew: false }
],
comments: [
{
username: '万年捧',
avatar: 'https://thirdwx.qlogo.cn/mmopen/vi_32/Q0j4TwGTfTKlR5PibUEEsVjXGfH4c1eR5hXDicoH0EJUTHYwDO3EvZLXXgON8GrNTbRg8DnzaddicibYnGcfq28tYg/132',
time: '2022-07-03',
content: '这是本年内看的唯一一部完结的!看的人真幸运,发家文和风险防控写的都是一流'
},
{
username: '残生往事',
avatar: 'https://thirdwx.qlogo.cn/mmopen/vi_32/3F4feeHnMyoGjqKfP8vGKCHwyvovMHiaO0Q1QkQMRTGibLcyJbUcUJ4LmdkkDqC5ZcqP1rvqKMviaYAyehqYb6ciaA/132',
content: '我很喜欢男主的性格,不小心眼,有格局,做事情多考虑下一步,商业和情感都处理得不错,就是那个林涵有点没必要吧?'
}
]
});
// 推荐书籍
const recommendedBooks = reactive([
{
id: '101',
title: '三体',
author: '刘慈欣',
cover: 'https://picsum.photos/120/160?random=1',
status: '已完结'
},
{
id: '102',
title: '活着',
author: '余华',
cover: 'https://picsum.photos/120/160?random=2',
status: '已完结'
},
{
id: '103',
title: '平凡的世界',
author: '路遥',
cover: 'https://picsum.photos/120/160?random=3',
status: '已完结'
},
{
id: '104',
title: '围城',
author: '钱钟书',
cover: 'https://picsum.photos/120/160?random=4',
status: '已完结'
}
]);
const activeTab = ref('intro');
const currentPage = ref(1);
const commentText = ref('');
const isInShelf = ref(false);
const rewardDialogVisible = ref(false);
const handlePageChange = (page) => {
currentPage.value = page;
// 实际应用中这里应该加载对应页的数据
};
// 创建一个清理函数
const cleanup = () => {
// 清理所有响应式数据
Object.keys(book).forEach(key => {
if (typeof book[key] === 'object') {
book[key] = null;
}
});
activeTab.value = 'intro';
currentPage.value = 1;
commentText.value = '';
isInShelf.value = false;
rewardDialogVisible.value = false;
};
// 在组件销毁前清理
onBeforeUnmount(() => {
cleanup();
});
// 修改路由导航方式
const goToChapter = (chapterId) => {
cleanup();
router.push({
name: 'ChapterDetail',
params: {
id: bookId,
chapterId: chapterId
}
});
};
const submitComment = () => {
if (!commentText.value.trim()) {
ElMessage.warning('请输入评论内容');
return;
}
// 实际应用中这里应该调用API提交评论
book.comments.unshift({
username: '当前用户',
avatar: 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png',
time: new Date().toLocaleString(),
content: commentText.value
});
commentText.value = '';
};
const toggleShelf = () => {
isInShelf.value = !isInShelf.value;
};
const showRewardDialog = () => {
rewardDialogVisible.value = true;
};
const handleRewardSuccess = (items) => {
console.log('打赏成功,打赏项目:', items);
// 这里可以添加刷新亲密值或其他相关数据的逻辑
};
onMounted(() => {
// 实际应用中这里应该根据bookId从API获取书籍详情
console.log('加载书籍详情,ID:', bookId);
});
return {
book,
recommendedBooks,
activeTab,
currentPage,
commentText,
handlePageChange,
goToChapter,
submitComment,
isInShelf,
toggleShelf,
rewardDialogVisible,
showRewardDialog,
handleRewardSuccess,
cleanup
};
}
};
</script>
<style lang="scss" scoped>
@use '@/assets/styles/variables.scss' as vars;
.book-detail-container {
width: 100%;
background-color: #f5f5f5;
}
// 小说基本信息部分
.book-info-wrapper {
background-color: #fff;
padding: 30px 0;
border-bottom: 1px solid #eee;
.book-info {
display: flex;
max-width: 1200px;
margin: 0 auto;
padding: 0 20px;
.book-cover {
width: 165px;
height: 220px;
margin-right: 30px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
img {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 6px;
}
}
.book-details {
flex: 1;
.book-title {
font-size: 24px;
font-weight: bold;
margin: 0 0 15px 0;
color: #333;
}
.book-meta {
margin-bottom: 8px;
.book-status-row {
display: flex;
align-items: center;
font-size: 15px;
margin-top: 10px;
.status-badge {
background: #eaffea;
color: #52c41a;
border-radius: 6px;
padding: 2px 12px;
font-size: 15px;
font-weight: 500;
margin-right: 8px;
}
.dot {
color: #d1d1d1;
margin: 0 8px;
font-size: 18px;
}
.reading-tip {
color: #bdbdbd;
font-size: 15px;
}
}
}
.book-user-info {
display: flex;
align-items: center;
margin-bottom: 18px;
.user-badges {
display: flex;
align-items: center;
margin-right: 18px;
.level-icon {
width: 36px;
height: 36px;
}
.badge-label {
color: #b88a4a;
font-size: 14px;
margin-left: 4px;
}
}
.user-medal {
margin-right: 18px;
.medal-icon {
width: 44px;
height: 44px;
}
}
.user-avatar-block {
display: flex;
align-items: center;
margin-right: 18px;
.user-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
margin-right: 8px;
}
.user-name {
color: #222;
font-size: 16px;
font-weight: 500;
margin-right: 4px;
}
.dot {
color: #d1d1d1;
margin: 0 8px;
font-size: 18px;
}
.user-title {
background: #ede6ff;
color: #a97cff;
border-radius: 8px;
padding: 2px 10px;
font-size: 15px;
margin-left: 2px;
}
}
.user-intimacy {
color: #bdbdbd;
font-size: 15px;
}
}
.action-buttons {
display: flex;
gap: 24px;
margin-top: 10px;
.action-btn-group {
display: flex;
flex-direction: column;
align-items: center;
.el-button {
width: 140px;
height: 40px;
font-size: 16px;
border-radius: 4px;
margin: 0;
font-weight: 500;
}
.diamond-icon {
width: 28px;
height: 18px;
margin-top: 4px;
}
.reward-btn {
color: #0A2463;
border: 1.5px solid #0A2463;
background: #fff;
}
.add-to-shelf-btn {
background: #FF7C6A;
color: #fff;
border: none;
}
.add-to-shelf-btn.in-shelf {
background: #fff;
color: #FF7C6A;
border: 1.5px solid #FF7C6A;
}
.read-btn {
background: #0A2463;
color: #fff;
border: none;
}
}
}
}
}
}
.book-main-content {
display: flex;
gap: 3px;
margin-top: 20px;
.main-left {
flex: 1.8;
min-width: 0;
display: flex;
flex-direction: column;
gap: 3px;
}
.main-right {
flex: 1;
min-width: 220px;
max-width: 280px;
}
}
</style>