Преглед изворни кода

使用 gemini 优化 UserHome.vue 和 ImageAlbumCard.vue

reghao пре 1 дан
родитељ
комит
aeb160a69a
2 измењених фајлова са 234 додато и 131 уклоњено
  1. 160 105
      src/components/card/ImageAlbumCard.vue
  2. 74 26
      src/views/user/UserHome.vue

+ 160 - 105
src/components/card/ImageAlbumCard.vue

@@ -1,156 +1,211 @@
 <template>
-  <el-col style="padding-right: 7px; padding-left: 7px">
-    <div style="cursor: pointer">
-      <el-card :body-style="{ padding: '0px' }" class="card">
-        <router-link target="_blank" :to="`/image/${imageAlbum.albumId}`">
-          <div class="imgs">
-            <el-image
+  <el-col :xs="12" :sm="8" :md="6" :lg="4" class="album-col">
+    <div class="album-card-wrapper" @click="handleCardClick">
+      <el-card :body-style="{ padding: '0px' }" class="album-card" shadow="hover">
+        <div class="image-container">
+          <el-image
               lazy
               fit="cover"
               :src="imageAlbum.coverUrl"
-              class="coverImg"
-            />
-            <span style="position: absolute; bottom: 0; right: 0; color:white">
-              <i class="el-icon-picture-outline">{{imageAlbum.total}}</i>
-            </span>
+              class="album-cover"
+          >
+            <div slot="placeholder" class="image-slot">
+              <i class="el-icon-loading"></i>
+            </div>
+          </el-image>
+
+          <div class="count-badge">
+            <i class="el-icon-picture-outline"></i>
+            <span>{{ imageAlbum.total }}</span>
+          </div>
+
+          <div class="image-overlay">
+            <i class="el-icon-view"></i>
+          </div>
+        </div>
+
+        <div class="album-info">
+          <div class="album-title">{{ imageAlbum.albumName }}</div>
+          <div class="album-meta" v-if="imageAlbum.username">
+            <span class="author">@{{ imageAlbum.username }}</span>
           </div>
-        </router-link>
-        <div style="padding: 14px">
-          <router-link target="_blank" :to="`/image/${imageAlbum.albumId}`">
-            <span style="left: 0;margin-bottom: 0px;color: black;">{{ imageAlbum.albumName | ellipsis }}</span>
-          </router-link>
         </div>
-<!--        <div style="padding: 14px">
-          <span style="left: 0;margin-bottom: 0px;color: black;">
-            <router-link target="_blank" :to="`/user/${imageAlbum.userId}`"><i class="el-icon-user"> {{ imageAlbum.username }} </i></router-link> · {{ imageAlbum.pubDate }}
-          </span>
-        </div>-->
       </el-card>
     </div>
   </el-col>
 </template>
 
 <script>
