Home.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <template>
  2. <div class="home">
  3. <h1>{{ currentTab === 2 ? '篮球直播' : '足球直播' }}</h1>
  4. <div class="tabs">
  5. <span :class="{ active: currentTab === 1 }" @click="changeTab(1)">足球</span>
  6. <span :class="{ active: currentTab === 2 }" @click="changeTab(2)">篮球</span>
  7. </div>
  8. <div v-if="loading" class="loading">加载中...</div>
  9. <div v-else-if="liveList.length" class="grid">
  10. <LiveCard
  11. v-for="item in liveList"
  12. :key="item._id"
  13. :live="item"
  14. @click="goToPlayer(item)"
  15. >
  16. <template #default>
  17. <div v-if="item.videoUrl">
  18. <!-- LiveCard 默认内容 -->
  19. </div>
  20. <div v-else>
  21. <!-- 检查 item.image 是否是 base64 字符串 -->
  22. <img :src="isBase64(item.image) ? item.image : item.image || 'https://via.placeholder.com/300x180?text=Live'" alt="动画预览" class="preview-img" />
  23. <p class="preview-text">播放动画中</p>
  24. </div>
  25. </template>
  26. </LiveCard>
  27. </div>
  28. <div v-else class="empty">暂无直播</div>
  29. </div>
  30. </template>
  31. <script setup>
  32. import { ref, onMounted } from 'vue'
  33. import LiveCard from '../components/LiveCard.vue'
  34. import { useRouter } from 'vue-router'
  35. import axios from 'axios'
  36. const router = useRouter()
  37. const liveList = ref([])
  38. const loading = ref(true)
  39. const currentTab = ref(1) // 1 足球 2 篮球
  40. // 判断是否是 base64 字符串
  41. // const isBase64 = (str) => {
  42. // const regex = /^data:image\/[a-z]+;base64,/i
  43. // return regex.test(str)
  44. // }
  45. const isBase64 = (str) => {
  46. return typeof str === 'string' && /^data:image\/[a-z]+;base64,/i.test(str)
  47. }
  48. const getCurrentDate = () => {
  49. const now = new Date()
  50. const year = now.getFullYear()
  51. const month = String(now.getMonth() + 1).padStart(2, '0')
  52. const day = String(now.getDate()).padStart(2, '0')
  53. return `${year}${month}${day}`
  54. }
  55. const fetchLiveList = async () => {
  56. loading.value = true
  57. try {
  58. // const res = await axios.post('/api/animation_new', {
  59. // authentication: 'd1c6b578c986f869000ec44e85091751',
  60. // date: getCurrentDate(),
  61. // lang: 1,
  62. // sportId: currentTab.value
  63. // })
  64. const type = currentTab.value === 1 ? 'live_football' : 'live_basketball'
  65. // console.log(type)
  66. const res = await axios.post('http://api.csqionghua.com/live_data.php?type='+type)
  67. //console.log('返回数据:', res.data.data)
  68. if (res.data.code === 200) {
  69. liveList.value = res.data.data
  70. .filter(item => item.videoUrl && item.videoUrl.trim() !== '') // 过滤掉没有 videoUrl 的项
  71. .sort((a, b) => new Date(b.matchTime) - new Date(a.matchTime)) // 按时间倒序
  72. .map(item => ({
  73. ...item,
  74. title: `${item.homeTeam} VS ${item.awayTeam}`,
  75. subtitle: item.competition,
  76. viewers: 0,
  77. image: item.thumb ? 'data:image/jpeg;base64,' + item.thumb : '' || 'https://via.placeholder.com/300x180?text=Live'
  78. }))
  79. }
  80. } catch (err) {
  81. console.error('Fetch error:', err)
  82. } finally {
  83. loading.value = false
  84. }
  85. }
  86. const changeTab = (tab) => {
  87. if (currentTab.value !== tab) {
  88. currentTab.value = tab
  89. fetchLiveList()
  90. }
  91. }
  92. const goToPlayer = (item) => {
  93. router.push({
  94. name: 'Player',
  95. params: { id: item._id },
  96. query: { title: item.title, videoUrl: item.videoUrl }
  97. })
  98. }
  99. onMounted(fetchLiveList)
  100. </script>
  101. <style>
  102. .grid {
  103. display: grid;
  104. flex-wrap: wrap;
  105. grid-template-columns: repeat(auto-fill, minmax(159px, 1fr));
  106. gap: 16px;
  107. }
  108. @media (max-width: 600px) {
  109. .grid {
  110. grid-template-columns: repeat(2, 1fr); /* 保证竖屏时至少2列 */
  111. }
  112. }
  113. .preview-img {
  114. width: 100%;
  115. height: 120px;
  116. object-fit: cover;
  117. border-radius: 8px;
  118. }
  119. .preview-text {
  120. text-align: center;
  121. margin-top: 8px;
  122. font-size: 14px;
  123. color: #999;
  124. }
  125. .empty {
  126. text-align: center;
  127. margin-top: 40px;
  128. font-size: 18px;
  129. color: #888;
  130. }
  131. .loading {
  132. text-align: center;
  133. margin-top: 40px;
  134. font-size: 18px;
  135. color: #555;
  136. }
  137. .tabs {
  138. display: flex;
  139. justify-content: flex-start;
  140. margin: 16px 0;
  141. padding-bottom: 8px;
  142. border-bottom: 1px dashed #f88;
  143. }
  144. .tabs span {
  145. margin-right: 24px;
  146. font-size: 18px;
  147. font-weight: 500;
  148. cursor: pointer;
  149. color: #333;
  150. position: relative;
  151. }
  152. .tabs span.active {
  153. color: #000;
  154. }
  155. .tabs span.active::after {
  156. content: '';
  157. position: absolute;
  158. bottom: -5px;
  159. left: 0;
  160. width: 100%;
  161. height: 3px;
  162. background: #000;
  163. border-radius: 2px;
  164. }
  165. </style>