<template>
|
|
<div class="bookshelf-container">
|
|
<div class="bookshelf-header">
|
|
<h1 class="bookshelf-title">我的书架</h1>
|
|
<div class="bookshelf-actions">
|
|
<el-button type="warning" class="clear-btn" @click="confirmClearBookshelf" :disabled="loading">清空书架</el-button>
|
|
<el-button type="danger" class="delete-btn" @click="toggleDeleteMode" :disabled="loading">{{ deleteMode ? '取消删除' : '删除书本' }}</el-button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 加载状态 -->
|
|
<div v-if="loading" class="loading-container">
|
|
<el-skeleton :rows="4" animated />
|
|
</div>
|
|
|
|
<div v-else-if="bookList.length === 0" class="empty-bookshelf">
|
|
<div class="empty-text">您的书架还没有书籍,去书城逛逛吧~</div>
|
|
<el-button type="primary" @click="goToHome">去书城看看</el-button>
|
|
</div>
|
|
|
|
<div v-else class="bookshelf-content">
|
|
<div class="book-grid">
|
|
<bookshelfCard
|
|
v-for="book in bookList"
|
|
:key="book.id"
|
|
:book="book"
|
|
:delete-mode="deleteMode"
|
|
@click="goToReadBook"
|
|
@delete="removeBook"
|
|
/>
|
|
</div>
|
|
|
|
<!-- 分页组件 -->
|
|
<div class="pagination-container" v-if="pagination.total > 0">
|
|
<el-pagination
|
|
v-model:current-page="pagination.pageNo"
|
|
v-model:page-size="pagination.pageSize"
|
|
:total="pagination.total"
|
|
layout="prev, pager, next"
|
|
background
|
|
@size-change="handleSizeChange"
|
|
@current-change="handleCurrentChange"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 确认清空书架的对话框 -->
|
|
<el-dialog
|
|
v-model="clearConfirmVisible"
|
|
title="确认清空"
|
|
width="30%"
|
|
>
|
|
<span>确定要清空书架吗?此操作不可恢复!</span>
|
|
<template #footer>
|
|
<span class="dialog-footer">
|
|
<el-button @click="clearConfirmVisible = false">取消</el-button>
|
|
<el-button type="primary" @click="clearBookshelf" :loading="clearLoading">确定</el-button>
|
|
</span>
|
|
</template>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { ref, reactive, onMounted } from 'vue';
|
|
import { useRouter } from 'vue-router';
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
import bookshelfCard from '@/components/bookshelf/bookshelfCard.vue';
|
|
import { bookshelfApi } from '@/api/bookshelf.js';
|
|
import { homeApi } from '@/api/modules.js';
|
|
|
|
export default {
|
|
name: 'BookshelfView',
|
|
components: {
|
|
bookshelfCard
|
|
},
|
|
setup() {
|
|
const router = useRouter();
|
|
const deleteMode = ref(false);
|
|
const clearConfirmVisible = ref(false);
|
|
const loading = ref(false);
|
|
const clearLoading = ref(false);
|
|
const bookList = ref([]);
|
|
|
|
// 分页数据
|
|
const pagination = reactive({
|
|
pageNo: 1,
|
|
pageSize: 20,
|
|
total: 0
|
|
});
|
|
|
|
// 获取书架列表
|
|
const getBookshelfList = async () => {
|
|
try {
|
|
loading.value = true;
|
|
const params = {
|
|
pageNo: pagination.pageNo,
|
|
pageSize: pagination.pageSize
|
|
};
|
|
|
|
const response = await bookshelfApi.getReadBookPage(params);
|
|
|
|
if (response.result && response.code == 200) {
|
|
const data = response.result;
|
|
bookList.value = data.records || [];
|
|
pagination.total = data.total || 0;
|
|
} else {
|
|
ElMessage.error(response?.message || '获取书架数据失败');
|
|
}
|
|
} catch (error) {
|
|
console.error('获取书架数据失败:', error);
|
|
ElMessage.error('获取书架数据失败,请稍后重试');
|
|
} finally {
|
|
loading.value = false;
|
|
}
|
|
};
|
|
|
|
// 跳转到阅读页面
|
|
const goToReadBook = async (book) => {
|
|
if (deleteMode.value) return; // 删除模式下不跳转
|
|
|
|
if(book.novelId){
|
|
// 先验证章节是否存在
|
|
try {
|
|
const chapterResponse = await homeApi.getBookCatalogDetail(book.novelId);
|
|
if (chapterResponse && chapterResponse.success && chapterResponse.result) {
|
|
// 章节存在,直接跳转
|
|
router.push({
|
|
name: 'ChapterDetail',
|
|
params: {
|
|
id: book.shopId,
|
|
chapterId: book.novelId
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
} catch (error) {
|
|
console.warn('章节不存在或获取失败,将跳转到第一章:', error);
|
|
}
|
|
// 如果章节不存在,继续执行下面的逻辑获取第一章
|
|
}
|
|
|
|
// 获取章节目录
|
|
try {
|
|
const response = await homeApi.getBookCatalogList({
|
|
bookId: book.shopId,
|
|
pageNo: 1,
|
|
pageSize: 1, // 获取第一章
|
|
});
|
|
|
|
if (response.success && response.result) {
|
|
// 处理章节数据格式
|
|
const catalogData = response.result.records || response.result || [];
|
|
|
|
if(catalogData[0]){
|
|
router.push({
|
|
name: 'ChapterDetail',
|
|
params: {
|
|
id: book.shopId,
|
|
chapterId: catalogData[0].id
|
|
}
|
|
});
|
|
}else{
|
|
ElMessage.info('暂无章节内容');
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error('获取章节目录失败:', error);
|
|
ElMessage.error('获取章节失败,请稍后重试');
|
|
}
|
|
};
|
|
|
|
// 跳转到首页
|
|
const goToHome = () => {
|
|
router.push('/');
|
|
};
|
|
|
|
// 切换删除模式
|
|
const toggleDeleteMode = () => {
|
|
deleteMode.value = !deleteMode.value;
|
|
};
|
|
|
|
// 移除书籍
|
|
const removeBook = async (bookId) => {
|
|
try {
|
|
await ElMessageBox.confirm('确定要将该书从书架中移除吗?', '提示', {
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
});
|
|
|
|
const response = await bookshelfApi.removeReadBook(bookId);
|
|
|
|
if (response && response.code === 200) {
|
|
ElMessage({
|
|
type: 'success',
|
|
message: '已从书架移除'
|
|
});
|
|
// 刷新列表
|
|
await getBookshelfList();
|
|
} else {
|
|
ElMessage.error(response?.message || '移除失败');
|
|
}
|
|
} catch (error) {
|
|
if (error !== 'cancel') {
|
|
console.error('移除书籍失败:', error);
|
|
ElMessage.error('移除失败,请稍后重试');
|
|
}
|
|
}
|
|
};
|
|
|
|
// 确认清空书架
|
|
const confirmClearBookshelf = () => {
|
|
if (bookList.value.length === 0) {
|
|
ElMessage.info('书架已经是空的了');
|
|
return;
|
|
}
|
|
clearConfirmVisible.value = true;
|
|
};
|
|
|
|
// 清空书架
|
|
const clearBookshelf = async () => {
|
|
try {
|
|
clearLoading.value = true;
|
|
|
|
// 获取所有书籍ID
|
|
const bookIds = bookList.value.map(book => book.id).join(',');
|
|
|
|
if (!bookIds) {
|
|
ElMessage.info('没有需要清空的书籍');
|
|
clearConfirmVisible.value = false;
|
|
return;
|
|
}
|
|
|
|
const response = await bookshelfApi.batchRemoveReadBook(bookIds);
|
|
|
|
if (response && response.code === 200) {
|
|
clearConfirmVisible.value = false;
|
|
ElMessage({
|
|
type: 'success',
|
|
message: '书架已清空'
|
|
});
|
|
// 刷新列表
|
|
await getBookshelfList();
|
|
} else {
|
|
ElMessage.error(response?.message || '清空失败');
|
|
}
|
|
} catch (error) {
|
|
console.error('清空书架失败:', error);
|
|
ElMessage.error('清空失败,请稍后重试');
|
|
} finally {
|
|
clearLoading.value = false;
|
|
}
|
|
};
|
|
|
|
// 分页大小改变
|
|
const handleSizeChange = (size) => {
|
|
pagination.pageSize = size;
|
|
pagination.pageNo = 1; // 重置到第一页
|
|
getBookshelfList();
|
|
};
|
|
|
|
// 当前页改变
|
|
const handleCurrentChange = (page) => {
|
|
pagination.pageNo = page;
|
|
getBookshelfList();
|
|
};
|
|
|
|
onMounted(() => {
|
|
getBookshelfList();
|
|
});
|
|
|
|
return {
|
|
bookList,
|
|
deleteMode,
|
|
clearConfirmVisible,
|
|
loading,
|
|
clearLoading,
|
|
pagination,
|
|
goToReadBook,
|
|
goToHome,
|
|
toggleDeleteMode,
|
|
removeBook,
|
|
confirmClearBookshelf,
|
|
clearBookshelf,
|
|
handleSizeChange,
|
|
handleCurrentChange,
|
|
getBookshelfList
|
|
};
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
@use '@/assets/styles/variables.scss' as vars;
|
|
|
|
.bookshelf-container {
|
|
width: 100%;
|
|
background-color: #fff;
|
|
min-height: calc(100vh - 60px);
|
|
padding: 20px;
|
|
}
|
|
|
|
.bookshelf-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 30px;
|
|
padding-bottom: 15px;
|
|
border-bottom: 2px solid #f0f0f0;
|
|
|
|
.bookshelf-title {
|
|
font-size: 20px;
|
|
font-weight: bold;
|
|
color: #333;
|
|
position: relative;
|
|
padding-left: 15px;
|
|
|
|
&::before {
|
|
content: '';
|
|
position: absolute;
|
|
left: 0;
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
height: 20px;
|
|
width: 4px;
|
|
background-color: vars.$primary-color;
|
|
border-radius: 2px;
|
|
}
|
|
}
|
|
|
|
.bookshelf-actions {
|
|
display: flex;
|
|
gap: 10px;
|
|
|
|
.clear-btn, .delete-btn {
|
|
font-size: 14px;
|
|
}
|
|
}
|
|
}
|
|
|
|
.loading-container {
|
|
padding: 20px;
|
|
}
|
|
|
|
.empty-bookshelf {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
justify-content: center;
|
|
padding: 100px 0;
|
|
color: #999;
|
|
|
|
.empty-text {
|
|
margin-bottom: 20px;
|
|
font-size: 16px;
|
|
}
|
|
}
|
|
|
|
.bookshelf-content {
|
|
.book-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(2, 1fr);
|
|
gap: 25px;
|
|
|
|
@media screen and (max-width: 1200px) {
|
|
grid-template-columns: repeat(2, 1fr);
|
|
}
|
|
|
|
@media screen and (max-width: 768px) {
|
|
grid-template-columns: repeat(1, 1fr);
|
|
}
|
|
|
|
@media screen and (max-width: 480px) {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
}
|
|
}
|
|
|
|
.pagination-container {
|
|
display: flex;
|
|
justify-content: center;
|
|
padding: 30px 0 10px 0;
|
|
margin-top: 20px;
|
|
border-top: 1px solid #f0f0f0;
|
|
}
|
|
</style>
|