Browse Source

style: 界面改版

chenlei 3 weeks ago
parent
commit
a606a945c7
98 changed files with 1294 additions and 381 deletions
  1. 6 2
      packages/base/src/constants.js
  2. 1 1
      packages/base/src/theme.scss
  3. BIN
      packages/pc/public/fonts/FZBWKSJW--GB1-0.ttf
  4. BIN
      packages/pc/public/fonts/FZQKBYSJW--GB1-0.TTF
  5. BIN
      packages/pc/public/fonts/FZWBJW.TTF
  6. 0 0
      packages/pc/public/fonts/SOURCEHANSERIFCN-BOLD.OTF
  7. 0 0
      packages/pc/public/fonts/SOURCEHANSERIFCN-REGULAR.OTF
  8. 0 0
      packages/pc/public/fonts/SourceHanSansCN-Regular.otf
  9. 5 1
      packages/pc/src/App.vue
  10. BIN
      packages/pc/src/assets/images/logo_02-min.png
  11. BIN
      packages/pc/src/assets/images/logo_04-min.png
  12. BIN
      packages/pc/src/assets/images/mb-bg.png
  13. 14 6
      packages/pc/src/assets/main.css
  14. BIN
      packages/pc/src/components/BookCard/images/bg-min.png
  15. 17 31
      packages/pc/src/components/BookCard/index.vue
  16. 149 30
      packages/pc/src/components/RankPanel/index.vue
  17. 15 19
      packages/pc/src/components/TopNav/components/MobileDialog.vue
  18. BIN
      packages/pc/src/components/TopNav/images/active-bg-min.jpg
  19. BIN
      packages/pc/src/components/TopNav/images/border.png
  20. BIN
      packages/pc/src/components/TopNav/images/detail-btn.png
  21. BIN
      packages/pc/src/components/TopNav/images/icon_font-min.png
  22. BIN
      packages/pc/src/components/TopNav/images/icon_font_active-min.png
  23. BIN
      packages/pc/src/components/TopNav/images/icon_img-min.png
  24. BIN
      packages/pc/src/components/TopNav/images/icon_img_active-min.png
  25. BIN
      packages/pc/src/components/TopNav/images/icon_text-min.png
  26. BIN
      packages/pc/src/components/TopNav/images/icon_text_active-min.png
  27. BIN
      packages/pc/src/components/TopNav/images/icon_video-min.png
  28. BIN
      packages/pc/src/components/TopNav/images/icon_video_active-min.png
  29. BIN
      packages/pc/src/components/TopNav/images/wechat-min.png
  30. 66 29
      packages/pc/src/components/TopNav/index.scss
  31. 20 14
      packages/pc/src/components/TopNav/index.vue
  32. BIN
      packages/pc/src/components/TopNav2/images/icon_book-min.png
  33. BIN
      packages/pc/src/components/TopNav2/images/icon_book_dark-min.png
  34. BIN
      packages/pc/src/components/TopNav2/images/icon_font-min.png
  35. BIN
      packages/pc/src/components/TopNav2/images/icon_font_active-min.png
  36. BIN
      packages/pc/src/components/TopNav2/images/icon_img-min.png
  37. BIN
      packages/pc/src/components/TopNav2/images/icon_img_active-min.png
  38. BIN
      packages/pc/src/components/TopNav2/images/icon_text-min.png
  39. BIN
      packages/pc/src/components/TopNav2/images/icon_text_active-min.png
  40. BIN
      packages/pc/src/components/TopNav2/images/icon_video-min.png
  41. BIN
      packages/pc/src/components/TopNav2/images/icon_video_active-min.png
  42. 168 0
      packages/pc/src/components/TopNav2/index.scss
  43. 250 0
      packages/pc/src/components/TopNav2/index.vue
  44. 27 7
      packages/pc/src/components/TreeMenu.vue
  45. 0 1
      packages/pc/src/router/index.js
  46. 49 61
      packages/pc/src/views/Detail/components/IntroductionDialog.vue
  47. 61 15
      packages/pc/src/views/Detail/components/Reader/index.scss
  48. 69 35
      packages/pc/src/views/Detail/components/Reader/index.vue
  49. BIN
      packages/pc/src/views/Detail/components/Toolbar/images/icon_comment_yellow.png
  50. BIN
      packages/pc/src/views/Detail/components/Toolbar/images/icon_like_yellow.png
  51. BIN
      packages/pc/src/views/Detail/components/Toolbar/images/icon_mark_yellow.png
  52. BIN
      packages/pc/src/views/Detail/components/Toolbar/images/icon_menu_yellow.png
  53. BIN
      packages/pc/src/views/Detail/components/Toolbar/images/icon_search_yellow.png
  54. BIN
      packages/pc/src/views/Detail/components/Toolbar/images/icon_setting_yellow.png
  55. BIN
      packages/pc/src/views/Detail/components/Toolbar/images/icon_share_yellow.png
  56. 6 0
      packages/pc/src/views/Detail/components/Toolbar/index.scss
  57. 32 30
      packages/pc/src/views/Detail/components/Toolbar/index.vue
  58. BIN
      packages/pc/src/views/Detail/images/bg-min.jpg
  59. BIN
      packages/pc/src/views/Detail/images/close-min.png
  60. BIN
      packages/pc/src/views/Detail/images/enlarge.png
  61. BIN
      packages/pc/src/views/Detail/images/footer-bg.png
  62. BIN
      packages/pc/src/views/Detail/images/fullscreen.png
  63. BIN
      packages/pc/src/views/Detail/images/main-bg.png
  64. BIN
      packages/pc/src/views/Detail/images/narrow.png
  65. BIN
      packages/pc/src/views/Detail/images/pagination.png
  66. 15 0
      packages/pc/src/views/Detail/index.scss
  67. 1 0
      packages/pc/src/views/Detail/index.vue
  68. 44 23
      packages/pc/src/views/Home2/components/News.vue
  69. BIN
      packages/pc/src/views/Home2/images/banner.jpg
  70. BIN
      packages/pc/src/views/Home2/images/bg.png
  71. BIN
      packages/pc/src/views/Home2/images/bg2-min.png
  72. BIN
      packages/pc/src/views/Home2/images/icon.png
  73. BIN
      packages/pc/src/views/Home2/images/icon_more-min.png
  74. BIN
      packages/pc/src/views/Home2/images/info-bg.png
  75. BIN
      packages/pc/src/views/Home2/images/item-bg.png
  76. BIN
      packages/pc/src/views/Home2/images/item2-bg.png
  77. BIN
      packages/pc/src/views/Home2/images/news-bd.png
  78. BIN
      packages/pc/src/views/Home2/images/news-bg.jpg
  79. BIN
      packages/pc/src/views/Home2/images/news-icon.png
  80. BIN
      packages/pc/src/views/Home2/images/tab-active.jpg
  81. BIN
      packages/pc/src/views/Home2/images/tab.jpg
  82. BIN
      packages/pc/src/views/Home2/images/text_news-min.png
  83. BIN
      packages/pc/src/views/Home2/images/text_readomg-min.png
  84. BIN
      packages/pc/src/views/Home2/images/text_recommend-min.png
  85. 70 5
      packages/pc/src/views/Home2/index.scss
  86. 44 25
      packages/pc/src/views/Home2/index.vue
  87. 67 0
      packages/pc/src/views/Stack/components/SearchInput/index2.vue
  88. 30 26
      packages/pc/src/views/Stack/components/Sidebar/index.scss
  89. 1 1
      packages/pc/src/views/Stack/components/Sidebar/index.vue
  90. BIN
      packages/pc/src/views/Stack/images/bg.jpg
  91. BIN
      packages/pc/src/views/Stack/images/icon.png
  92. BIN
      packages/pc/src/views/Stack/images/input-bg.png
  93. BIN
      packages/pc/src/views/Stack/images/left-icon.png
  94. BIN
      packages/pc/src/views/Stack/images/right-icon.png
  95. BIN
      packages/pc/src/views/Stack/images/scroll-bg.png
  96. BIN
      packages/pc/src/views/Stack/images/sidebar-bg.png
  97. 54 9
      packages/pc/src/views/Stack/index.scss
  98. 13 10
      packages/pc/src/views/Stack/index.vue

+ 6 - 2
packages/base/src/constants.js

