Parcourir la source

使用 gemini 优化用户收藏夹页面 AlbumPost.vue

reghao il y a 1 jour
Parent
commit
ce4a7db499
1 fichiers modifiés avec 274 ajouts et 245 suppressions
  1. 274 245
      src/views/post/AlbumPost.vue

+ 274 - 245
src/views/post/AlbumPost.vue

@@ -1,311 +1,340 @@
 <template>
-  <el-container>
-    <el-header height="220">
-      <el-card class="box-card" style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
-        <div v-if="albumInfo !== null" slot="header" class="clearfix">
-          <el-image
-            lazy
-            fit="cover"
-            class="coverImg"
-            :src="albumInfo.coverUrl"
-          />
-          <el-row>
-            <span>当前播放列表</span>
-            <el-select
-              v-model="queryInfo.albumId"
-              clearable
-              placeholder="播放列表"
-              style="margin-left: 5px"
-              @change="onSelectChange"
-            >
-              <el-option
-                v-for="(item, index) in allAlbums"
-                :key="index"
-                :label="item.label"
-                :value="item.value"
-              />
-            </el-select>
-            <span style="padding-left: 20px">
-              <span style="color: blue">{{ albumInfo.total }}</span> 个稿件
-              <span style="color: red">{{ albumInfo.scopeStr }}</span>
-            </span>
-            <el-button style="float: right; padding: 10px" type="text" @click="onPlayAlbum">播放全部</el-button>
-          </el-row>
+  <div class="album-page-container">
+    <header class="album-header-card">
+      <div v-if="albumInfo" class="album-info-wrapper">
+        <div class="album-cover-box">
+          <el-image lazy fit="cover" class="header-cover-img" :src="albumInfo.coverUrl" />
         </div>
-        <div class="text item" />
-      </el-card>
-    </el-header>
-    <el-main>
-      <el-row style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px">
-        <el-col :md="24">
-          <div v-if="dataList.length === 0" align="center">
-            <img src="@/assets/img/not-result.png">
-            <div>还没有收藏呢~</div>
+
+        <div class="album-detail-content">
+          <div class="top-row">
+            <h2 class="album-title">{{ albumInfo.title || '播放列表' }}</h2>
+            <el-button type="primary" size="small" icon="el-icon-video-play" class="play-all-btn" @click="onPlayAlbum">播放全部</el-button>
           </div>
-          <div v-if="dataList.length !== 0">
-            <el-col
-              v-for="(item, index) in dataList"
-              :key="index"
-              :md="6"
-              :sm="12"
-              :xs="12"
-              style="padding-right: 5px; padding-left: 5px; padding-bottom: 5px"
-            >
-              <el-card :body-style="{ padding: '0px' }" class="card">
-                <div class="imgs" style="cursor: pointer" :title="item.title">
-                  <router-link target="_blank" :to="`/video/${item.videoId}`">
-                    <el-image
-                      lazy
-                      fit="cover"
-                      class="coverImg"
-                      :src="item.coverUrl"
-                    />
-                    <span style="position: absolute; top: 0; left: 60%; color:white"> {{ item.duration }} </span>
-                    <span style="position: absolute; bottom: 0; left: 0; color:white">
-                      <i v-if="item.horizontal" class="el-icon-monitor" />
-                      <i v-else class="el-icon-mobile-phone" />
-                    </span>
-                  </router-link>
-                </div>
-                <div style="padding: 14px">
-                  <router-link style="text-decoration-line: none" target="_blank" :to="`/video/${item.videoId}`">
-                    <span style="left: 0;margin-bottom: 0px;color: black;">{{ item.title | ellipsis }}</span>
-                  </router-link>
-                </div>
-                <div style="padding: 14px">
-                  <span style="left: 0;margin-bottom: 0px;color: black;">
-                    <router-link target="_blank" :to="`/user/${item.user.userId}`">
-                      <i class="el-icon-user"> {{ item.user.screenName | ellipsisUsername }} </i></router-link> • {{ item.pubDateStr }}
+
+          <div class="filter-row">
+            <div class="select-group">
+              <span class="label hidden-xs-only">切换列表:</span>
+              <el-select
+                  v-model="queryInfo.albumId"
+                  size="small"
+                  class="album-select"
+                  @change="onSelectChange"
+              >
+                <el-option
+                    v-for="(item, index) in allAlbums"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                />
+              </el-select>
+            </div>
+            <div class="stats-tags">
+              <el-tag size="mini" effect="plain" type="info">{{ albumInfo.total }} 个稿件</el-tag>
+              <el-tag size="mini" effect="plain" type="success" class="mgl-8">{{ albumInfo.scopeStr }}</el-tag>
+            </div>
+          </div>
+        </div>
+      </div>
+    </header>
+
+    <main class="album-main-content">
+      <div v-if="dataList.length === 0" class="empty-status">
+        <el-empty description="暂无收藏内容" :image-size="150"></el-empty>
+      </div>
+
+      <el-row :gutter="20" class="video-grid">
+        <el-col
+            v-for="(item, index) in dataList"
+            :key="index"
+            :xs="12" :sm="8" :md="6" :lg="4" :xl="4"
+            class="video-col"
+        >
+          <el-card :body-style="{ padding: '0px' }" class="video-card" shadow="hover">
+            <div class="card-image-box">
+              <router-link :to="`/video/${item.videoId}`" target="_blank">
+                <el-image lazy fit="cover" class="card-cover" :src="item.coverUrl" />
+                <div class="card-badges">
+                  <span class="duration">{{ item.duration }}</span>
+                  <span class="device-icon">
+                    <i :class="item.horizontal ? 'el-icon-monitor' : 'el-icon-mobile-phone'" />
                   </span>
                 </div>
