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.
189 lines
4.3 KiB
189 lines
4.3 KiB
<template>
|
|
<div class="book-detail-container" v-if="book">
|
|
<el-card class="book-card">
|
|
<div class="book-header">
|
|
<el-image :src="book.url" class="cover-large" fit="cover" />
|
|
<div class="book-info">
|
|
<h1 class="title">{{ book.title }}</h1>
|
|
<div class="meta">
|
|
<!-- <el-tag type="info" size="large">{{ book.content }}</el-tag> -->
|
|
<el-tag type="success" size="large">¥{{ book.money }}/天</el-tag>
|
|
</div>
|
|
<div class="status">
|
|
<el-tag :type="book.state === '正常' ? 'success' : 'danger'" size="large">
|
|
{{ book.state }}
|
|
</el-tag>
|
|
<span>阅读量: {{ book.number }}</span>
|
|
</div>
|
|
<div class="actions">
|
|
<el-button
|
|
type="primary"
|
|
size="large"
|
|
:disabled="book.state !== '正常'"
|
|
@click="borrowBook"
|
|
v-if="!isAdmin">
|
|
立即借阅
|
|
</el-button>
|
|
<el-button
|
|
type="danger"
|
|
size="large"
|
|
@click="deleteBook"
|
|
v-if="isAdmin">
|
|
删除书籍
|
|
</el-button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<el-divider />
|
|
|
|
<div class="book-description">
|
|
<h3>书籍简介</h3>
|
|
<p>{{ book.content || '暂无简介' }}</p>
|
|
</div>
|
|
</el-card>
|
|
</div>
|
|
<el-empty v-else description="书籍不存在" />
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, onMounted, computed } from 'vue'
|
|
import { useRoute, useRouter } from 'vue-router'
|
|
import { useStore } from 'vuex'
|
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
|
|
const route = useRoute()
|
|
const router = useRouter()
|
|
const store = useStore()
|
|
|
|
const book = ref(null)
|
|
const loading = ref(true)
|
|
|
|
const isAdmin = computed(() => store.getters.isAdmin)
|
|
|
|
onMounted(async () => {
|
|
await fetchBook()
|
|
})
|
|
|
|
const fetchBook = async () => {
|
|
try {
|
|
loading.value = true
|
|
const title = route.params.title
|
|
|
|
// 正确传递书名参数
|
|
const response = await store.dispatch('fetchBookByTitle', { title })
|
|
|
|
// 处理API响应格式
|
|
if (response.data && response.data.code === 200) {
|
|
book.value = response.data.data
|
|
} else if (response.data) {
|
|
// 处理没有code字段但直接返回数据的情况
|
|
book.value = response.data
|
|
} else {
|
|
throw new Error('书籍不存在')
|
|
}
|
|
} catch (error) {
|
|
console.error('获取书籍详情失败:', error)
|
|
ElMessage.error(error.message || '获取书籍详情失败')
|
|
|
|
// 使用有意义的预设数据
|
|
book.value = {
|
|
title: route.params.title,
|
|
url: 'https://picsum.photos/id/24/300/400',
|
|
money: 5.00,
|
|
number: 8,
|
|
content: `无法获取《${route.params.title}》的详细信息`,
|
|
state: '维护中',
|
|
}
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
|
|
const borrowBook = async () => {
|
|
try {
|
|
await store.dispatch('borrowBook', { title: book.value.title })
|
|
ElMessage.success(`成功借阅《${book.value.title}》`)
|
|
// 刷新书籍信息
|
|
await fetchBook()
|
|
} catch (error) {
|
|
console.error('借阅失败:', error)
|
|
ElMessage.error(error.message || '借阅失败')
|
|
}
|
|
}
|
|
|
|
const deleteBook = async () => {
|
|
try {
|
|
await ElMessageBox.confirm(
|
|
`确定要删除《${book.value.title}》吗?此操作不可恢复。`,
|
|
'删除确认',
|
|
{
|
|
confirmButtonText: '确定',
|
|
cancelButtonText: '取消',
|
|
type: 'warning'
|
|
}
|
|
)
|
|
|
|
await store.dispatch('deleteBook', { title: book.value.title })
|
|
ElMessage.success('书籍已删除')
|
|
router.push('/books')
|
|
} catch (error) {
|
|
if (error !== 'cancel') {
|
|
console.error('删除失败:', error)
|
|
ElMessage.error('删除失败')
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.book-detail-container {
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
}
|
|
|
|
.book-header {
|
|
display: flex;
|
|
gap: 40px;
|
|
}
|
|
|
|
.cover-large {
|
|
width: 300px;
|
|
height: 400px;
|
|
border-radius: 8px;
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.book-info {
|
|
flex: 1;
|
|
}
|
|
|
|
.title {
|
|
margin-top: 0;
|
|
font-size: 28px;
|
|
}
|
|
|
|
.meta {
|
|
display: flex;
|
|
gap: 10px;
|
|
margin: 20px 0;
|
|
}
|
|
|
|
.status {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 15px;
|
|
font-size: 18px;
|
|
margin: 30px 0;
|
|
}
|
|
|
|
.actions {
|
|
margin-top: 40px;
|
|
}
|
|
|
|
.book-description {
|
|
margin-top: 30px;
|
|
}
|
|
</style> |