@@ -1,8 +1,8 @@
 export const THEMES = [
   {
     key: "default",
-    color: "#ffffff",
-    textColor: "#464646",
+    color: "#D6C3A6",
+    textColor: "#69512D",
     borderColor: "#D1BB9E",
   },
   {
@@ -27,6 +27,10 @@ export const THEMES = [
 
 export const FONT_FAMILYS = [
   {
+    label: "方正清刻本悦",
+    value: "FZQKBYSJW--GB1-0",
+  },
+  {
     label: "黑体",
     value: "Microsoft Yahei",
   },

+ 1 - 1
packages/base/src/theme.scss

@@ -1,5 +1,5 @@
 html {
-  --topnav-bg-color: #f8f6f2;
+  --topnav-bg-color: #252525;
   --page-bg-color: #f3f3f3;
   --pane-bg-color: white;
   --pane2-bg-color: #fbfbfa;

BIN
packages/pc/public/fonts/FZBWKSJW--GB1-0.ttf


BIN
packages/pc/public/fonts/FZQKBYSJW--GB1-0.TTF


BIN
packages/pc/public/fonts/FZWBJW.TTF


packages/pc/src/assets/fonts/SOURCEHANSERIFCN-BOLD.OTF → packages/pc/public/fonts/SOURCEHANSERIFCN-BOLD.OTF


packages/pc/src/assets/fonts/SOURCEHANSERIFCN-REGULAR.OTF → packages/pc/public/fonts/SOURCEHANSERIFCN-REGULAR.OTF


packages/pc/src/assets/fonts/SourceHanSansCN-Regular.otf → packages/pc/public/fonts/SourceHanSansCN-Regular.otf


+ 5 - 1
packages/pc/src/App.vue

@@ -2,6 +2,7 @@
 import { onMounted } from "vue";
 import { RouterView } from "vue-router";
 import TopNav from "@/components/TopNav/index.vue";
+import TopNav2 from "@/components/TopNav2/index.vue";
 import { useBaseStore } from "./stores";
 
 const baseStore = useBaseStore();
@@ -15,7 +16,10 @@ onMounted(() => {
 
 <template>
   <el-scrollbar wrap-style="min-width: 1100px;" height="100vh">
-    <TopNav />
+    <template v-if="$route.name">
+      <TopNav2 v-if="$route.name === 'home'" />
+      <TopNav v-else />
+    </template>
 
     <RouterView />
   </el-scrollbar>

BIN
packages/pc/src/assets/images/logo_02-min.png


BIN
packages/pc/src/assets/images/logo_04-min.png


BIN
packages/pc/src/assets/images/mb-bg.png


+ 14 - 6
packages/pc/src/assets/main.css

@@ -104,7 +104,7 @@ body,
 input {
   font-size: 14px;
   color: #464646;
-  font-family: "Source Han Sans CN-Regular";
+  font-family: "FZQKBYSJW--GB1-0";
 }
 ol,
 ul {
@@ -157,21 +157,29 @@ input[type="number"]::-webkit-outer-spin-button {
   width: 350px !important;
 }
 
-.w1100 {
+.w1200 {
   margin: 0 auto;
-  width: 1100px;
+  width: 1200px;
   overflow: hidden;
 }
 
 @font-face {
   font-family: "Source Han Sans CN-Regular";
-  src: url("@/assets/fonts/SourceHanSansCN-Regular.otf");
+  src: url("/public/fonts/SourceHanSansCN-Regular.otf");
 }
 @font-face {
   font-family: "Source Han Serif CN-Bold";
-  src: url("@/assets/fonts/SOURCEHANSERIFCN-BOLD.otf");
+  src: url("/public/fonts/SOURCEHANSERIFCN-BOLD.otf");
 }
 @font-face {
   font-family: "Source Han Serif CN-Regular";
-  src: url("@/assets/fonts/SOURCEHANSERIFCN-REGULAR.otf");
+  src: url("/public/fonts/SOURCEHANSERIFCN-REGULAR.otf");
+}
+@font-face {
+  font-family: "FZQKBYSJW--GB1-0";
+  src: url("/public/fonts/FZQKBYSJW--GB1-0.TTF");
+}
+@font-face {
+  font-family: "FZBWKSJW--GB1-0";
+  src: url("/public/fonts/FZBWKSJW--GB1-0.TTF");
 }

BIN
packages/pc/src/components/BookCard/images/bg-min.png


+ 17 - 31
packages/pc/src/components/BookCard/index.vue

@@ -5,7 +5,7 @@
     :class="{ row: isRow, large: size === 'large' }"
   >
     <div class="book-card-img">
-      <el-image :src="`${baseUrl}${_item.thumb}`" fit="cover" />
+      <el-image :src="`${baseUrl}${_item.thumb}`" fit="contain" />
 
       <img
         v-if="showLike"
@@ -21,8 +21,10 @@
 
     <div class="book-card-inner">
       <p class="book-card__name limit-line">{{ _item.name }}</p>
-      <p v-if="isRow" class="limit-line">{{ _item.author }}</p>
-      <p class="limit-line">{{ _item.press }}</p>
+      <div>
+        <p v-if="isRow" class="limit-line">{{ _item.author }}</p>
+        <p class="limit-line">{{ _item.press }}</p>
+      </div>
     </div>
   </router-link>
 </template>
@@ -90,36 +92,26 @@ const handleLike = async () => {
 
 <style lang="scss" scoped>
 .book-card {
+  position: relative;
   display: flex;
   flex-direction: column;
-  width: 150px;
+  padding: 10px 0 10px 130px;
+  width: 397px;
+  height: 103px;
+  box-sizing: border-box;
+  background: url("./images/bg-min.png") no-repeat center / contain;
   cursor: pointer;
 
   // 横版样式
   &.row {
-    width: 100%;
     flex-direction: row;
-    gap: 18px;
     line-height: 16px;
 
-    &.large {
-      width: 100%;
-      font-size: 18px;
-      line-height: 21px;
-
-      .book-card-img {
-        width: 114px;
-        height: 146px;
-      }
-      .book-card__name {
-        margin-bottom: 20px;
-        font-size: 24px;
-        line-height: 34px;
-      }
-    }
     .book-card-img {
+      position: absolute;
+      left: 19px;
+      bottom: 14px;
       width: 90px;
-      height: 115px;
     }
     .book-card-inner {
       flex: 1;
@@ -131,18 +123,10 @@ const handleLike = async () => {
       line-height: 22px;
     }
   }
-  &.large {
-    width: 192px;
-
-    .book-card-img {
-      height: 259px;
-    }
-  }
   &-img {
     position: relative;
     flex-shrink: 0;
     width: inherit;
-    height: 200px;
 
     .el-image {
       width: 100%;
@@ -171,7 +155,9 @@ const handleLike = async () => {
     }
   }
   &-inner {
-    text-align: center;
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
   }
   &__name {
     margin-top: 8px;

+ 149 - 30
packages/pc/src/components/RankPanel/index.vue

@@ -1,53 +1,172 @@
 <template>
-  <div class="rank-panel">
-    <div class="rank-panel-header">
-      <p class="rank-panel-header__title">
-        <slot name="title-prepend" />排行榜
-      </p>
-      <p class="rank-panel-header__subtitle">{{ subTitle }}</p>
+  <div v-if="list.length" class="rank-panel-main">
+    <div
+      class="rank-panel-topone"
+      @click="
+        $router.push({
+          name: 'detail',
+          params: { id: list[0].id, type: 'reader' },
+        })
+      "
+    >
+      <div class="rank-panel-topone-top">
+        <p class="title limit-line line-2">{{ list[0].name }}</p>
+        <p style="margin: 10px 0 15px">{{ list[0].author }}</p>
+        <p>{{ list[0].press }}</p>
+      </div>
+      <div class="rank-panel-topone-footer"></div>
+      <el-image
+        class="rank-panel-topone__banner"
+        :src="`${baseUrl}${list[0].thumb}`"
+        fit="contain"
+      />
     </div>
 
-    <ul v-if="list.length" class="rank-panel-list">
-      <li v-for="item in list" :key="item.id">
-        <book-card :item="item" />
-      </li>
-    </ul>
+    <el-scrollbar class="rank-panel-scrollbar" style="height: 670px">
+      <ul class="rank-panel-list">
+        <li
+          v-for="(item, index) in list.slice(1, 9)"
+          :key="item.id"
+          class="rank-item"
+          @click="
+            $router.push({
+              name: 'detail',
+              params: { id: item.id, type: 'reader' },
+            })
+          "
+        >
+          <span class="rank-item__num">{{ index + 2 }}</span>
 
-    <el-empty v-else :image-size="50" description="暂无数据" />
+          <p class="title limit-line line-2">{{ item.name }}</p>
+
+          <div class="rank-item-footer">
+            <p>{{ item.author }}</p>
+            <p>{{ item.press }}</p>
+          </div>
+
+          <el-image
+            class="rank-item__banner"
+            :src="`${baseUrl}${item.thumb}`"
+            fit="contain"
+          />
+        </li>
+      </ul>
+    </el-scrollbar>
   </div>
+
+  <el-empty v-else :image-size="50" description="暂无数据" />
 </template>
 
 <script setup>
-import BookCard from "@/components/BookCard/index.vue";
+import { getBaseUrl } from "@/utils";
 
-defineProps(["subTitle", "list"]);
+defineProps(["list"]);
+const baseUrl = getBaseUrl();
 </script>
 
 <style lang="scss" scoped>
 .rank-panel {
-  &-header {
-    padding-bottom: 10px;
-    border-bottom: 1px solid #dddddd;
-
-    &__title {
-      display: flex;
-      align-items: flex-end;
-      font-size: 24px;
-      font-family: "Source Han Serif CN-Bold";
-    }
-    &__subtitle {
-      color: #a99271;
+  &-scrollbar {
+    margin: 0 -9px;
+
+    :deep(.el-scrollbar__wrap) {
+      overflow-x: hidden;
     }
   }
   &-list {
     display: flex;
     flex-wrap: wrap;
-    margin: 0 -15px;
+    justify-content: center;
+  }
+  &-topone {
+    position: relative;
+    margin: 0 auto 50px;
+    padding-top: 45px;
+    width: 1334px;
+    cursor: pointer;
+    font-family: "Source Han Serif CN-Regular";
+
+    &::before {
+      content: "";
+      position: absolute;
+      top: 0;
+      left: 45px;
+      width: 75px;
+      height: 57px;
+      background: url("../../views/Home2/images/icon.png") no-repeat center /
+        contain;
+    }
+    &-top {
+      padding: 0 580px 0 100px;
+      font-size: 20px;
+      height: 240px;
+      color: #434343;
 
-    li {
-      margin: 15px;
-      width: calc(50% - 30px);
+      .title {
+        font-family: "Source Han Serif CN-Bold";
+        font-size: 31px;
+        line-height: 62px;
+      }
+    }
+    &-footer {
+      width: 100%;
+      height: 233px;
+      background: url("../../views/Home2/images/info-bg.png") no-repeat center /
+        contain;
+    }
+    &__banner {
+      position: absolute;
+      right: 92px;
+      bottom: 80px;
+      width: 270px;
+      box-shadow: -5px 5px 10px #666;
+      transform: perspective(300px) rotateY(8deg);
     }
   }
 }
+.rank-item {
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  position: relative;
+  margin: 52px 9px;
+  padding: 14px 170px 10px 70px;
+  width: 495px;
+  height: 121px;
+  cursor: pointer;
+  box-sizing: border-box;
+  font-family: "Source Han Serif CN-Regular";
+  background: url("../../views/Home2/images/item-bg.png") no-repeat center /
+    contain;
+
+  &:nth-child(3n + 2) {
+    background-image: url("../../views/Home2/images/item2-bg.png");
+
+    p {
+      color: white !important;
+    }
+  }
+  .title {
+    font-family: "Source Han Serif CN-Bold";
+    font-size: 19px;
+    line-height: 25px;
+    color: black;
+  }
+  p {
+    color: #434343;
+  }
+  &__num {
+    position: absolute;
+    top: 11px;
+    left: 16px;
+    font-size: 23px;
+    color: white;
+  }
+  &__banner {
+    position: absolute;
+    right: 34px;
+    bottom: 30px;
+    height: 140px;
+  }
+}
 </style>

+ 15 - 19
packages/pc/src/components/TopNav/components/MobileDialog.vue

@@ -1,5 +1,10 @@
 <template>
-  <el-dialog v-model="show" class="mobile-dialog" width="425px">
+  <el-dialog
+    v-model="show"
+    class="mobile-dialog"
+    width="530px"
+    :show-close="false"
+  >
     <vue-qrcode
       class="mobile-dialog__scan"
       type="image/png"
@@ -9,7 +14,6 @@
       }"
       :value="mobileUrl"
     />
-    <span>手机扫描二维码</span>
   </el-dialog>
 </template>
 
@@ -38,25 +42,17 @@ const show = computed({
 
 <style lang="scss">
 .mobile-dialog {
-  height: 517px;
-  background: rgba(255, 255, 255, 0.9);
+  position: relative;
+  height: 678px;
+  background: url("@/assets/images/mb-bg.png") no-repeat center / contain;
 
-  .el-dialog__body {
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    justify-content: center;
-    gap: 32px;
-    height: 100%;
-
-    span {
-      font-size: 24px;
-      font-family: "Source Han Serif CN-Bold";
-    }
-  }
   &__scan {
-    width: 300px;
-    height: 300px;
+    position: absolute;
+    left: calc(50% - 3px);
+    bottom: 140px;
+    width: 310px;
+    height: 310px;
+    transform: translateX(-50%);
   }
 }
 </style>

BIN
packages/pc/src/components/TopNav/images/active-bg-min.jpg


BIN
packages/pc/src/components/TopNav/images/border.png


BIN
packages/pc/src/components/TopNav/images/detail-btn.png


BIN
packages/pc/src/components/TopNav/images/icon_font-min.png


BIN
packages/pc/src/components/TopNav/images/icon_font_active-min.png


BIN
packages/pc/src/components/TopNav/images/icon_img-min.png


BIN
packages/pc/src/components/TopNav/images/icon_img_active-min.png


BIN
packages/pc/src/components/TopNav/images/icon_text-min.png


BIN
packages/pc/src/components/TopNav/images/icon_text_active-min.png


BIN
packages/pc/src/components/TopNav/images/icon_video-min.png


BIN
packages/pc/src/components/TopNav/images/icon_video_active-min.png


BIN
packages/pc/src/components/TopNav/images/wechat-min.png


+ 66 - 29
packages/pc/src/components/TopNav/index.scss

@@ -1,5 +1,8 @@
 .top-nav {
-  height: 80px;
+  height: 100px;
+  font-family: "FZBWKSJW--GB1-0";
+  color: white;
+  font-size: 20px;
 
   &-container {
     position: fixed;
@@ -8,7 +11,6 @@
     right: 0;
     height: inherit;
     background: var(--topnav-bg-color);
-    border-bottom: 1px solid rgba(211, 191, 162, 0.5);
     z-index: 1000;
 
     &.simple {
@@ -23,6 +25,14 @@
       max-width: 1434px;
       height: inherit;
     }
+    &.is-detail {
+      .top-nav-rg-first {
+        gap: 80px;
+      }
+      .top-nav-rg__divider {
+        margin: 0 70px;
+      }
+    }
   }
 
   &-lf {
@@ -32,24 +42,44 @@
   &-rg {
     display: flex;
     align-items: center;
+    height: 100%;
 
     &-first {
       display: flex;
       align-items: center;
-      gap: 57px;
-      font-size: 18px;
+      gap: 125px;
       white-space: nowrap;
-      font-family: "Source Han Serif CN-Bold";
+      height: inherit;
 
       li {
+        position: relative;
+        width: 75px;
+        height: inherit;
+        text-align: center;
+        line-height: 75px;
+        writing-mode: vertical-lr;
         cursor: pointer;
+
+        &.active {
+          &::after {
+            content: "";
+            position: absolute;
+            top: 0;
+            left: 0;
+            right: 0;
+            bottom: -13px;
+            background: url("./images/active-bg-min.jpg") no-repeat center /
+              contain;
+            z-index: -1;
+          }
+        }
       }
     }
     &__divider {
-      margin: 0 57px;
-      width: 1px;
-      height: 20px;
-      background: #d3bfa2;
+      margin: 0 88px 0 198px;
+      width: 4px;
+      height: 89px;
+      background: url("./images/border.png") no-repeat center / contain;
     }
   }
 
@@ -82,9 +112,20 @@
   }
 
   &__login {
-    font-size: 18px;
-    font-family: "Source Han Serif CN-Bold";
+    position: relative;
     cursor: pointer;
+
+    &::before {
+      content: "";
+      position: absolute;
+      top: 50%;
+      left: -35px;
+      width: 43px;
+      height: 43px;
+      transform: translateY(-50%);
+      background: url("./images/wechat-min.png") no-repeat center / contain;
+      z-index: -1;
+    }
   }
 
   &__logo {
@@ -97,41 +138,37 @@
     align-items: center;
     gap: 30px;
 
+    &__inner {
+      p {
+        margin-top: 10px;
+        font-size: 14px;
+      }
+    }
     &__title {
       display: flex;
       align-items: center;
       gap: 20px;
 
       span {
-        display: inline-flex;
-        align-items: center;
-        justify-content: center;
-        width: 70px;
-        height: 25px;
-        font-size: 12px;
-        font-family: "Source Han Sans CN-Regular";
-        color: var(--el-color-primary);
-        border: 1px solid var(--el-color-primary);
-        border-radius: 3px;
-        box-sizing: border-box;
-        white-space: nowrap;
+        width: 109px;
+        height: 43px;
+        font-size: 0;
+        background: url("./images/detail-btn.png") no-repeat center / contain;
         cursor: pointer;
       }
     }
     h1 {
       max-width: 200px;
-      font-size: 24px;
+      font-size: 20px;
       font-family: "Source Han Serif CN-Bold";
     }
-    p {
-      color: var(--text-color-secondary);
-    }
   }
 
   &-detail-nav {
     display: flex;
     align-items: center;
-    gap: 30px;
+    gap: 70px;
+    padding-bottom: 20px;
 
     &__item {
       position: relative;
@@ -153,7 +190,7 @@
       p {
         position: absolute;
         left: 50%;
-        bottom: -20px;
+        bottom: -30px;
         line-height: 20px;
         white-space: nowrap;
         color: var(--color-primary-opacity-5);

+ 20 - 14
packages/pc/src/components/TopNav/index.vue

@@ -2,7 +2,7 @@
   <div class="top-nav">
     <div
       class="top-nav-container"
-      :class="{ simple: hideBgColor }"
+      :class="{ simple: hideBgColor, 'is-detail': isDetail }"
       :style="{ backgroundColor: bgColor }"
     >
       <div>
@@ -38,7 +38,7 @@
         <div class="top-nav-rg">
           <ul class="top-nav-rg-first">
             <li @click="mobileVisible = true">手机版</li>
-            <li v-if="!isDetail">
+            <li v-if="!isDetail" :class="{ active: $route.name === 'stack' }">
               <router-link :to="{ name: 'stack' }">书库</router-link>
             </li>
             <li
@@ -77,7 +77,7 @@
                       : item.icon
                   "
                 />
-                <p>{{ item.text }}</p>
+                <p v-if="$route.params.type === item.key">{{ item.text }}</p>
               </div>
 
               <!-- 简/繁体 -->
@@ -88,9 +88,9 @@
               />
 
               <!-- 书库 -->
-              <router-link :to="{ name: 'stack' }">
+              <!-- <router-link :to="{ name: 'stack' }">
                 <img :src="isDark ? skDarkIcon : skIcon" />
-              </router-link>
+              </router-link> -->
             </div>
 
             <div class="top-nav-rg__divider" />
@@ -133,12 +133,12 @@ import { useRoute, useRouter } from "vue-router";
 import { useDark } from "@vueuse/core";
 import { storeToRefs } from "pinia";
 import { getFixUrl } from "@/utils";
-import { updateBookCollectApi, fakeLoginApi } from "@/api";
+import { updateBookCollectApi } from "@/api";
 import { useBaseStore, useEpubStore, useDetailStore } from "@/stores";
 import LoginDialog from "./components/LoginDialog.vue";
 import MobileDialog from "./components/MobileDialog.vue";
 
-import LogoIcon from "@/assets/images/logo_03-min.png";
+import LogoIcon from "@/assets/images/logo_04-min.png";
 import LogoWhiteIcon from "@/assets/images/logo-min.png";
 import TextIcon from "./images/icon_text-min.png";
 import TextActiveIcon from "./images/icon_text_active-min.png";
@@ -215,13 +215,19 @@ const handleLogin = async () => {
   // baseStore.login(data);
 };
 
-watch(route, (v) => {
-  isDetail.value = v.name === "detail";
-  showLogo.value = v.meta.showLogo ?? false;
-  hideBgColor.value =
-    (v.meta.hideTopNavBgColor || Boolean(v.meta.topNavBgColor)) ?? true;
-  bgColor.value = v.meta.topNavBgColor ?? "";
-});
+watch(
+  route,
+  (v) => {
+    isDetail.value = v.name === "detail";
+    showLogo.value = v.meta.showLogo ?? false;
+    hideBgColor.value =
+      (v.meta.hideTopNavBgColor || Boolean(v.meta.topNavBgColor)) ?? true;
+    bgColor.value = v.meta.topNavBgColor ?? "";
+  },
+  {
+    immediate: true,
+  }
+);
 
 // 目前没有公众号,先默认登录
 // onMounted(() => {

BIN
packages/pc/src/components/TopNav2/images/icon_book-min.png


BIN
packages/pc/src/components/TopNav2/images/icon_book_dark-min.png


BIN
packages/pc/src/components/TopNav2/images/icon_font-min.png


BIN
packages/pc/src/components/TopNav2/images/icon_font_active-min.png


BIN
packages/pc/src/components/TopNav2/images/icon_img-min.png


BIN
packages/pc/src/components/TopNav2/images/icon_img_active-min.png


BIN
packages/pc/src/components/TopNav2/images/icon_text-min.png


BIN
packages/pc/src/components/TopNav2/images/icon_text_active-min.png


BIN
packages/pc/src/components/TopNav2/images/icon_video-min.png


BIN
packages/pc/src/components/TopNav2/images/icon_video_active-min.png


+ 168 - 0
packages/pc/src/components/TopNav2/index.scss

@@ -0,0 +1,168 @@
+.top-nav {
+  height: 80px;
+
+  &-container {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    height: inherit;
+    background: #f8f6f2;
+    border-bottom: 1px solid rgba(211, 191, 162, 0.5);
+    z-index: 1000;
+
+    &.simple {
+      background: none;
+      border: none;
+    }
+    > div {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      margin: 0 auto;
+      max-width: 1434px;
+      height: inherit;
+    }
+  }
+
+  &-lf {
+    padding-right: 10px;
+  }
+
+  &-rg {
+    display: flex;
+    align-items: center;
+
+    &-first {
+      display: flex;
+      align-items: center;
+      gap: 57px;
+      font-size: 18px;
+      white-space: nowrap;
+      font-family: "Source Han Serif CN-Bold";
+
+      li {
+        cursor: pointer;
+      }
+    }
+    &__divider {
+      margin: 0 57px;
+      width: 1px;
+      height: 20px;
+      background: #d3bfa2;
+    }
+  }
+
+  &-user {
+    display: flex;
+    align-items: center;
+    gap: 20px;
+    font-size: 18px;
+    white-space: nowrap;
+    font-family: "Source Han Serif CN-Bold";
+    cursor: pointer;
+
+    &-toolbar {
+      li {
+        height: 50px;
+        line-height: 50px;
+        font-size: 16px;
+        color: white;
+        text-align: center;
+        cursor: pointer;
+
+        &:hover {
+          background: rgba($color: white, $alpha: 0.1);
+        }
+        &:not(:last-child) {
+          border-bottom: 1px solid rgba($color: white, $alpha: 0.5);
+        }
+      }
+    }
+  }
+
+  &__login {
+    font-size: 18px;
+    font-family: "Source Han Serif CN-Bold";
+    cursor: pointer;
+  }
+
+  &__logo {
+    display: block;
+    cursor: pointer;
+  }
+
+  &-detail {
+    display: flex;
+    align-items: center;
+    gap: 30px;
+
+    &__title {
+      display: flex;
+      align-items: center;
+      gap: 20px;
+
+      span {
+        display: inline-flex;
+        align-items: center;
+        justify-content: center;
+        width: 70px;
+        height: 25px;
+        font-size: 12px;
+        font-family: "Source Han Sans CN-Regular";
+        color: var(--el-color-primary);
+        border: 1px solid var(--el-color-primary);
+        border-radius: 3px;
+        box-sizing: border-box;
+        white-space: nowrap;
+        cursor: pointer;
+      }
+    }
+    h1 {
+      max-width: 200px;
+      font-size: 24px;
+      font-family: "Source Han Serif CN-Bold";
+    }
+    p {
+      color: var(--text-color-secondary);
+    }
+  }
+
+  &-detail-nav {
+    display: flex;
+    align-items: center;
+    gap: 30px;
+
+    &__item {
+      position: relative;
+      cursor: pointer;
+
+      &.active {
+        p {
+          color: var(--el-color-primary);
+        }
+      }
+      &:hover {
+        p {
+          color: var(--el-color-primary);
+        }
+      }
+      img {
+        display: block;
+      }
+      p {
+        position: absolute;
+        left: 50%;
+        bottom: -20px;
+        line-height: 20px;
+        white-space: nowrap;
+        color: var(--color-primary-opacity-5);
+        transform: translateX(-50%);
+      }
+    }
+    img {
+      display: block;
+      cursor: pointer;
+    }
+  }
+}

+ 250 - 0
packages/pc/src/components/TopNav2/index.vue

@@ -0,0 +1,250 @@
+<template>
+  <div class="top-nav">
+    <div
+      class="top-nav-container"
+      :class="{ simple: hideBgColor }"
+      :style="{ backgroundColor: bgColor }"
+    >
+      <div>
+        <div class="top-nav-lf">
+          <router-link v-if="showLogo" :to="{ name: 'home' }">
+            <img
+              class="top-nav__logo"
+              draggable="false"
+              src="@/assets/images/logo_02-min.png"
+            />
+          </router-link>
+
+          <div v-if="isDetail" class="top-nav-detail">
+            <router-link :to="{ name: 'home' }">
+              <img
+                :src="isDark ? LogoWhiteIcon : LogoIcon"
+                draggable="false"
+                style="display: block"
+              />
+            </router-link>
+            <div class="top-nav-detail__inner">
+              <div class="top-nav-detail__title">
+                <h1 class="limit-line">
+                  {{ detail?.name }}
+                </h1>
+                <span @click="introductionVisible = true">查看简介</span>
+              </div>
+              <p>{{ detail?.author }} {{ detail?.press }} 编</p>
+            </div>
+          </div>
+        </div>
+
+        <div class="top-nav-rg">
+          <ul class="top-nav-rg-first">
+            <li @click="mobileVisible = true">手机版</li>
+            <li v-if="!isDetail">
+              <router-link :to="{ name: 'stack' }">书库</router-link>
+            </li>
+            <li
+              v-else
+              v-loading="joinLoading"
+              element-loading-custom-class="top-nav__loading"
+              @click="handleLike"
+            >
+              {{ detail?.isCollect === 1 ? "我的书架" : "加入书架" }}
+            </li>
+          </ul>
+
+          <div class="top-nav-rg__divider" />
+
+          <template v-if="isDetail">
+            <div class="top-nav-detail-nav">
+              <div
+                v-for="item in DETAIL_NAV"
+                :key="item.key"
+                class="top-nav-detail-nav__item"
+                :class="{ active: $route.params.type === item.key }"
+                @click="
+                  $router.push({
+                    name: 'detail',
+                    params: {
+                      id: route.params.id,
+                      type: item.key,
+                    },
+                  })
+                "
+              >
+                <img
+                  :src="
+                    $route.params.type === item.key
+                      ? item.activeIcon
+                      : item.icon
+                  "
+                />
+                <p>{{ item.text }}</p>
+              </div>
+
+              <!-- 简/繁体 -->
+              <img
+                v-show="$route.params.type === 'reader'"
+                :src="isSimplified ? jtIcon : ftIcon"
+                @click="epubStore.toggleText"
+              />
+
+              <!-- 书库 -->
+              <router-link :to="{ name: 'stack' }">
+                <img :src="isDark ? skDarkIcon : skIcon" />
+              </router-link>
+            </div>
+
+            <div class="top-nav-rg__divider" />
+          </template>
+
+          <el-popover
+            v-if="isLogin"
+            :width="124"
+            popper-class="top-nav-user-popover"
+            effect="dark"
+            trigger="click"
+            placement="bottom-end"
+          >
+            <template #reference>
+              <div class="top-nav-user">
+                <el-avatar :src="getFixUrl(userInfo.avatarUrl)" :size="30" />
+                <p>{{ userInfo.nickName }}</p>
+              </div>
+            </template>
+
+            <ul class="top-nav-user-toolbar">
+              <li @click="$router.push({ name: 'bookshelf' })">我的书架</li>
+              <li @click="baseStore.logout">退出登录</li>
+            </ul>
+          </el-popover>
+
+          <div v-else class="top-nav__login" @click="handleLogin">微信登录</div>
+        </div>
+      </div>
+    </div>
+  </div>
+
+  <login-dialog v-model:visible="loginVisible" />
+  <mobile-dialog v-model:visible="mobileVisible" />
+</template>
+
+<script setup>
+import { watch, ref } from "vue";
+import { useRoute, useRouter } from "vue-router";
+import { useDark } from "@vueuse/core";
+import { storeToRefs } from "pinia";
+import { getFixUrl } from "@/utils";
+import { updateBookCollectApi } from "@/api";
+import { useBaseStore, useEpubStore, useDetailStore } from "@/stores";
+import LoginDialog from "../TopNav/components/LoginDialog.vue";
+import MobileDialog from "../TopNav/components/MobileDialog.vue";
+
+import LogoIcon from "@/assets/images/logo_03-min.png";
+import LogoWhiteIcon from "@/assets/images/logo-min.png";
+import TextIcon from "./images/icon_text-min.png";
+import TextActiveIcon from "./images/icon_text_active-min.png";
+import VideoIcon from "./images/icon_video-min.png";
+import VideoActiveIcon from "./images/icon_video_active-min.png";
+import ImgIcon from "./images/icon_img-min.png";
+import ImgActiveIcon from "./images/icon_img_active-min.png";
+import jtIcon from "./images/icon_font-min.png";
+import ftIcon from "./images/icon_font_active-min.png";
+import skIcon from "./images/icon_book-min.png";
+import skDarkIcon from "./images/icon_book_dark-min.png";
+
+const DETAIL_NAV = [
+  {
+    key: "reader",
+    icon: TextIcon,
+    activeIcon: TextActiveIcon,
+    text: "文本",
+  },
+  {
+    key: "video",
+    icon: VideoIcon,
+    activeIcon: VideoActiveIcon,
+    text: "视频",
+  },
+  {
+    key: "photocopy",
+    icon: ImgIcon,
+    activeIcon: ImgActiveIcon,
+    text: "影印",
+  },
+];
+
+const route = useRoute();
+const router = useRouter();
+const isDark = useDark();
+
+const detailStore = useDetailStore();
+const { introductionVisible, detail } = storeToRefs(detailStore);
+const baseStore = useBaseStore();
+const { isLogin, loginVisible, userInfo } = storeToRefs(baseStore);
+const epubStore = useEpubStore(window.pinia);
+const { isSimplified } = storeToRefs(epubStore);
+
+const isDetail = ref(false);
+const showLogo = ref(false);
+const hideBgColor = ref(false);
+const bgColor = ref("");
+const joinLoading = ref(false);
+const mobileVisible = ref(false);
+
+// 加入书架
+const handleLike = async () => {
+  if (!baseStore.loginValidator()) return;
+
+  if (detail.value.isCollect !== 1) {
+    try {
+      joinLoading.value = true;
+      await updateBookCollectApi(detail.value.id, {
+        status: 1,
+      });
+      detail.value.isCollect = 1;
+    } finally {
+      joinLoading.value = false;
+    }
+  } else {
+    router.push({ name: "bookshelf" });
+  }
+};
+
+const handleLogin = async () => {
+  loginVisible.value = true;
+  // const data = await fakeLoginApi(1);
+  // baseStore.login(data);
+};
+
+watch(route, (v) => {
+  isDetail.value = v.name === "detail";
+  showLogo.value = v.meta.showLogo ?? false;
+  hideBgColor.value =
+    (v.meta.hideTopNavBgColor || Boolean(v.meta.topNavBgColor)) ?? true;
+  bgColor.value = v.meta.topNavBgColor ?? "";
+});
+
+// 目前没有公众号,先默认登录
+// onMounted(() => {
+//   handleLogin();
+// });
+</script>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>
+
+<style lang="scss">
+.el-popover.top-nav-user-popover {
+  --el-popover-padding: 10px;
+  min-width: 124px;
+}
+
+.top-nav__loading {
+  --el-loading-spinner-size: 20px;
+
+  top: -5px;
+  left: -10px;
+  right: -10px;
+  bottom: -5px;
+}
+</style>

+ 27 - 7
packages/pc/src/components/TreeMenu.vue

@@ -79,6 +79,7 @@ export default defineComponent({
 
 <style lang="scss" scoped>
 .tree-menu {
+  --el-menu-sub-item-height: 33px;
   --el-menu-item-height: 40px;
   --el-menu-item-font-size: 18px;
   --el-menu-active-color: var(--text-color-secondary);
@@ -92,15 +93,34 @@ export default defineComponent({
     width: 0;
     white-space: normal;
   }
+  :deep(.el-menu--inline) {
+    margin-bottom: 10px;
+
+    .el-menu-item {
+      --el-menu-item-font-size: 15px;
+      color: #8c5e11;
+
+      p {
+        border-bottom: 1px solid #c0a67b;
+      }
+    }
+  }
   :deep(.active > .el-sub-menu__title),
   :deep(.el-menu-item.active) {
-    color: var(--el-color-primary);
-    border-left: 3px solid var(--el-color-primary);
-    background: linear-gradient(
-      90deg,
-      rgba(209, 187, 158, 0.2) 0%,
-      rgba(209, 187, 158, 0) 100%
-    );
+    border-top: 1px solid #a9342e;
+    background: RGBA(246, 240, 228, 1);
+
+    // &::after {
+    //   content: "";
+    //   position: absolute;
+    //   top: 50%;
+    //   right: 9px;
+    //   width: 20px;
+    //   height: 16px;
+    //   background: url("../views/Stack/images/icon.png") no-repeat center /
+    //     contain;
+    //   transform: translateY(-50%);
+    // }
   }
 }
 </style>

+ 0 - 1
packages/pc/src/router/index.js

@@ -18,7 +18,6 @@ const router = createRouter({
       component: () => import("@/views/Home2/index.vue"),
       meta: {
         showLogo: true,
-        topNavBgColor: "rgba(248, 246, 242, 0.2)",
       },
     },
     {

+ 49 - 61
packages/pc/src/views/Detail/components/IntroductionDialog.vue

@@ -1,28 +1,36 @@
 <template>
   <el-dialog
     v-model="show"
-    top="10vh"
+    top="12vh"
     class="introduction-dialog"
-    width="1174px"
+    width="1117px"
+    :show-close="false"
   >
-    <div class="introduction-dialog-left">
-      <el-image
-        fit="cover"
-        class="introduction-dialog-left__cover"
-        :src="baseUrl + (detail.thumbPc || detail.thumb)"
-      />
-      <div class="introduction-dialog-left-info">
-        <h3>{{ detail.name }}</h3>
-        <p class="introduction-dialog-left-info__auther">{{ detail.author }}</p>
+    <img
+      class="introduction-dialog__close"
+      src="../images/close-min.png"
+      @click="show = false"
+    />
+
+    <el-image
+      fit="contain"
+      class="introduction-dialog__cover"
+      :src="baseUrl + (detail.thumbPc || detail.thumb)"
+    />
+
+    <div class="introduction-dialog-right">
+      <h3>{{ detail.name }}</h3>
+
+      <div class="introduction-dialog-right-info">
+        <p class="introduction-dialog-right__auther">
+          {{ detail.author }}
+        </p>
         <p>{{ detail.press }} 编</p>
       </div>
-    </div>
-    <div class="introduction-dialog-right">
-      <div class="introduction-dialog-right__title"><span>作品简介</span></div>
+
       <div style="margin: 0 -10px">
         <el-scrollbar
-          style="margin-top: 30px; padding: 0 10px; font-size: 18px"
-          :height="610 - 65"
+          style="padding: 0 10px; font-size: 16px; text-indent: 2em"
         >
           <div v-html="detail.description" />
         </el-scrollbar>
@@ -61,12 +69,20 @@ const show = computed({
 <style lang="scss">
 .introduction-dialog {
   --el-message-close-size: 20px;
+  --el-dialog-border-radius: 0;
 
-  padding: 0;
-  height: 745px;
-  border-radius: 10px;
-  overflow: hidden;
+  padding: 0 100px 0 576px;
+  height: 675px;
+  background: url("../images/bg-min.jpg") no-repeat center / cover;
 
+  &__close {
+    position: absolute;
+    top: -34px;
+    right: -56px;
+    width: 48px;
+    height: 48px;
+    cursor: pointer;
+  }
   .el-dialog__header {
     padding-bottom: 0;
   }
@@ -78,54 +94,26 @@ const show = computed({
     display: flex;
     height: 100%;
   }
-  &-left {
+  &__cover {
+    position: absolute;
+    left: 93px;
+    bottom: 129px;
+    width: 329px;
+  }
+  &-right {
     flex: 1;
     display: flex;
     flex-direction: column;
-    align-items: center;
     justify-content: center;
-    background: var(--pane2-bg-color);
+    color: #3c3a36;
 
-    &__cover {
-      width: 262px;
-      height: 353px;
+    h3 {
+      font-size: 24px;
     }
     &-info {
-      margin-top: 80px;
-      text-align: center;
-
-      h3 {
-        font-size: 24px;
-        font-family: "Source Han Serif CN-Bold";
-      }
-      &__auther {
-        margin-top: 14px;
-      }
-    }
-  }
-  &-right {
-    flex: 1;
-    padding: 90px 70px 45px;
-
-    &__title {
-      display: inline-block;
-      position: relative;
-      font-size: 24px;
-      font-family: "Source Han Serif CN-Bold";
-
-      &::after {
-        content: "";
-        position: absolute;
-        right: 0;
-        bottom: 2px;
-        width: 48px;
-        height: 7px;
-        background: var(--el-color-primary);
-      }
-      span {
-        position: relative;
-        z-index: 1;
-      }
+      margin: 20px 0 50px;
+      line-height: 27px;
+      opacity: 0.8;
     }
   }
 }

+ 61 - 15
packages/pc/src/views/Detail/components/Reader/index.scss

@@ -1,14 +1,38 @@
 .detail-text {
+  position: relative;
   display: flex;
+  align-items: center;
   flex-direction: column;
+  padding: 30px 0;
   width: 100%;
-  height: calc(100vh - var(--topnav-height) - 54px - 52px);
-  overflow: hidden;
+  height: 100%;
+  box-sizing: border-box;
+
+  h3 {
+    position: absolute;
+    top: 56px;
+    left: 47px;
+    font-size: 24px;
+    writing-mode: vertical-lr;
+    letter-spacing: 1px;
+    font-family: "Source Han Serif CN-Bold";
+
+    &::before {
+      content: "";
+      position: absolute;
+      top: -35px;
+      left: 0;
+      width: 15px;
+      height: 15px;
+      background: #b3554e;
+    }
+  }
 
   #reader {
+    position: relative;
     margin: 0 -40px;
     flex: 1;
-    width: 100%;
+    width: 539px;
     height: 0;
 
     :deep(.epub-view) {
@@ -61,22 +85,44 @@
     }
   }
 
+  &-footer {
+    position: relative;
+    margin-top: 20px;
+    width: 243px;
+    height: 43px;
+    background: url("../../images/footer-bg.png") no-repeat center / contain;
+
+    &__fullscreen {
+      position: absolute;
+      top: calc(50% - 2px);
+      right: 30px;
+      width: 18px;
+      height: 18px;
+      cursor: pointer;
+      transform: translateY(-50%);
+
+      &.disabled {
+        cursor: not-allowed;
+      }
+    }
+  }
+
   &-pagination {
+    position: absolute;
+    top: 0;
+    left: 16px;
+    bottom: 0;
     display: flex;
     align-items: center;
-    justify-content: space-between;
-    margin-top: 28px;
+    justify-content: center;
+    gap: 30px;
+    width: 160px;
+    font-size: 17px;
+    color: white;
+    background: url("../../images/pagination.png") no-repeat center / contain;
 
-    &__btn {
-      display: flex;
-      align-items: center;
-      justify-content: center;
-      width: 110px;
-      height: 40px;
-      color: var(--el-color-primary);
-      font-size: 18px;
-      user-select: none;
-      background: url("../../images/btn_03.png") no-repeat center / contain;
+    span:nth-child(1),
+    span:nth-child(3) {
       cursor: pointer;
     }
   }

+ 69 - 35
packages/pc/src/views/Detail/components/Reader/index.vue

@@ -1,5 +1,7 @@
 <template>
   <div class="detail-text" v-loading="bookLoading">
+    <h3>{{ detail?.name }}</h3>
+
     <div id="reader" />
 
     <Teleport v-if="selectMenuStyle.visibility === 'visible'" to="#reader">
@@ -42,39 +44,42 @@
       </div>
     </Teleport>
 
-    <div class="detail-text-pagination">
-      <div
-        class="detail-text-pagination__btn"
-        @click="
-          () => {
-            hideSelectMenu();
-            epubStore.prePage();
-          }
-        "
-      >
-        <el-icon><ArrowLeft /></el-icon>
-        上一页
-      </div>
-
-      <div
-        class="detail-text-pagination__btn"
-        @click="
-          () => {
-            hideSelectMenu();
-            epubStore.nextPage();
-            if (isLogin && detail && typeof detail.isCollect !== 'number') {
-              // 标记为有阅读过
-              updateBookCollectApi(detail.id, {
-                status: 0,
-              });
-              detail.isCollect = 0;
+    <div class="detail-text-footer">
+      <div class="detail-text-pagination">
+        <span
+          @click="
+            () => {
+              hideSelectMenu();
+              epubStore.prePage();
             }
-          }
-        "
-      >
-        下一页
-        <el-icon><ArrowRight /></el-icon>
+          "
+          ><</span
+        >
+        <span>{{ currentPage }}/{{ totalPage }}</span>
+        <span
+          @click="
+            () => {
+              hideSelectMenu();
+              epubStore.nextPage();
+              if (isLogin && detail && typeof detail.isCollect !== 'number') {
+                // 标记为有阅读过
+                updateBookCollectApi(detail.id, {
+                  status: 0,
+                });
+                detail.isCollect = 0;
+              }
+            }
+          "
+          >></span
+        >
       </div>
+
+      <img
+        class="detail-text-footer__fullscreen"
+        :class="{ disabled: !isSupported }"
+        src="../../images/fullscreen.png"
+        @click="toggle"
+      />
     </div>
   </div>
 </template>
@@ -83,8 +88,8 @@
 import { onMounted, onBeforeUnmount, ref, watch } from "vue";
 import { ElMessage, ElNotification } from "element-plus";
 import useClipboard from "vue-clipboard3";
-import { ArrowLeft, ArrowRight } from "@element-plus/icons-vue";
 import { storeToRefs } from "pinia";
+import { useFullscreen } from "@vueuse/core";
 import { getBaseUrl } from "@/utils";
 import { useEpubStore, useDetailStore, useBaseStore } from "@/stores";
 import { COLOR_MAP } from "./constants";
@@ -92,6 +97,7 @@ import { updateBookCollectApi, saveLabelApi, deleteLabelApi } from "@/api";
 
 const props = defineProps(["detail", "isLogin"]);
 
+const { isFullscreen, isSupported, toggle } = useFullscreen();
 const baseStore = useBaseStore();
 const epubStore = useEpubStore(window.pinia);
 const detailStore = useDetailStore();
@@ -101,15 +107,17 @@ const selectMenuStyle = ref({});
 const selectedCfi = ref("");
 const baseUrl = getBaseUrl();
 const bookLoading = ref(true);
+const totalPage = ref(0);
+const currentPage = ref(0);
 
 onMounted(async () => {
   await epubStore.init({
     url: baseUrl + props.detail.filePath,
     renderOptions: {
       flow: "paginated",
-      manager: "continuous",
-      snap: true,
-      method: "inline",
+      // manager: "continuous",
+      // snap: true,
+      // method: "inline",
     },
     error() {
       ElMessage.error("图书加载失败");
@@ -117,7 +125,24 @@ onMounted(async () => {
     },
   });
 
+  epubStore.rendition.on("locationChanged", (location) => {
+    currentPage.value = location.index + 1;
+    totalPage.value = epubStore.book.spine.length;
+  });
+
   epubStore.rendition.hooks.render.register((v) => {
+    const fontStyle = v.document.createElement("style");
+    fontStyle.textContent = `
+      @font-face {
+        font-family: 'FZQKBYSJW--GB1-0';
+        src: url('./fonts/FZQKBYSJW--GB1-0.TTF');
+      }
+      * {
+        line-height: 32px;
+      }
+    `;
+    v.document.head.appendChild(fontStyle);
+
     v.document.body.addEventListener("mouseup", (e) => {
       const selection = v.window.getSelection();
 
@@ -274,6 +299,15 @@ watch(isLogin, (v) => {
     });
   }
 });
+
+watch(isFullscreen, () => {
+  setTimeout(() => {
+    const dom = document.getElementsByClassName("#reader");
+    if (dom.length) {
+      epubStore.rendition.resize(dom[0].clientWidth, dom[0].clientHeight);
+    }
+  }, 50);
+});
 </script>
 
 <style lang="scss" scoped>

BIN
packages/pc/src/views/Detail/components/Toolbar/images/icon_comment_yellow.png


BIN
packages/pc/src/views/Detail/components/Toolbar/images/icon_like_yellow.png


BIN
packages/pc/src/views/Detail/components/Toolbar/images/icon_mark_yellow.png


BIN
packages/pc/src/views/Detail/components/Toolbar/images/icon_menu_yellow.png


BIN
packages/pc/src/views/Detail/components/Toolbar/images/icon_search_yellow.png


BIN
packages/pc/src/views/Detail/components/Toolbar/images/icon_setting_yellow.png


BIN
packages/pc/src/views/Detail/components/Toolbar/images/icon_share_yellow.png


+ 6 - 0
packages/pc/src/views/Detail/components/Toolbar/index.scss

@@ -14,6 +14,7 @@
     display: flex;
     flex-direction: column;
     align-items: center;
+    gap: 3px;
     cursor: pointer;
     z-index: 997;
     transform: translateY(-50%);
@@ -26,7 +27,12 @@
     &:hover span {
       color: var(--el-color-primary);
     }
+    img {
+      width: 48px;
+      height: 48px;
+    }
     span {
+      font-size: 16px;
       line-height: 20px;
     }
   }

+ 32 - 30
packages/pc/src/views/Detail/components/Toolbar/index.vue

@@ -9,12 +9,7 @@
     }"
     @click="handleToolbar(item.key, idx)"
   >
-    <svg-icon
-      :name="item.icon"
-      width="40px"
-      height="40px"
-      color="var(--icon-color)"
-    />
+    <img draggable="false" :src="item.icon" />
     <span>{{ item.label }}</span>
   </div>
 
@@ -37,6 +32,13 @@ import Search from "../Search.vue";
 import NoteDrawer from "../Note.vue";
 import Bookmark from "../Bookmark.vue";
 import Comment from "../Comment.vue";
+import MenuIcon from "./images/icon_menu_yellow.png";
+import SearchIcon from "./images/icon_search_yellow.png";
+import MarkIcon from "./images/icon_mark_yellow.png";
+import LikeIcon from "./images/icon_like_yellow.png";
+import SettingIcon from "./images/icon_setting_yellow.png";
+import CommentIcon from "./images/icon_comment_yellow.png";
+import ShareIcon from "./images/icon_share_yellow.png";
 
 const { isFullscreen, isSupported, toggle } = useFullscreen();
 const epubStore = useEpubStore(window.pinia);
@@ -55,55 +57,55 @@ const list = computed(() => {
     {
       top: 0,
       label: "目录",
-      icon: "icon_menu_yellow",
+      icon: MenuIcon,
       key: "directory",
     },
     {
       top: 0,
       label: "搜索",
-      icon: "icon_search_yellow",
+      icon: SearchIcon,
       key: "search",
     },
     {
       top: 0,
       label: "笔记",
-      icon: "icon_mark_yellow",
+      icon: MarkIcon,
       key: "note",
     },
     {
       top: 0,
       label: "书签",
-      icon: "icon_like_yellow",
+      icon: LikeIcon,
       key: "bookmark",
     },
     {
       top: 0,
       label: "设置",
-      icon: "icon_setting_yellow",
+      icon: SettingIcon,
       key: "setting",
     },
     {
       top: 0,
       label: "评论",
-      icon: "icon_comment_yellow",
+      icon: CommentIcon,
       key: "comment",
     },
     {
       top: 0,
       label: "分享",
-      icon: "icon_share_yellow",
+      icon: ShareIcon,
       key: "share",
     },
   ];
-  if (isSupported.value) {
-    stack.push({
-      top: 0,
-      label: "全屏",
-      icon: "icon_fullscreen_yellow",
-      key: "fullscreen",
-    });
-  }
-  const itemHeight = 60;
+  // if (isSupported.value) {
+  //   stack.push({
+  //     top: 0,
+  //     label: "全屏",
+  //     icon: "icon_fullscreen_yellow",
+  //     key: "fullscreen",
+  //   });
+  // }
+  const itemHeight = 71;
   const listHeight = itemHeight * stack.length;
   let top = (window.innerHeight - listHeight) / 2;
 
@@ -171,14 +173,14 @@ const handleClose = () => {
   active.value = -1;
 };
 
-watch(isFullscreen, () => {
-  setTimeout(() => {
-    const dom = document.getElementsByClassName("detail-text");
-    if (dom.length) {
-      epubStore.rendition.resize(dom[0].clientWidth, dom[0].clientHeight - 68);
-    }
-  }, 50);
-});
+// watch(isFullscreen, () => {
+//   setTimeout(() => {
+//     const dom = document.getElementsByClassName("detail-text");
+//     if (dom.length) {
+//       epubStore.rendition.resize(dom[0].clientWidth, dom[0].clientHeight - 68);
+//     }
+//   }, 50);
+// });
 </script>
 
 <style lang="scss" scoped>

BIN
packages/pc/src/views/Detail/images/bg-min.jpg


BIN
packages/pc/src/views/Detail/images/close-min.png


BIN
packages/pc/src/views/Detail/images/enlarge.png


BIN
packages/pc/src/views/Detail/images/footer-bg.png


BIN
packages/pc/src/views/Detail/images/fullscreen.png


BIN
packages/pc/src/views/Detail/images/main-bg.png


BIN
packages/pc/src/views/Detail/images/narrow.png


BIN
packages/pc/src/views/Detail/images/pagination.png


+ 15 - 0
packages/pc/src/views/Detail/index.scss

@@ -0,0 +1,15 @@
+.detail {
+  min-width: 1311px;
+  background: url("../Stack/images/bg.jpg") no-repeat center / cover;
+
+  :deep(.page-pane-container) {
+    width: 1311px;
+    height: 930px;
+    box-shadow: none;
+    background: url("./images/main-bg.png") no-repeat center / cover !important;
+
+    .el-scrollbar__view {
+      height: 100%;
+    }
+  }
+}

+ 1 - 0
packages/pc/src/views/Detail/index.vue

@@ -1,6 +1,7 @@
 <template>
   <page-pane
     v-loading.fullscreen.lock="loading"
+    class="detail"
     :container-color="paneBgColor"
     :simple="isPhotocopy"
   >

+ 44 - 23
packages/pc/src/views/Home2/components/News.vue

@@ -1,9 +1,13 @@
 <template>
   <div v-loading="loading" class="home2-news">
     <div class="w1100">
-      <p class="home2-news__title">
-        <img draggable="false" src="../images/text_news-min.png" />公告
-      </p>
+      <p class="home2-news__title"><span>新闻</span>公告</p>
+
+      <img
+        class="home2-news-bd"
+        src="../images/news-bd.png"
+        draggable="false"
+      />
 
       <div v-if="list.length" class="home2-news-list">
         <div
@@ -78,42 +82,59 @@ const handleClick = (item) => {
 <style lang="scss" scoped>
 .home2-news {
   position: relative;
-  margin-top: 40px;
-  height: 605px;
-  background: #f5f3ec;
+  padding-top: 50px;
+  height: 472px;
+  background: url("../images/news-bg.jpg") #252525 no-repeat top left / contain;
 
-  &::before {
-    content: "";
-    position: absolute;
-    top: 0;
-    left: 0;
-    width: 880px;
-    height: 605px;
-    background: url("../images/bg2-min.png") no-repeat left center / contain;
+  .w1100 {
+    margin: 0 auto;
+    display: flex;
+    flex-direction: column;
+    width: 100%;
+    max-width: 1783px;
+  }
+  &-bd {
+    margin: 26px 0 33px;
+    width: 100%;
   }
   &__title {
-    display: flex;
-    align-items: flex-end;
-    margin-top: 50px;
-    padding-bottom: 20px;
-    font-size: 24px;
+    position: relative;
+    margin-left: 284px;
+    font-size: 21px;
+    letter-spacing: 1px;
+    color: #c0a67b;
     font-family: "Source Han Serif CN-Bold";
-    border-bottom: 1px solid #dddddd;
+
+    span {
+      font-size: 30px;
+    }
+    &::before {
+      content: "";
+      position: absolute;
+      top: 50%;
+      left: -51px;
+      width: 36px;
+      height: 36px;
+      background: url("../images/news-icon.png") no-repeat center / contain;
+      transform: translateY(-50%);
+    }
   }
   &-list {
     display: flex;
     flex-wrap: wrap;
     justify-content: space-between;
     position: relative;
-    margin-top: 10px;
+    padding: 0 260px;
     z-index: 1;
   }
   &-item {
     display: flex;
     align-items: center;
-    margin: 10px 0;
-    width: calc(50% - 50px);
+    margin: 5px 0;
+    width: calc(50% - 90px);
+    color: white;
     cursor: pointer;
+    font-size: 15px;
 
     .limit-line {
       flex: 1;

BIN
packages/pc/src/views/Home2/images/banner.jpg


BIN
packages/pc/src/views/Home2/images/bg.png


BIN
packages/pc/src/views/Home2/images/bg2-min.png


BIN
packages/pc/src/views/Home2/images/icon.png


BIN
packages/pc/src/views/Home2/images/icon_more-min.png


BIN
packages/pc/src/views/Home2/images/info-bg.png


BIN
packages/pc/src/views/Home2/images/item-bg.png


BIN
packages/pc/src/views/Home2/images/item2-bg.png


BIN
packages/pc/src/views/Home2/images/news-bd.png


BIN
packages/pc/src/views/Home2/images/news-bg.jpg


BIN
packages/pc/src/views/Home2/images/news-icon.png


BIN
packages/pc/src/views/Home2/images/tab-active.jpg


BIN
packages/pc/src/views/Home2/images/tab.jpg


BIN
packages/pc/src/views/Home2/images/text_news-min.png


BIN
packages/pc/src/views/Home2/images/text_readomg-min.png


BIN
packages/pc/src/views/Home2/images/text_recommend-min.png


+ 70 - 5
packages/pc/src/views/Home2/index.scss

@@ -1,4 +1,7 @@
 .home2 {
+  display: flex;
+  flex-direction: column;
+
   &-top {
     margin-top: calc(var(--topnav-height) * -1);
     padding-top: var(--topnav-height);
@@ -6,7 +9,7 @@
     background: url("@/assets/images/bg-min.jpg") no-repeat top center / cover;
     box-sizing: border-box;
 
-    .w1100 {
+    .w1200 {
       display: flex;
       justify-content: space-between;
       padding: 38px 0;
@@ -60,13 +63,75 @@
     }
   }
 
+  &-banner {
+    display: block;
+    width: 100%;
+  }
+
   &-main {
+    position: relative;
+    margin-top: -95px;
+    padding-top: 125px;
+    height: 1565px;
+    background: url("./images/bg.png") no-repeat top center / cover;
+    z-index: 1;
+
+    .w1200 {
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      width: 100%;
+      max-width: 1521px;
+    }
+  }
+
+  &-tabs {
     display: flex;
-    gap: 128px;
-    margin-top: 30px;
+    gap: 54px;
+    margin-bottom: 130px;
+
+    li {
+      position: relative;
+      width: 542px;
+      height: 82px;
+      color: white;
+      cursor: pointer;
+      background: url("./images/tab.jpg") no-repeat center / contain;
 
-    .rank-panel {
-      flex: 1;
+      &.active {
+        background-image: url("./images/tab-active.jpg");
+      }
+      p {
+        position: absolute;
+        top: 50%;
+        left: 50%;
+        font-size: 21px;
+        letter-spacing: 2px;
+        font-family: "FZQKBYSJW--GB1-0";
+        transform: translate(-50%, -50%);
+
+        span {
+          font-size: 30px;
+        }
+      }
+      > span {
+        position: absolute;
+        right: 20px;
+        bottom: 10px;
+        font-size: 15px;
+        font-family: "Source Han Serif CN-Regular";
+
+        &::before {
+          content: "";
+          position: absolute;
+          top: 50%;
+          left: -60px;
+          width: 51px;
+          height: 1px;
+          background: white;
+          transform: translateY(-50%);
+        }
+      }
     }
   }
 }

+ 44 - 25
packages/pc/src/views/Home2/index.vue

@@ -1,7 +1,7 @@
 <template>
   <div class="home2">
-    <div v-if="isLogin" class="home2-top">
-      <div class="w1100">
+    <!-- <div v-if="isLogin" class="home2-top">
+      <div class="w1200">
         <div class="home2-top-lf">
           <div>
             <p>我的书架</p>
@@ -24,7 +24,7 @@
         </div>
 
         <div class="home2-top-main">
-          <!-- isCollect = 2 移出书架 -->
+          // isCollect = 2 移出书架
           <book-card
             v-for="item in bookList
               .filter((i) => i.isCollect !== 2)
@@ -44,28 +44,35 @@
           <template #image><div /></template>
         </el-empty>
       </div>
-    </div>
+    </div> -->
+
+    <img class="home2-banner" draggable="false" src="./images/banner.jpg" />
+
+    <div class="home2-main">
+      <div class="w1200">
+        <ul class="home2-tabs">
+          <li
+            v-for="(item, index) in TABS"
+            :key="item.label"
+            :class="{ active: activeTab === index }"
+            @click="activeTab = index"
+          >
+            <p>
+              <span>{{ item.label }}</span
+              >排行榜
+            </p>
+            <span>{{ item.subTitle }}</span>
+          </li>
+        </ul>
+
+        <rank-panel
+          v-if="activeTab === 0"
+          v-loading="recommendLoading"
+          :list="recommendList"
+        />
 
-    <div class="home2-main w1100">
-      <rank-panel
-        v-loading="recommendLoading"
-        sub-title="用户最喜爱的文献"
-        :list="recommendList"
-      >
-        <template #title-prepend>
-          <img draggable="false" src="./images/text_recommend-min.png" />
-        </template>
-      </rank-panel>
-
-      <rank-panel
-        v-loading="readLoading"
-        sub-title="阅读量最多的文献"
-        :list="readList"
-      >
-        <template #title-prepend>
-          <img draggable="false" src="./images/text_readomg-min.png" />
-        </template>
-      </rank-panel>
+        <rank-panel v-else v-loading="readLoading" :list="readList" />
+      </div>
     </div>
 
     <news />
@@ -82,7 +89,7 @@ import {
   getMyBookListApi,
   getUserCollectedBookCountApi,
 } from "@/api";
-import BookCard from "@/components/BookCard/index.vue";
+// import BookCard from "@/components/BookCard/index.vue";
 import RankPanel from "@/components/RankPanel/index.vue";
 import News from "./components/News.vue";
 
@@ -95,6 +102,18 @@ const readList = ref([]);
 const bookLoading = ref(false);
 const bookList = ref([]);
 const collectedCount = ref("-");
+const activeTab = ref(0);
+
+const TABS = [
+  {
+    label: "推荐",
+    subTitle: "用户最喜爱的文献",
+  },
+  {
+    label: "阅读",
+    subTitle: "阅读量最多的文献",
+  },
+];
 
 onMounted(() => {
   getRecommendList();

+ 67 - 0
packages/pc/src/views/Stack/components/SearchInput/index2.vue

@@ -0,0 +1,67 @@
+<template>
+  <div class="search-input">
+    <span>书籍名称</span>
+
+    <div class="search-input__driver" />
+
+    <input
+      placeholder="请输入关键词..."
+      :value="modelValue"
+      @input="emit('update:modelValue', $event.target.value)"
+    />
+
+    <div class="search-input-btn" @click="emit('search')">搜索</div>
+  </div>
+</template>
+
+<script setup>
+const props = defineProps(["modelValue"]);
+const emit = defineEmits(["update:modelValue", "search"]);
+</script>
+
+<style lang="scss" scoped>
+.search-input {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+  margin-top: 15px;
+  padding: 0 8px 0 13px;
+  width: 458px;
+  height: 55px;
+  font-family: "FZQKBYSJW--GB1-0";
+  overflow: hidden;
+  background: url("../../images/input-bg.png") no-repeat center / cover;
+
+  &__driver {
+    width: 2px;
+    height: 24px;
+    background: #9c917e;
+  }
+  span {
+    font-size: 18px;
+    color: #2a2a2a;
+  }
+  input {
+    flex: 1;
+    border: 0;
+    height: 100%;
+    outline: none;
+    font-size: 16px;
+    font-family: "FZQKBYSJW--GB1-0";
+    background: transparent;
+
+    &::placeholder {
+      color: #958474;
+    }
+  }
+  &-btn {
+    width: 97px;
+    height: 39px;
+    text-align: center;
+    line-height: 39px;
+    color: white;
+    background: #9d1712;
+    cursor: pointer;
+  }
+}
+</style>

+ 30 - 26
packages/pc/src/views/Stack/components/Sidebar/index.scss

@@ -1,8 +1,17 @@
 .stack-sidebar {
   $itemHeight: 40px;
+  --el-menu-bg-color: transparent;
 
+  padding: 45px 55px;
   height: 100%;
+  box-sizing: border-box;
 
+  :deep(.el-tabs__nav) {
+    padding: 0 34px;
+    width: 100%;
+    box-sizing: border-box;
+    justify-content: space-between;
+  }
   :deep(.el-tabs) {
     height: 100%;
   }
@@ -12,27 +21,39 @@
     height: 100%;
   }
   :deep(.el-tabs__item) {
-    --el-font-size-base: 18px;
-    --el-text-color-primary: rgba(70, 70, 70, 0.5);
+    --el-font-size-base: 19px;
+    --el-text-color-primary: #2a2a2a;
 
     align-items: flex-end;
     padding-bottom: 8px;
-    font-family: "Source Han Serif CN-Bold";
+    width: 150px;
+    font-family: "FZQKBYSJW--GB1-0";
     line-height: 1;
     z-index: 2;
 
     &.is-active {
-      color: #464646;
-      font-size: 24px;
+      color: #2a2a2a;
+      font-size: 26px;
     }
   }
   :deep(.el-tabs__nav-wrap)::after {
     display: none;
   }
   :deep(.el-tabs__active-bar) {
-    bottom: 5px;
-    height: 7px;
-    background-color: #d1bb9e;
+    bottom: 0px;
+    height: 8px;
+    background-color: #9d1712;
+  }
+
+  :deep(.el-sub-menu__icon-arrow) {
+    margin-top: -8px;
+    width: 20px;
+    height: 16px;
+    background: url("../../images/icon.png") no-repeat center / contain;
+
+    svg {
+      display: none;
+    }
   }
 
   .search-input {
@@ -41,23 +62,6 @@
 
   &-list {
     padding-right: 20px;
-  }
-  &-item {
-    padding-left: 24px;
-    height: $itemHeight;
-    line-height: $itemHeight;
-    font-size: 18px;
-    font-family: "Source Han Serif CN-Bold";
-    cursor: pointer;
-
-    &.active {
-      color: var(--el-color-primary);
-      border-left: 3px solid var(--el-color-primary);
-      background: linear-gradient(
-        90deg,
-        rgba(209, 187, 158, 0.2) 0%,
-        rgba(209, 187, 158, 0) 100%
-      );
-    }
+    font-family: "FZQKBYSJW--GB1-0";
   }
 }

+ 1 - 1
packages/pc/src/views/Stack/components/Sidebar/index.vue

@@ -39,7 +39,7 @@ import { ref, onMounted } from "vue";
 import { useRouteQuery } from "@vueuse/router";
 import { getStorageTreeApi, getExhibitTypeListApi } from "@/api";
 import TreeMenu from "@/components/TreeMenu.vue";
-import SearchInput from "../SearchInput/index.vue";
+import SearchInput from "../SearchInput/index2.vue";
 
 const emits = defineEmits(["select"]);
 

BIN
packages/pc/src/views/Stack/images/bg.jpg


BIN
packages/pc/src/views/Stack/images/icon.png


BIN
packages/pc/src/views/Stack/images/input-bg.png


BIN
packages/pc/src/views/Stack/images/left-icon.png


BIN
packages/pc/src/views/Stack/images/right-icon.png


BIN
packages/pc/src/views/Stack/images/scroll-bg.png


BIN
packages/pc/src/views/Stack/images/sidebar-bg.png


+ 54 - 9
packages/pc/src/views/Stack/index.scss

@@ -1,21 +1,51 @@
 .stack {
   display: flex;
-  gap: calc(70px - 12.5px);
+  gap: 40px;
   height: 100%;
 
   &-page {
+    min-width: 1532px;
+    background: url("./images/bg.jpg") no-repeat center / cover;
+
     :deep(.el-scrollbar__view) {
       height: 100%;
     }
+    :deep(.page-pane-container) {
+      padding: 6px 0 10px;
+      width: 1532px;
+      height: 948px;
+      box-shadow: none;
+      background: url("./images/scroll-bg.png") no-repeat center / contain;
+      background-position-x: 6px;
+    }
+    &-pagination {
+      --el-color-primary: #9d1712;
+      --el-pagination-button-bg-color: #e2d4c0;
+      margin-top: 10px;
+
+      :deep(.btn-prev) {
+        width: 14px;
+        height: 17px;
+        background-color: unset !important;
+        background: url("./images/left-icon.png") no-repeat center / contain;
+      }
+      :deep(.btn-next) {
+        width: 14px;
+        height: 17px;
+        background-color: unset !important;
+        background: url("./images/right-icon.png") no-repeat center / contain;
+      }
+    }
   }
   &-left {
-    flex: 0 0 360px;
-    padding-right: 20px;
-    border-right: 1px solid rgba(70, 70, 70, 0.2);
+    position: relative;
+    left: -3px;
+    flex: 0 0 571px;
+    background: url("./images/sidebar-bg.png") no-repeat center / contain;
   }
   &-main {
     flex: 1;
-    padding-top: 15px;
+    padding: 50px 0;
     height: 100%;
     display: flex;
     flex-direction: column;
@@ -27,18 +57,33 @@
     --el-text-color-primary: rgba(70, 70, 70, 1);
     --el-text-color-regular: rgba(70, 70, 70, 0.5);
 
-    padding: 0 12.5px;
+    position: relative;
+    font-size: 19px;
+    padding: 0 19px 7px;
     box-sizing: border-box;
+    border-bottom: 1px solid #a78d62;
+    font-family: "FZQKBYSJW--GB1-0";
+
+    &::before {
+      content: "";
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 3px;
+      height: 17px;
+      background: #9d1712;
+    }
   }
 
   &-list {
     display: flex;
     flex-wrap: wrap;
-    margin: -12.5px 0;
+    justify-content: space-between;
+    margin: 52px 0 0;
+    padding-right: 68px;
 
     li {
-      margin: 12.5px;
-      width: calc(50% - 25px);
+      margin: 38px 0;
     }
   }
 }

+ 13 - 10
packages/pc/src/views/Stack/index.vue

@@ -6,19 +6,21 @@
       </div>
 
       <div class="stack-main">
-        <el-breadcrumb
-          class="stack-breadcrumb"
-          :separator-icon="ArrowRight"
-          style="width: 100%"
-        >
-          <el-breadcrumb-item v-for="item in breadcrumb" :key="item.id">{{
-            item.name
-          }}</el-breadcrumb-item>
-        </el-breadcrumb>
+        <div style="padding-right: 68px; width: 100%; box-sizing: border-box">
+          <el-breadcrumb
+            class="stack-breadcrumb"
+            :separator-icon="ArrowRight"
+            style="width: 100%"
+          >
+            <el-breadcrumb-item v-for="item in breadcrumb" :key="item.id">{{
+              item.name
+            }}</el-breadcrumb-item>
+          </el-breadcrumb>
+        </div>
 
         <el-scrollbar
           v-loading="loading"
-          style="flex: 1; width: 100%; height: 0; margin: 18px 0"
+          style="flex: 1; width: 100%; height: 0"
         >
           <ul class="stack-list">
             <li v-for="item in list" :key="item.id">
@@ -30,6 +32,7 @@
         </el-scrollbar>
 
         <el-pagination
+          class="stack-page-pagination"
           hide-on-single-page
           background
           layout="prev, pager, next"