-                <div style="padding: 14px;">
-                  <el-tooltip class="item" effect="dark" content="删除收藏" placement="top-end">
-                    <el-button
-                      size="mini"
-                      type="danger"
-                      class="el-icon-delete"
-                      @click="onDeleteItem(item)"
-                    />
+              </router-link>
+            </div>
+
+            <div class="card-info">
+              <router-link :to="`/video/${item.videoId}`" target="_blank" class="video-title-link">
+                <h4 class="video-title">{{ item.title }}</h4>
+              </router-link>
+
+              <div class="video-meta">
+                <router-link :to="`/user/${item.user.userId}`" target="_blank" class="user-link">
+                  <i class="el-icon-user" /> {{ item.user.screenName }}
+                </router-link>
+                <span class="pub-date">{{ item.pubDateStr }}</span>
+              </div>
+
+              <div class="card-btns">
+                <el-button-group class="full-width-btns">
+                  <el-tooltip content="设为封面" placement="top" :disabled="screenWidth < 768">
+                    <el-button size="mini" icon="el-icon-picture-outline" @click="onSetCover(item)"></el-button>
                   </el-tooltip>
-                  <el-tooltip class="item" effect="dark" content="设为封面" placement="top-end">
-                    <el-button
-                      size="mini"
-                      type="warning"
-                      class="el-icon-picture-outline"
-                      @click="onSetCover(item)"
-                    />
+                  <el-tooltip content="删除收藏" placement="top" :disabled="screenWidth < 768">
+                    <el-button size="mini" type="danger" plain icon="el-icon-delete" @click="onDeleteItem(item)"></el-button>
                   </el-tooltip>
-                </div>
-              </el-card>
-            </el-col>
-          </div>
+                </el-button-group>
+              </div>
+            </div>
+          </el-card>
         </el-col>
       </el-row>
-      <el-pagination
-        hide-on-single-page
-        :small="screenWidth <= 768"
-        layout="prev, pager, next"
-        :page-size="pageSize"
-        :current-page="currentPage"
-        :total="totalSize"
-        @current-change="handleCurrentChange"
-        @prev-click="handleCurrentChange"
-        @next-click="handleCurrentChange"
-      />
-    </el-main>
-
-    <!-- 创建相册对话框 -->
-    <el-dialog
-      append-to-body
-      :visible.sync="createAlbumDiaglog"
-      width="30%"
-      center
-    />
-  </el-container>
+
+      <div class="pagination-wrapper">
+        <el-pagination
+            background
+            :small="screenWidth < 768"
+            layout="total, prev, pager, next"
+            :page-size="pageSize"
+            :current-page="currentPage"
+            :total="totalSize"
+            @current-change="handleCurrentChange"
+        />
+      </div>
+    </main>
+
+    <el-backtop target=".admin-main"></el-backtop>
+  </div>
 </template>
 
 <script>
