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.
pyx_gitkeshe/library_system/src/views/Books/BookList.vue

203 lines
4.5 KiB

<template>
<div class="book-list-container">
<div class="search-bar">
<el-input
v-model="searchKeyword"
placeholder="搜索书名"
clearable
@clear="fetchBooks"
@keyup.enter="fetchBooks"
class="search-input">
<template #append>
<el-button :icon="Search" @click="fetchBooks" />
</template>
</el-input>
<el-button
type="primary"
@click="goToAddBook"
v-if="isAdmin"
class="add-button">
<el-icon><Plus /></el-icon>
添加书籍
</el-button>
</div>
<div class="books-grid">
<el-card
v-for="book in books"
:key="book.id"
class="book-card"
shadow="hover"
@click="goToBookDetail(book.id)">
<div class="book-cover">
<el-image
:src="book.url"
fit="cover"
class="cover-image"
:alt="book.title" />
</div>
<div class="book-info">
<h3 class="book-title">{{ book.title }}</h3>
<div class="book-meta">
<el-tag type="info" size="small">{{ book.content }}</el-tag>
<el-tag type="success" size="small">¥{{ book.money }}/天</el-tag>
</div>
<div class="book-status">
<el-tag
:type="book.state === '正常' ? 'success' : 'danger'"
size="small">
{{ book.state }}
</el-tag>
<span>阅读量: {{ book.number }}次</span>
</div>
</div>
</el-card>
</div>
<div class="pagination">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:total="total"
layout="prev, pager, next, jumper"
@current-change="fetchBooks"
background />
</div>
</div>
</template>
<script setup>
import { ref, onMounted, computed } from 'vue'
import { useRouter } from 'vue-router'
import { useStore } from 'vuex'
import { Search, Plus } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus'
const store = useStore()
const router = useRouter()
const books = ref([])
const searchKeyword = ref('')
const currentPage = ref(1)
const pageSize = ref(12)
const total = ref(0)
const isAdmin = computed(() => store.getters.isAdmin)
onMounted(() => {
fetchBooks()
})
const fetchBooks = async () => {
try {
const params = {
page: currentPage.value,
pageSize: pageSize.value,
keyword: searchKeyword.value
}
const response = await store.dispatch('fetchBooks', params)
books.value = response.data.list
total.value = response.data.total
} catch (error) {
console.error('获取书籍列表失败:', error)
ElMessage.error('获取书籍列表失败')
books.value = [
{ id: 1, title: '三体', url: 'https://picsum.photos/id/24/200/300', money: 5, number: 12, state: '正常', content: '科幻' },
{ id: 2, title: '人类简史', url: 'https://picsum.photos/id/25/200/300', money: 4, number: 10, state: '正常', content: '历史' },
{ id: 3, title: '百年孤独', url: 'https://picsum.photos/id/26/200/300', money: 6, number: 0, state: '维护中', content: '文学' },
]
total.value = books.value.length
}
}
const goToBookDetail = (id) => {
router.push({ name: 'BookDetail', params: { id } })
}
const goToAddBook = () => {
router.push({ name: 'AddBook' })
}
</script>
<style scoped>
.book-list-container {
padding: 20px;
}
.search-bar {
display: flex;
margin-bottom: 20px;
}
.search-input {
width: 300px;
margin-right: 20px;
}
.add-button {
margin-left: auto;
}
.books-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
gap: 20px;
margin-bottom: 30px;
}
.book-card {
cursor: pointer;
transition: transform 0.3s;
}
.book-card:hover {
transform: translateY(-5px);
}
.book-cover {
height: 180px;
overflow: hidden;
border-radius: 4px;
margin-bottom: 15px;
}
.cover-image {
width: 100%;
height: 100%;
object-fit: cover;
}
.book-info {
padding: 0 10px 10px;
}
.book-title {
margin: 0 0 10px;
font-size: 16px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.book-meta {
display: flex;
gap: 5px;
margin-bottom: 10px;
}
.book-status {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 13px;
color: #666;
}
.pagination {
display: flex;
justify-content: center;
margin-top: 20px;
}
</style>