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

182 lines
4.5 KiB

  1. <template>
  2. <div class="book-card" @click="goToDetail">
  3. <div class="book-cover">
  4. <img :src="book.image" :alt="book.title">
  5. <!-- 原创标签 -->
  6. <div v-if="book.isOriginal == 'Y'" class="tag original">原创</div>
  7. </div>
  8. <div class="book-info">
  9. <h3 class="book-title">{{ book.name }}</h3>
  10. <p class="book-author">作者{{ book.author }}</p>
  11. <p class="book-intro" v-if="book.details">{{ book.details }}</p>
  12. <div class="book-status">
  13. <span class="status-tag" :class="statusClass">{{ statusText }}</span>
  14. <span class="reading-count">{{ book.service }}</span>
  15. </div>
  16. </div>
  17. </div>
  18. </template>
  19. <script>
  20. import { computed } from 'vue';
  21. import { useRouter } from 'vue-router';
  22. export default {
  23. name: 'BookCard',
  24. props: {
  25. book: {
  26. type: Object,
  27. required: true,
  28. default: () => ({
  29. id: '',
  30. title: '',
  31. author: '',
  32. description: '',
  33. cover: '',
  34. status: '',
  35. readCount: 0
  36. })
  37. }
  38. },
  39. setup(props) {
  40. const router = useRouter();
  41. const goToDetail = () => {
  42. router.push({
  43. path: `/book/${props.book.id}`
  44. });
  45. };
  46. // 状态文本映射
  47. const statusText = computed(() => {
  48. const status = props.book.status;
  49. if (status === 1 || status === '1' || status === 'completed') {
  50. return '已完结';
  51. }
  52. return '连载中';
  53. });
  54. // 状态样式类映射
  55. const statusClass = computed(() => {
  56. const status = props.book.status;
  57. if (status === 1 || status === '1' || status === 'completed') {
  58. return 'completed';
  59. }
  60. return 'serializing';
  61. });
  62. return {
  63. goToDetail,
  64. statusText,
  65. statusClass
  66. };
  67. }
  68. };
  69. </script>
  70. <style lang="scss" scoped>
  71. @use '@/assets/styles/variables.scss' as vars;
  72. .book-card {
  73. display: flex;
  74. border-radius: 4px;
  75. overflow: hidden;
  76. transition: all 0.3s;
  77. cursor: pointer;
  78. background-color: #fff;
  79. margin-bottom: 15px;
  80. .book-cover {
  81. width: 100px;
  82. min-width: 100px;
  83. height: 140px;
  84. overflow: hidden;
  85. position: relative;
  86. img {
  87. width: 100%;
  88. height: 100%;
  89. object-fit: cover;
  90. border-radius: 4px;
  91. }
  92. .tag {
  93. position: absolute;
  94. top: 0;
  95. left: 0;
  96. font-size: 12px;
  97. color: #fff;
  98. padding: 2px 8px;
  99. border-radius: 0 0 4px 0;
  100. &.original {
  101. background-color: #ffa502;
  102. }
  103. }
  104. }
  105. .book-info {
  106. flex: 1;
  107. padding: 12px;
  108. display: flex;
  109. flex-direction: column;
  110. justify-content: space-between;
  111. .book-title {
  112. margin: 0 0 6px;
  113. font-size: 16px;
  114. font-weight: bold;
  115. color: #333;
  116. overflow: hidden;
  117. text-overflow: ellipsis;
  118. white-space: nowrap;
  119. }
  120. .book-author {
  121. font-size: 14px;
  122. color: #666;
  123. margin: 0 0 8px;
  124. }
  125. .book-intro {
  126. font-size: 12px;
  127. color: #999;
  128. line-height: 1.5;
  129. margin: 0 0 auto;
  130. overflow: hidden;
  131. text-overflow: ellipsis;
  132. display: -webkit-box;
  133. -webkit-line-clamp: 2;
  134. -webkit-box-orient: vertical;
  135. }
  136. .book-status {
  137. margin-top: 8px;
  138. display: flex;
  139. align-items: center;
  140. gap: 10px;
  141. .status-tag {
  142. padding: 2px 8px;
  143. border-radius: 10px;
  144. font-size: 12px;
  145. &.serializing {
  146. background-color: #67C23A33;
  147. color: #67C23A;
  148. }
  149. &.completed {
  150. background-color: #409EFF33;
  151. color: #409EFF;
  152. }
  153. }
  154. .reading-count {
  155. font-size: 12px;
  156. color: #999;
  157. }
  158. }
  159. }
  160. }
  161. </style>