-import {
-  collectItem,
-  getAlbumItems,
-  getUserAlbumSelectList
-} from '@/api/collect'
+import { collectItem, getAlbumItems, getUserAlbumSelectList } from '@/api/collect'
 
 export default {
   name: 'AlbumPost',
-  filters: {
-    ellipsis(value) {
-      if (!value) return ''
-      const max = 15
-      if (value.length > max) {
-        return value.slice(0, max) + '...'
-      }
-      return value
-    },
-    ellipsisUsername(value) {
-      if (!value) return ''
-      const max = 10
-      if (value.length > max) {
-        return value.slice(0, max) + '...'
-      }
-      return value
-    }
-  },
   data() {
     return {
-      allAlbums: [
-        { label: '全部', value: 1 }
-      ],
-      queryInfo: {
-        albumId: null,
-        pn: 1
-      },
-      // 屏幕宽度, 为了控制分页条的大小
+      allAlbums: [],
+      queryInfo: { albumId: null, pn: 1 },
       screenWidth: document.body.clientWidth,
       currentPage: 1,
       pageSize: 12,
       totalSize: 0,
       dataList: [],
-      albumInfo: null,
-      // **********************************************************************
-      createAlbumDiaglog: false
+      albumInfo: null
     }
   },
   created() {
     this.getSelectList()
-    const albumId = this.$route.query.albumId
-    if (albumId !== undefined) {
-      this.queryInfo.albumId = albumId
-    }
-
-    const pn = this.$route.query.pn
-    if (albumId !== undefined) {
-      this.queryInfo.pn = pn
-      this.currentPage = pn
+    const { albumId, pn } = this.$route.query
+    if (albumId) this.queryInfo.albumId = albumId
+    if (pn) {
+      this.queryInfo.pn = parseInt(pn)
+      this.currentPage = parseInt(pn)
     }
-
     this.getData()
-    document.title = '我的播放列表'
+  },
+  mounted() {
+    window.addEventListener('resize', this.handleResize)
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.handleResize)
   },
   methods: {
+    handleResize() {
+      this.screenWidth = document.body.clientWidth
+    },
     onSelectChange() {
       this.queryInfo.pn = 1
       this.currentPage = 1
-      this.getData()
-      this.$router.push({
-        path: '/bg/my/album',
-        query: this.queryInfo
-      })
+      this.updateRouteAndData()
     },
-    handleCurrentChange(pageNumber) {
-      this.currentPage = pageNumber
-      this.queryInfo.pn = pageNumber
-      // this.getData()
-      this.$router.push({
-        path: '/bg/my/album',
-        query: this.queryInfo
-      })
-      // 回到顶部
-      scrollTo(0, 0)
+    handleCurrentChange(page) {
+      this.currentPage = page
+      this.queryInfo.pn = page
+      this.updateRouteAndData()
+      const container = document.querySelector('.admin-main')
+      if (container) container.scrollTo({ top: 0, behavior: 'smooth' })
+    },
+    updateRouteAndData() {
+      this.$router.push({ path: '/bg/my/album', query: this.queryInfo })
       this.getData()
     },
     getData() {
       getAlbumItems(this.queryInfo).then(resp => {
         if (resp.code === 0) {
-          const respData = resp.data
-          this.dataList = respData.pageList.list
-          this.totalSize = respData.pageList.totalSize
-          this.albumInfo = respData.albumInfo
+          this.dataList = resp.data.pageList.list
+          this.totalSize = resp.data.pageList.totalSize
+          this.albumInfo = resp.data.albumInfo
           this.queryInfo.albumId = this.albumInfo.albumId
         }
-      }).catch(error => {
-        this.$message({
-          message: error.message,
-          type: 'error',
-          duration: 1000
-        })
       })
     },
     getSelectList() {
       getUserAlbumSelectList().then(resp => {
-        if (resp.code === 0) {
-          this.allAlbums = resp.data
-        }
+        if (resp.code === 0) this.allAlbums = resp.data
       })
     },
-    // 设为封面
     onSetCover(item) {
-      const jsonData = {}
-      jsonData.albumId = this.albumInfo.albumId
-      jsonData.postId = item.videoId
-      jsonData.action = 3
-      collectItem(jsonData).then(res => {
+      collectItem({ albumId: this.albumInfo.albumId, postId: item.videoId, action: 3 }).then(res => {
         if (res.code === 0) {
-          this.$message({
-            type: 'success',
-            message: '封面已更新!'
-          })
+          this.$message.success('已更新封面')
+          this.getData()
         }
       })
     },
-    // 移除收藏
     onDeleteItem(item) {
-      this.$confirm('确认删除本收藏?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        const jsonData = {}
-        jsonData.albumId = this.albumInfo.albumId
-        jsonData.postId = item.videoId
-        jsonData.action = 2
-        collectItem(jsonData).then(res => {
+      this.$confirm('确定移除该收藏吗?', '提示', { type: 'warning' }).then(() => {
+        collectItem({ albumId: this.albumInfo.albumId, postId: item.videoId, action: 2 }).then(res => {
           if (res.code === 0) {
-            this.$router.go(0)
+            this.$message.success('已移除')
+            this.getData()
           }
         })
-      }).catch(() => {
-        this.$message({
-          type: 'info',
-          message: '已取消'
-        })
-      })
+      }).catch(() => {})
     },
-    onPlayAlbum() {
-      this.$message.info('暂未实现')
-    }
+    onPlayAlbum() { this.$message.info('播放列表功能建设中') }
   }
 }
 </script>
 
-<style>
-/*处于手机屏幕时*/
-@media screen and (max-width: 768px) {
-  .tit {
-    font-weight: 600;
-    font-size: 12px;
-    height: 32px;
-  }
-  .time {
-    font-size: 10px;
-    color: #999;
-  }
-  .num {
-    font-size: 9px;
-    padding-top: 3px;
-  }
-  .bottom {
-    margin-top: 2px;
-    line-height: 7px;
-  }
-  .coverImg {
-    height: 120px !important;
-  }
+<style scoped>
+/* 1. 基础容器与布局修复 */
+.album-page-container {
+  padding: 0;
+  max-width: 1400px; /* 限制 PC 端最大宽度,防止卡片过稀疏 */
+  margin: 0 auto;
 }
 
-.coverImg {
+.album-header-card {
+  background: #fff;
+  border-radius: 8px;
+  padding: 24px;
+  margin-bottom: 20px;
+  box-shadow: 0 2px 12px rgba(0,0,0,0.04);
+}
+
+.album-info-wrapper {
+  display: flex;
+  gap: 24px;
+}
+
+.album-cover-box {
+  width: 180px;
+  height: 110px;
+  flex-shrink: 0;
+  border-radius: 6px;
+  overflow: hidden;
+}
+
+.header-cover-img { width: 100%; height: 100%; }
+
+.album-detail-content { flex: 1; min-width: 0; display: flex; flex-direction: column; justify-content: space-between; }
+
+.top-row { display: flex; justify-content: space-between; align-items: flex-start; }
+
+.album-title { margin: 0; font-size: 20px; color: #303133; font-weight: 600; }
+
+.filter-row { display: flex; align-items: center; justify-content: space-between; margin-top: 15px; }
+
+.select-group { display: flex; align-items: center; }
+
+.album-select { width: 200px; }
+
+.mgl-8 { margin-left: 8px; }
+
+/* 2. 视频卡片 PC 端优化 */
+.video-grid { margin: 0 -10px; } /* 抵消 col 的 padding */
+
+.video-card {
+  border-radius: 8px;
+  border: 1px solid #ebeef5;
+  margin-bottom: 20px;
+  transition: all 0.3s ease;
+}
+
+.card-image-box {
+  position: relative;
   width: 100%;
-  height: 90px;
-  display: block;
+  padding-top: 56.25%; /* 16:9 比例锁定 */
+}
+
+.card-cover {
+  position: absolute;
+  top: 0; left: 0;
+  width: 100%; height: 100%;
+}
+
+.card-badges {
+  position: absolute;
+  bottom: 6px; left: 0; right: 0;
+  padding: 0 8px;
+  display: flex;
+  justify-content: space-between;
+  background: linear-gradient(transparent, rgba(0,0,0,0.6));
+  color: #fff; font-size: 12px;
+}
+
+.card-info { padding: 12px; }
+
+.video-title {
+  margin: 0 0 10px 0;
+  font-size: 14px;
+  height: 40px; /* 两行高度固定 */
+  line-height: 20px;
+  color: #303133;
+  display: -webkit-box;
+  -webkit-line-clamp: 2;
+  -webkit-box-orient: vertical;
+  overflow: hidden;
+}
+
+.video-meta {
+  display: flex;
+  justify-content: space-between;
+  font-size: 12px;
+  color: #909399;
+  margin-bottom: 12px;
+}
+
+.user-link { color: #606266; text-decoration: none; max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.user-link:hover { color: #409EFF; }
+
+/* 按钮组 */
+.full-width-btns { display: flex; width: 100%; }
+.full-width-btns .el-button { flex: 1; }
+
+.pagination-wrapper { padding: 40px 0; display: flex; justify-content: center; }
+
+/* 3. 移动端专项适配修复溢出 */
+@media screen and (max-width: 768px) {
+  .album-header-card { padding: 15px; margin-bottom: 15px; }
+
+  .album-info-wrapper { flex-direction: column; gap: 12px; align-items: center; text-align: center; }
+
+  .album-cover-box { width: 140px; height: 85px; }
+
+  .top-row { flex-direction: column; align-items: center; gap: 10px; }
+
+  .album-title { font-size: 16px; }
+
+  .filter-row { flex-direction: column; gap: 10px; align-items: stretch; }
+
+  .album-select { width: 100%; }
+
+  .video-grid { margin: 0 -5px; }
+
+  .video-col { padding: 0 5px !important; }
+
+  .video-title { font-size: 13px; height: 36px; line-height: 18px; margin-bottom: 6px; }
+
+  .video-meta { flex-direction: column; gap: 4px; margin-bottom: 8px; }
+
+  .card-info { padding: 8px; }
+}
+
+/* 隐藏辅助类 */
+@media screen and (max-width: 767px) {
+  .hidden-xs-only { display: none !important; }
 }
 </style>