Prechádzať zdrojové kódy

feat(components): 提取课程卡片为独立组件并优化样式结构

将 Home.vue 和 SearchPlatform.vue 中的课程卡片抽取为单独的 CourseCard 组件,
统一管理样式与结构,提升代码复用性和可维护性。同时删除冗余的内联样式定义,
引入全局样式类名,并修复部分 SCSS 变量引用错误。

此外,在 SearchPlatform.vue 中新增分页组件 Pagination 的使用,完善页面功能结构;
调整搜索栏及类型筛选区域布局,增强视觉一致性与用户体验。
zhangningning 6 dní pred
rodič
commit
2ded1c7d2b

+ 45 - 0
src/components/Pagination.vue

@@ -0,0 +1,45 @@
+<!-- src/components/Pagination.vue -->
+<template>
+  <div class="pagination-container">
+    <el-pagination
+      background
+      layout="prev, pager, next, total"
+      :total="total"
+      :page-size="pageSize"
+      :current-page="currentPage"
+      @current-change="handleCurrentChange"
+    />
+  </div>
+</template>
+
+<script setup>
+defineProps({
+  total: {
+    type: Number,
+    default: 0
+  },
+  pageSize: {
+    type: Number,
+    default: 10
+  },
+  currentPage: {
+    type: Number,
+    default: 1
+  }
+})
+
+const emit = defineEmits(['update:currentPage', 'pageChange'])
+
+const handleCurrentChange = (page) => {
+  emit('update:currentPage', page)
+  emit('pageChange', page)
+}
+</script>
+
+<style scoped>
+.pagination-container {
+  display: flex;
+  justify-content: center;
+  margin-top: 20px;
+}
+</style>

+ 66 - 0
src/components/course-card.vue

@@ -0,0 +1,66 @@
+<template>
+  <div class="course-card">
+    <div class="flex-center-between">
+      <img :src="n8Icon" alt="" style="width: 50px; height: 50px;" class="mr10">
+      <div class="line2 font_size18 line_height22 font_weight400">
+        【Linux】【操作】Linux操作集锦系列之十五——如何破解pdf如何破解pdf如何破解pdf如何破解pdf如何破解pdf
+      </div>
+    </div>
+    <div class="mt16 gap10">
+      <img :src="yunIcon" alt="" style="width: 16px; height: 16px;">
+      <div class="font_size13">n8n平台</div>
+      <img :src="riliIcon" alt="" style="width: 16px; height: 16px;">
+      <div class="font_size13">2023-10-15</div>
+    </div>
+    <div class="mt16 line3 gray font_size13">
+      - 本文介绍两款开源的密码破解工具John the Ripper和PDFCrack,用于破解PDF、Word、Excel、ZIP、RAR等文件的密码。John the Ripper支持字典和暴力破解两种模
+    </div>
+    <div class="gap10 mt16">
+      <el-button type="primary" class="flex_1" size="large" plain>
+        <el-icon class="mr10"><Document /></el-icon>
+        查看详情
+      </el-button>
+      <el-button type="primary" class="flex_1" size="large">
+        <el-icon class="mr10"><VideoPlay /></el-icon>
+        开始使用
+      </el-button>
+    </div>
+  </div>
+</template>
+<script setup>
+import n8Icon from '@/assets/imgs/8n8.png'
+import yunIcon from '@/assets/imgs/yun.png'
+import riliIcon from '@/assets/imgs/rili.png'
+const props = defineProps({
+  // 视频地址
+  info: {
+    type: Object,
+    default: () => ({})
+  }
+});
+</script>
+
+<style scoped lang="scss">
+.course-card {
+  border: 1px solid #ffffff;
+  // background-color: rgba(255, 255, 255, 0.5);
+  background-color: #ffffff;
+  border-radius: 8px;
+  padding: 16px;
+  overflow: hidden;
+  cursor: pointer;
+  transition: transform 0.3s;
+  
+  &:hover {
+    transform: translateY(-5px);
+    box-shadow: 0 5px 15px rgba(0,0,0,0.1);
+  }
+  .line2{
+    //hover 显示下划线
+    text-decoration: none;
+    &:hover{
+      text-decoration: underline;
+    }
+  }
+}
+</style>