-import { handleVisited } from 'assets/js/utils'
-
 export default {
   name: 'ImageAlbumCard',
-  filters: {
-    ellipsis(value) {
-      if (!value) return ''
-      const max = 20
-      if (value.length > max) {
-        return value.slice(0, max) + '...'
-      }
-      return value
-    }
-  },
   props: {
     imageAlbum: {
       type: Object,
-      default: null
-    },
-    // 时间前的描述
-    dateTit: {
-      type: String,
-      default: ''
+      required: true,
+      default: () => ({})
     }
   },
   methods: {
-    getVisited(visited) {
-      return handleVisited(visited)
+    handleCardClick() {
+      // 移动端通常直接跳转,PC端建议新窗口打开
+      const url = this.$router.resolve(`/image/${this.imageAlbum.albumId}`).href;
+      window.open(url, '_blank');
     }
   }
 }
 </script>
 
 <style scoped>
-.time {
-  font-size: 15px;
-  color: #999;
+/* 容器布局优化 */
+.album-col {
+  padding: 8px !important; /* 统一间距 */
 }
 
-.bottom {
-  margin-top: 13px;
-  line-height: 12px;
+.album-card-wrapper {
+  cursor: pointer;
+  perspective: 1000px;
 }
 
-.tit {
-  font-weight: 700;
-  font-size: 18px;
+.album-card {
+  border: none !important;
+  border-radius: 12px !important; /* 圆角更大更现代 */
+  overflow: hidden;
+  background: #fff;
+  transition: transform 0.3s ease, box-shadow 0.3s ease;
+}
 
-  height: 50px;
+/* 封面容器逻辑 */
+.image-container {
+  position: relative;
+  width: 100%;
+  aspect-ratio: 4 / 5; /* 保持美观的长宽比,不随图片变形 */
   overflow: hidden;
-  text-overflow: ellipsis;
+  background: #f5f7fa;
+}
+
+.album-cover {
+  width: 100%;
+  height: 100%;
+  transition: transform 0.5s ease;
+}
+
+/* 玻璃拟态角标 */
+.count-badge {
+  position: absolute;
+  bottom: 8px;
+  right: 8px;
+  padding: 4px 8px;
+  background: rgba(0, 0, 0, 0.4);
+  backdrop-filter: blur(4px); /* 背景模糊 */
+  border-radius: 20px;
+  color: #fff;
+  font-size: 11px;
+  display: flex;
+  align-items: center;
+  gap: 4px;
+  z-index: 2;
+}
+
+/* 悬浮遮罩 */
+.image-overlay {
+  position: absolute;
+  inset: 0;
+  background: rgba(0, 0, 0, 0.1);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  opacity: 0;
+  transition: opacity 0.3s;
+  color: #fff;
+  font-size: 24px;
+}
+
+/* 文本区域 */
+.album-info {
+  padding: 10px 12px 14px;
+}
+
+.album-title {
+  font-size: 14px;
+  font-weight: 600;
+  color: #2c3e50;
+  line-height: 1.4;
+  height: 40px; /* 两行高度 */
   display: -webkit-box;
-  -webkit-line-clamp: 2; /*行数*/
   -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+  overflow: hidden;
+  word-break: break-all;
 }
 
-.num {
-  position: relative;
-  font-size: 15px;
-  padding-top: 9px;
+.album-meta {
+  margin-top: 6px;
+  font-size: 12px;
+  color: #909399;
 }
 
-/*处于手机屏幕时*/
-@media screen and (max-width: 768px) {
-  .tit {
-    font-weight: 600;
-    font-size: 12px;
-    height: 32px;
+.author {
+  max-width: 100%;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  display: inline-block;
+}
+
+/* PC 端悬浮动效 */
+@media screen and (min-width: 769px) {
+  .album-card-wrapper:hover .album-card {
+    transform: translateY(-4px);
+    box-shadow: 0 10px 20px rgba(0,0,0,0.1) !important;
   }
-  .time {
-    font-size: 10px;
-    color: #999;
+
+  .album-card-wrapper:hover .album-cover {
+    transform: scale(1.1);
   }
-  .num {
-    font-size: 9px;
-    padding-top: 3px;
+
+  .album-card-wrapper:hover .image-overlay {
+    opacity: 1;
   }
-  .bottom {
-    margin-top: 2px;
-    line-height: 7px;
+}
+
+/* 移动端特殊适配 */
+@media screen and (max-width: 768px) {
+  .album-col {
+    padding: 5px !important;
   }
-  .coverImg {
-    height: 120px !important;
+
+  .album-card {
+    border-radius: 8px !important;
   }
-}
 
-.coverImg {
-  width: 100%;
-  height: 175px;
-  display: block;
-}
+  .album-info {
+    padding: 8px 8px 10px;
+  }
 
-.clearfix:before,
-.clearfix:after {
-  display: table;
-  content: "";
-}
+  .album-title {
+    font-size: 12px;
+    height: 34px;
+    line-height: 1.4;
+  }
 
-.clearfix:after {
-  clear: both;
-}
+  .album-meta {
+    font-size: 10px;
+  }
 
-.card {
-  margin-bottom: 20px;
-  transition: all 0.6s; /*所有属性变化在0.6秒内执行动画*/
+  /* 移动端点击反馈 */
+  .album-card-wrapper:active .album-card {
+    transform: scale(0.97);
+    transition: transform 0.1s;
+  }
 }
 
-/*.card:hover {
-  !*鼠标放上之后元素变成1.06倍大小*!
-  transform: scale(1.06);
-}*/
-.imgs {
-  position: relative;
-}
-.play-icon {
-  position: absolute;
-  /*top: -15px;*/
-  right: 2%;
-  bottom: 5px;
-  z-index: 7;
-  width: 40px;
+.image-slot {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  width: 100%;
+  height: 100%;
+  background: #f5f7fa;
+  color: #909399;
 }
 </style>

+ 74 - 26
src/views/user/UserHome.vue

@@ -1,10 +1,10 @@
 <template>
   <div class="user-home-container">
     <div class="user-header-wrapper">
-      <el-card v-if="user" class="user-info-card" :body-style="{ padding: '20px' }">
+      <el-card v-if="user" class="user-info-card" :body-style="{ padding: isMobile ? '15px' : '20px' }">
         <div class="info-content-top">
           <div class="avatar-section">
-            <el-avatar :size="90" :src="user.avatarUrl" class="user-avatar-main" />
+            <el-avatar :size="isMobile ? 70 : 90" :src="user.avatarUrl" class="user-avatar-main" />
             <el-tag
                 v-if="user.vip"
                 size="mini"
@@ -20,15 +20,22 @@
             <el-button
                 :type="followButton.text === '已关注' ? 'info' : 'danger'"
                 round
-                size="medium"
+                :size="isMobile ? 'small' : 'medium'"
                 :icon="followButton.icon"
                 @click="followUser(user.userId)"
+                class="action-btn-item"
             >
               {{ followButton.text }}
             </el-button>
-            <el-button icon="el-icon-message" round size="medium" @click="sendMessage(user.userId)">发消息</el-button>
+            <el-button
+                icon="el-icon-message"
+                round
+                :size="isMobile ? 'small' : 'medium'"
+                @click="sendMessage(user.userId)"
+                class="action-btn-item"
+            >发消息</el-button>
 
-            <el-dropdown trigger="click" class="more-btn">
+            <el-dropdown trigger="click" class="more-btn" v-if="!isMobile">
               <el-button icon="el-icon-more" circle plain size="medium"></el-button>
               <el-dropdown-menu slot="dropdown">
                 <el-dropdown-item v-if="user.biliUserId">
@@ -64,10 +71,10 @@
     </div>
 
     <div class="user-content-section">
-      <el-tabs v-if="userContentData" v-model="activeName" class="custom-tabs" @tab-click="tabClick">
+      <el-tabs v-if="userContentData" v-model="activeName" class="custom-tabs" @tab-click="tabClick" :stretch="isMobile">
         <el-tab-pane name="video">
           <span slot="label">视频 <span class="tab-count">{{ userContentData.videoCount }}</span></span>
-          <el-row :gutter="15" class="grid-container" v-loading="loading">
+          <el-row :gutter="isMobile ? 10 : 15" class="grid-container" v-loading="loading">
             <el-col v-for="(video, index) in dataList" :key="index" :xs="12" :sm="8" :md="6">
               <video-card :video="video" class="content-card-hover" />
             </el-col>
@@ -76,7 +83,7 @@
 
         <el-tab-pane name="image">
           <span slot="label">图片 <span class="tab-count">{{ userContentData.imageCount }}</span></span>
-          <el-row :gutter="15" class="grid-container" v-loading="loading">
+          <el-row :gutter="isMobile ? 10 : 15" class="grid-container" v-loading="loading">
             <el-col v-for="(album, index) in dataList" :key="index" :xs="12" :sm="8" :md="6">
               <image-album-card :image-album="album" class="content-card-hover" />
             </el-col>
@@ -85,7 +92,7 @@
 
         <el-tab-pane name="album">
           <span slot="label">收藏夹 <span class="tab-count">{{ userContentData.albumCount }}</span></span>
-          <el-row :gutter="15" class="grid-container" v-loading="loading">
+          <el-row :gutter="isMobile ? 10 : 15" class="grid-container" v-loading="loading">
             <el-col v-for="(item, index) in dataList" :key="index" :xs="12" :sm="8" :md="6">
               <el-card :body-style="{ padding: '0px' }" class="playlist-card content-card-hover">
                 <router-link :to="`/playlist/${item.albumId}`" class="no-link-style">
@@ -105,15 +112,16 @@
         </el-tab-pane>
       </el-tabs>
 
-      <el-empty v-if="showEmpty && !loading" :image-size="200" description="该分类下空空如也" />
+      <el-empty v-if="showEmpty && !loading" :image-size="isMobile ? 120 : 200" description="该分类下空空如也" />
 
       <div class="pagination-wrapper" v-if="totalSize > pageSize">
         <el-pagination
             background
-            layout="prev, pager, next"
+            :layout="isMobile ? 'prev, pager, next' : 'prev, pager, next'"
             :current-page="currentPage"
             :page-size="pageSize"
             :total="totalSize"
+            :pager-count="isMobile ? 5 : 7"
             @current-change="handleCurrentChange"
         />
       </div>
@@ -144,20 +152,20 @@ export default {
       dataList: [],
       userContentData: null,
       loading: false,
-      showEmpty: false
+      showEmpty: false,
+      isMobile: false // 标记是否为移动端
     }
   },
   watch: {
-    // 1. 监听路由参数中的 ID 变化 (核心修复)
     '$route.params.id': {
       handler(newId) {
         if (newId) {
           this.userId = newId;
-          this.resetPageState(); // 切换用户时,重置页码和列表
-          this.initUserContext(); // 重新加载用户资料和关系
+          this.resetPageState();
+          this.initUserContext();
         }
       },
-      immediate: true // 确保组件创建时也能触发
+      immediate: true
     },
     '$route.query': {
       handler() {
@@ -169,9 +177,18 @@ export default {
   created() {
     this.userId = this.$route.params.id;
     this.initUserContext();
+    this.checkMobile();
+  },
+  mounted() {
+    window.addEventListener('resize', this.checkMobile);
+  },
+  destroyed() {
+    window.removeEventListener('resize', this.checkMobile);
   },
   methods: {
-    // 新增:切换用户时重置状态,防止数据残留
+    checkMobile() {
+      this.isMobile = window.innerWidth <= 768;
+    },
     resetPageState() {
       this.dataList = [];
       this.currentPage = 1;
@@ -298,7 +315,6 @@ export default {
   background: #fff;
 }
 
-/* 会员 Tag 覆盖在头像上的样式 */
 .vip-tag-overlay {
   position: absolute;
   bottom: 0;
@@ -332,6 +348,7 @@ export default {
   color: #9499a0;
   font-size: 14px;
   margin-bottom: 20px;
+  line-height: 1.5;
 }
 
 .user-stats {
@@ -369,8 +386,8 @@ export default {
 .content-card-hover:hover { transform: translateY(-5px); }
 .no-link-style { text-decoration: none; color: inherit; }
 
-.playlist-card { border-radius: 8px; overflow: hidden; }
-.playlist-cover-wrapper { position: relative; aspect-ratio: 16/9; }
+.playlist-card { border-radius: 8px; overflow: hidden; height: 100%; }
+.playlist-cover-wrapper { position: relative; aspect-ratio: 16/9; width: 100%; overflow: hidden; }
 .playlist-img { width: 100%; height: 100%; }
 .playlist-mask { position: absolute; bottom: 0; right: 0; background: rgba(0,0,0,0.6); color: #fff; padding: 2px 8px; font-size: 12px; border-top-left-radius: 8px; }
 .playlist-info { padding: 10px; text-align: left; }
@@ -378,11 +395,42 @@ export default {
 .pagination-wrapper { margin-top: 30px; display: flex; justify-content: center; }
 
 @media screen and (max-width: 768px) {
-  .user-home-container { padding-top: 10px; }
-  .user-avatar-main { width: 70px !important; height: 70px !important; }
-  .user-name { font-size: 20px; }
-  .vip-tag-overlay { right: -5px; bottom: -2px; }
-  .action-section .el-button { padding: 8px 12px; font-size: 12px; }
-  .more-btn { display: none; }
+  .user-home-container { padding: 10px 0 30px 0; }
+  .user-header-wrapper { padding: 0 10px; }
+  .user-content-section { padding: 0 10px; }
+
+  .info-content-top {
+    flex-direction: column;
+    align-items: flex-start;
+    gap: 15px;
+  }
+
+  .action-section {
+    width: 100%;
+    justify-content: flex-start;
+  }
+
+  .action-btn-item {
+    flex: 1; /* 按钮在移动端平分宽度 */
+    text-align: center;
+  }
+
+  .user-name { font-size: 18px; flex-wrap: wrap; }
+  .user-stats { gap: 20px; }
+  .user-signature { font-size: 13px; margin-bottom: 15px; }
+
+  .custom-tabs /deep/ .el-tabs__header {
+    padding: 0 10px;
+  }
+
+  .grid-container {
+    margin-left: -5px !important;
+    margin-right: -5px !important;
+  }
+
+  .grid-container .el-col {
+    padding-left: 5px !important;
+    padding-right: 5px !important;
+  }
 }
 </style>