- <template>
- <div class="book-card" @click="goToDetail">
- <div class="book-cover">
- <img :src="book.image" :alt="book.title">
- <!-- 原创标签 -->
- <div v-if="book.isOriginal == 'Y'" class="tag original">原创</div>
- </div>
- <div class="book-info">
- <h3 class="book-title">{{ book.name }}</h3>
- <p class="book-author">作者:{{ book.author }}</p>
- <p class="book-intro" v-if="book.details">{{ book.details }}</p>
- <div class="book-status">
- <span class="status-tag" :class="statusClass">{{ statusText }}</span>
- <span class="reading-count">{{ book.service }}</span>
- </div>
- </div>
- </div>
- </template>
-
- <script>
- import { computed } from 'vue';
- import { useRouter } from 'vue-router';
-
- export default {
- name: 'BookCard',
- props: {
- book: {
- type: Object,
- required: true,
- default: () => ({
- id: '',
- title: '',
- author: '',
- description: '',
- cover: '',
- status: '',
- readCount: 0
- })
- }
- },
- setup(props) {
- const router = useRouter();
-
- const goToDetail = () => {
- router.push({
- path: `/book/${props.book.id}`
- });
- };
-
- // 状态文本映射
- const statusText = computed(() => {
- const status = props.book.status;
- if (status === 1 || status === '1' || status === 'completed') {
- return '已完结';
- }
- return '连载中';
- });
-
- // 状态样式类映射
- const statusClass = computed(() => {
- const status = props.book.status;
- if (status === 1 || status === '1' || status === 'completed') {
- return 'completed';
- }
- return 'serializing';
- });
-
- return {
- goToDetail,
- statusText,
- statusClass
- };
- }
- };
- </script>
-
- <style lang="scss" scoped>
- @use '@/assets/styles/variables.scss' as vars;
-
- .book-card {
- display: flex;
- border-radius: 4px;
- overflow: hidden;
- transition: all 0.3s;
- cursor: pointer;
- background-color: #fff;
- margin-bottom: 15px;
-
-
- .book-cover {
- width: 100px;
- min-width: 100px;
- height: 140px;
- overflow: hidden;
- position: relative;
-
- img {
- width: 100%;
- height: 100%;
- object-fit: cover;
- border-radius: 4px;
- }
-
- .tag {
- position: absolute;
- top: 0;
- left: 0;
- font-size: 12px;
- color: #fff;
- padding: 2px 8px;
- border-radius: 0 0 4px 0;
-
- &.original {
- background-color: #ffa502;
- }
- }
- }
-
- .book-info {
- flex: 1;
- padding: 12px;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-
- .book-title {
- margin: 0 0 6px;
- font-size: 16px;
- font-weight: bold;
- color: #333;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- .book-author {
- font-size: 14px;
- color: #666;
- margin: 0 0 8px;
- }
-
- .book-intro {
- font-size: 12px;
- color: #999;
- line-height: 1.5;
- margin: 0 0 auto;
- overflow: hidden;
- text-overflow: ellipsis;
- display: -webkit-box;
- -webkit-line-clamp: 2;
- -webkit-box-orient: vertical;
- }
-
- .book-status {
- margin-top: 8px;
- display: flex;
- align-items: center;
- gap: 10px;
-
- .status-tag {
- padding: 2px 8px;
- border-radius: 10px;
- font-size: 12px;
-
- &.serializing {
- background-color: #67C23A33;
- color: #67C23A;
- }
-
- &.completed {
- background-color: #409EFF33;
- color: #409EFF;
- }
- }
-
- .reading-count {
- font-size: 12px;
- color: #999;
- }
- }
- }
- }
- </style>
|