+ 2 - 49
src/pages/Home.vue

@@ -63,34 +63,7 @@
     <!-- 工作流列表 -->
     <div class="course-list">
       <div class="course-grid">
-        <div class="course-card" v-for="item in 4" :key="item">
-          <div class="flex-center-between">
-            <img :src="n8Icon" alt="" style="width: 50px; height: 50px;" class="mr10">
-            <div class="line2 font_size14 line_height22 font_weight400">
-              【Linux】【操作】Linux操作集锦系列之十五——如何破解pdf如何破解pdf如何破解pdf如何破解pdf如何破解pdf
-            </div>
-          </div>
-          <div class="mt16 gap10">
-            <img :src="yunIcon" alt="" style="width: 16px; height: 16px;">
-            <div class="font_size13">n8n平台</div>
-            <img :src="riliIcon" alt="" style="width: 16px; height: 16px;">
-            <div class="font_size13">2023-10-15</div>
-          </div>
-          <div class="mt16 line3 gray font_size13">
-            - 本文介绍两款开源的密码破解工具John the Ripper和PDFCrack,用于破解PDF、Word、Excel、ZIP、RAR等文件的密码。John the Ripper支持字典和暴力破解两种模
-          </div>
-          <div class="gap10 mt16">
-            <el-button type="primary" class="flex_1" size="large" plain>
-              <el-icon class="mr10"><Document /></el-icon>
-              查看详情
-            </el-button>
-            <el-button type="primary" class="flex_1" size="large">
-              <el-icon class="mr10"><VideoPlay /></el-icon>
-              开始使用
-            </el-button>
-          </div>
-        </div>
-        
+        <CourseCard v-for="item in 4" :key="item" />
       </div>
     </div>
     
@@ -105,9 +78,8 @@ import n8Icon from '@/assets/imgs/8n8.png'
 import cozeIcon from '@/assets/imgs/coze.png'
 import difyIcon from '@/assets/imgs/dify.png'
 import fastgptIcon from '@/assets/imgs/FastGPT.png'
-import yunIcon from '@/assets/imgs/yun.png'
-import riliIcon from '@/assets/imgs/rili.png'
 import detailIcon from '@/assets/imgs/detail.png'
+import CourseCard from '@/components/course-card.vue'
 
 
 import { onMounted,ref } from 'vue'
@@ -333,25 +305,6 @@ $height-btn: 50px;
 .home-page{
   .course-list{
     margin-top: 70px;
-    .course-grid {
-      display: grid;
-      grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
-      gap: 20px;
-    }
-    .course-card {
-      border: 1px solid #ffffff;
-      background-color: rgba(255, 255, 255, 0.5);
-      border-radius: 8px;
-      padding: 16px;
-      overflow: hidden;
-      cursor: pointer;
-      transition: transform 0.3s;
-      
-      &:hover {
-        transform: translateY(-5px);
-        box-shadow: 0 5px 15px rgba(0,0,0,0.1);
-      }
-    }
   }
 }
 </style>

+ 153 - 5
src/pages/SearchPlatform.vue

@@ -1,21 +1,77 @@
 <template>
   <div class="search-platform container-height">
     <div v-if="!isChildRoute">
-      {{currentPath}}
       <Breadcrumb />
-      <h1 @click="goWorkflowDetail">{{activePlatform}}</h1>
-      <h1 @click="goWorkflowAdd">创建工作流</h1>
+      <div class="padding16 bg_color_fff border_radius_16">
+        <!-- 搜索与创建区域 -->
+        <div class="search-create-bar">
+          <div class="search-input-container flex_1">
+            <input
+              type="text"
+              :placeholder="$t('common.qingshuruyaosousuodegongzuoliu')"
+              class="search-input"
+            />
+            <button class="search-btn bg_color_primary" @click.stop.prevent="goSearchPlatform">
+              <img :src="searchIcon" alt="" class="icon-search">
+              {{$t('common.shousuo')}}
+            </button>
+          </div>
+          <button class="create-btn bg_color_primary" @click.stop.prevent="goWorkflowAdd">
+            <img :src="addIcon" alt="" class="icon-add">
+            {{$t('common.chuangjiangongzuoliu')}}
+          </button>
+          <div class="flex-center-between border_radius_10 pad20" style="background: #EAF0FF;height: 56px;">
+            <img :src="n8Icon" alt="" style="width: 30px; height: 30px;" class="mr10">
+            <div class="font_size18 color_theme">前往{{activePlatform}}</div>
+            <el-icon :size="24" color="#2D71FF"><CaretRight /></el-icon>
+          </div>
+        </div>
+        <div class="typeList flex-between typeborder">
+          <div class="gray font_size14 typeName">类型:</div>
+          <div class="flex_1 gap10">
+            <div class="font_size14 typeItem active" v-for="item in 5" :key="item">全部</div>
+          </div>
+        </div>
+        <div class="typeList flex-between">
+          <div class="gray font_size14 typeName">二级分类:</div>
+          <div class="flex_1 gap10">
+            <div class="font_size14 typeItem active" v-for="item in 5" :key="item">全部</div>
+          </div>
+        </div>
+      </div>
+      <!-- 课程列表 -->
+      <div class="course-list mt20">
+        <div class="course-grid">
+          <CourseCard v-for="item in 4" :key="item" />
+        </div>
+      </div>
+      <!-- 分页 -->
+      <!-- 替换原有的分页代码 -->
+      <Pagination 
+        :total="pagination.total"
+        :page-size="pagination.pageSize"
+        :current-page="pagination.currentPage"
+        @page-change="handlePageChange"
+      />
     </div>
     <router-view />
   </div>
 </template>
 
 <script setup>
+  import searchIcon from '@/assets/imgs/search.png'
+  import addIcon from '@/assets/imgs/add.png'
+  import n8Icon from '@/assets/imgs/8n8.png'
+
+  import CourseCard from '@/components/course-card.vue'
+  import Pagination from '@/components/Pagination.vue'
+
+
   import { useRouter, useRoute } from 'vue-router'
   const router = useRouter()
   const route = useRoute()
   console.log(router,route)
-  import { ref, computed } from 'vue'
+  import { ref, computed, reactive } from 'vue'
   //获取参数
   const query = router.currentRoute.value.query
   const activePlatform = ref(query.activePlatform || '')
@@ -24,6 +80,19 @@
   const isChildRoute = computed(() => {
     return route.matched.length > 1
   })
+  // 添加分页相关数据
+  const pagination = reactive({
+    currentPage: 1,
+    pageSize: 10,
+    total: 100
+  })
+  const handlePageChange = (page) => {
+    pagination.currentPage = page
+    // 这里可以添加获取数据的逻辑
+    console.log('当前页:', page)
+  }
+
+
   const goWorkflowDetail = () => {
     //增加参数名称
     router.push({
@@ -45,7 +114,86 @@
 </script>
 
 <style scoped lang="scss">
-.search-platform {
+  // 2. 混合器:按钮通用样式
+@mixin btn-style() {
+  padding: 0 16px;
+  color: #ffffff;
+  border: none;
+  border-radius: 10px;
+  cursor: pointer;
+  display: flex;
+  align-items: center;
+  gap:8px;
+  font-size: 18px;
   
+  &:hover {
+    opacity: 0.9;
+  }
+}
+.search-platform {
+ 
+  // 搜索创建栏嵌套
+  .search-create-bar {
+    display: flex;
+    align-items: center;
+    gap: 8px;
+    background-color: rgba(255, 255, 255, 0.5);
+    border-radius: 10px;
+
+    .search-input {
+      flex: 1;
+      height: 60px;
+      padding: 0 12px;
+      outline: none;
+      font-size: 18px;
+      border-radius:7px;
+      border: none;
+      width: 100%;
+      //占位符的颜色
+      ::placeholder {
+        color: #999;
+      }
+    }
+
+    .search-btn {
+      height: 50px;
+      @include btn-style();
+    }
+
+    .create-btn {
+      height: 56px;
+      @include btn-style();
+    }
+    .search-input-container{
+      position: relative;
+      border-radius: 8px;
+      border:2px solid $primary-color;
+      .search-btn{
+        position: absolute;
+        top: 6px;
+        right: 16px;
+      }
+    }
+  }
+  .typeList{
+    padding: 20px 0;
+    &.typeborder{
+      border-bottom: 1px dashed #DCDFE6;
+    }
+    .typeName{
+      margin-top: 6px;
+      width: 80px;
+    }
+    .typeItem{
+      margin: 0 8px;
+      &.active{
+        background: rgba(45,113,255,0.1);
+        border-radius: 4px 4px 4px 4px;
+        padding: 4px 8px;
+        color: $primary-color;
+        font-weight: 600;
+      }
+    }
+  }
 }
 </style>

+ 25 - 8
src/styles/index.scss

@@ -14,9 +14,9 @@ $danger-color: #e63946; // 危险色(价格、警告等)
 		border-color: $primary-color;
 	}
 	&.is-plain {
-		color: $primary-color;
+		// color: $primary-color;
 		border:none;
-		background-color: #ffffff;
+		// background-color: #ffffff;
 	}
 }
 .container-height {
@@ -103,6 +103,9 @@ wx-image{
 .padding12 {
 	padding: 12px
 }
+.padding16 {
+	padding: 16px
+}
 .padding20 {
 	padding: 20px
 }
@@ -398,12 +401,20 @@ wx-image{
 	justify-content: flex-start;
 	align-items: center;
 	gap: 10px;
+	 flex-wrap:wrap ;
+}
+//课程网格布局
+.course-grid {
+	display: grid;
+	grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
+	gap: 20px;
 }
+
 .order_btn{
 	font-size: 25px;
 	color: #ffffff;
 	border-radius:10px;
-	background-color: primary-color;
+	background-color: $primary-color;
 	&.error{
 		background-color: #E93323;
 	}
@@ -435,7 +446,7 @@ wx-image{
 	background-color: #ffffff;
 }
 .bg_color_primary{
-	background-color: primary-color;
+	background-color: $primary-color;
 }
 .bg_gradient_primary{
 	background: linear-gradient(180deg, #0089FF 0%, #F5F7FA  50%);
@@ -449,6 +460,9 @@ wx-image{
 .border_radius_10{
 	border-radius: 10px;
 }
+.border_radius_16{
+	border-radius: 16px;
+}
 .border_radius_20{
 	border-radius: 20px;
 }
@@ -488,6 +502,9 @@ wx-image{
 .font_size24{
 	font-size: 24px;
 }
+.font_size18{
+	font-size: 18px;
+}
 .font_size14{
 	font-size: 14px;
 }
@@ -500,7 +517,7 @@ wx-image{
 .line_vertical{
 	width: 8px;
 	height: 30px;
-	background-color: primary-color;
+	background-color: $primary-color;
 	border-radius: 4px;
 }
 .color_price{
@@ -516,7 +533,7 @@ wx-image{
 	color: #000000;
 }
 .color_theme{
-	color: primary-color;
+	color: $primary-color;
 }
 
 .text_align_center{
@@ -577,7 +594,7 @@ wx-image{
     transition: all 0.3s;
 
     &.checked {
-      border-color: primary-color;
+      border-color: $primary-color;
 
       &::after {
         content: "";
@@ -587,7 +604,7 @@ wx-image{
         transform: translate(-50%, -50%);
         width: 20px;
         height: 20px;
-        background: primary-color;
+        background: $primary-color;
         border-radius: 50%;
       }
     }