chenlei 10 月之前
當前提交
578a9ab1c1
共有 49 個文件被更改,包括 2532 次插入0 次删除
  1. 22 0
      .gitignore
  2. 4 0
      .vscode/settings.json
  3. 12 0
      package.json
  4. 30 0
      packages/pc/.gitignore
  5. 3 0
      packages/pc/.vscode/extensions.json
  6. 29 0
      packages/pc/README.md
  7. 13 0
      packages/pc/index.html
  8. 8 0
      packages/pc/jsconfig.json
  9. 24 0
      packages/pc/package.json
  10. 二進制
      packages/pc/public/favicon.ico
  11. 24 0
      packages/pc/src/App.vue
  12. 7 0
      packages/pc/src/assets/element.scss
  13. 二進制
      packages/pc/src/assets/fonts/SOURCEHANSERIFCN-BOLD.OTF
  14. 二進制
      packages/pc/src/assets/fonts/SOURCEHANSERIFCN-REGULAR.OTF
  15. 二進制
      packages/pc/src/assets/fonts/SourceHanSansCN-Regular.otf
  16. 二進制
      packages/pc/src/assets/images/bg-min.jpg
  17. 二進制
      packages/pc/src/assets/images/btn_01-min.png
  18. 二進制
      packages/pc/src/assets/images/btn_02-min.png
  19. 二進制
      packages/pc/src/assets/images/icon_click.png
  20. 二進制
      packages/pc/src/assets/images/icon_edit-min.png
  21. 二進制
      packages/pc/src/assets/images/icon_like.png
  22. 二進制
      packages/pc/src/assets/images/icon_portrait-min.png
  23. 二進制
      packages/pc/src/assets/images/icon_search-min.png
  24. 二進制
      packages/pc/src/assets/images/icon_unlike.png
  25. 二進制
      packages/pc/src/assets/images/logo_01-min.png
  26. 二進制
      packages/pc/src/assets/images/logo_02-min.png
  27. 153 0
      packages/pc/src/assets/main.css
  28. 114 0
      packages/pc/src/components/BookCard/index.vue
  29. 51 0
      packages/pc/src/components/RankPanel/index.vue
  30. 83 0
      packages/pc/src/components/TopNav/index.scss
  31. 82 0
      packages/pc/src/components/TopNav/index.vue
  32. 14 0
      packages/pc/src/main.js
  33. 34 0
      packages/pc/src/router/index.js
  34. 8 0
      packages/pc/src/stores/base.js
  35. 1 0
      packages/pc/src/stores/index.js
  36. 106 0
      packages/pc/src/views/Bookshelf/index.scss
  37. 69 0
      packages/pc/src/views/Bookshelf/index.vue
  38. 二進制
      packages/pc/src/views/Home/images/btn_more-min.png
  39. 90 0
      packages/pc/src/views/Home/index.scss
  40. 33 0
      packages/pc/src/views/Home/index.vue
  41. 二進制
      packages/pc/src/views/Home2/images/icon_more-min.png
  42. 二進制
      packages/pc/src/views/Home2/images/text_readomg-min.png
  43. 二進制
      packages/pc/src/views/Home2/images/text_recommend-min.png
  44. 66 0
      packages/pc/src/views/Home2/index.scss
  45. 49 0
      packages/pc/src/views/Home2/index.vue
  46. 3 0
      packages/pc/src/views/Stack/index.vue
  47. 42 0
      packages/pc/vite.config.js
  48. 1355 0
      pnpm-lock.yaml
  49. 3 0
      pnpm-workspace.yaml

+ 22 - 0
.gitignore

@@ -0,0 +1,22 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+node_modules
+npm-debug.log*
+yarn-error.log
+yarn.lock
+package-lock.json
+
+# production
+/es
+docs-dist
+
+# misc
+.DS_Store
+
+# ide
+/.idea
+
+dist
+dist-node
+build

+ 4 - 0
.vscode/settings.json

@@ -0,0 +1,4 @@
+{
+  "editor.defaultFormatter": "esbenp.prettier-vscode",
+  "editor.formatOnSave": true
+}

+ 12 - 0
package.json

@@ -0,0 +1,12 @@
+{
+  "name": "lsq-book",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "keywords": [],
+  "author": "",
+  "license": "ISC"
+}

+ 30 - 0
packages/pc/.gitignore

@@ -0,0 +1,30 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+.DS_Store
+dist
+dist-ssr
+coverage
+*.local
+
+/cypress/videos/
+/cypress/screenshots/
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+*.tsbuildinfo

+ 3 - 0
packages/pc/.vscode/extensions.json

@@ -0,0 +1,3 @@
+{
+  "recommendations": ["Vue.volar"]
+}

+ 29 - 0
packages/pc/README.md

@@ -0,0 +1,29 @@
+# pc
+
+This template should help get you started developing with Vue 3 in Vite.
+
+## Recommended IDE Setup
+
+[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
+
+## Customize configuration
+
+See [Vite Configuration Reference](https://vitejs.dev/config/).
+
+## Project Setup
+
+```sh
+npm install
+```
+
+### Compile and Hot-Reload for Development
+
+```sh
+npm run dev
+```
+
+### Compile and Minify for Production
+
+```sh
+npm run build
+```

+ 13 - 0
packages/pc/index.html

@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8">
+    <link rel="icon" href="/favicon.ico">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Vite App</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.js"></script>
+  </body>
+</html>

+ 8 - 0
packages/pc/jsconfig.json

@@ -0,0 +1,8 @@
+{
+  "compilerOptions": {
+    "paths": {
+      "@/*": ["./src/*"]
+    }
+  },
+  "exclude": ["node_modules", "dist"]
+}

+ 24 - 0
packages/pc/package.json

@@ -0,0 +1,24 @@
+{
+  "name": "pc",
+  "version": "0.0.0",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "element-plus": "^2.8.3",
+    "pinia": "^2.1.7",
+    "vue": "^3.4.29",
+    "vue-router": "^4.3.3"
+  },
+  "devDependencies": {
+    "@vitejs/plugin-vue": "^5.0.5",
+    "sass": "1.53.0",
+    "unplugin-auto-import": "^0.18.3",
+    "unplugin-vue-components": "^0.27.4",
+    "vite": "^5.3.1"
+  }
+}

二進制
packages/pc/public/favicon.ico


+ 24 - 0
packages/pc/src/App.vue

@@ -0,0 +1,24 @@
+<script setup>
+import { RouterView } from "vue-router";
+import TopNav from "@/components/TopNav/index.vue";
+</script>
+
+<template>
+  <TopNav />
+
+  <RouterView />
+</template>
+
+<style lang="scss">
+#app {
+  --topnav-height: 80px;
+
+  min-width: 1100px;
+}
+
+.w1100 {
+  margin: 0 auto;
+  width: 1100px;
+  overflow: hidden;
+}
+</style>

+ 7 - 0
packages/pc/src/assets/element.scss

@@ -0,0 +1,7 @@
+@forward "element-plus/theme-chalk/src/common/var.scss" with (
+  $colors: (
+    "primary": (
+      "base": #b49d7e,
+    ),
+  )
+);

二進制
packages/pc/src/assets/fonts/SOURCEHANSERIFCN-BOLD.OTF


二進制
packages/pc/src/assets/fonts/SOURCEHANSERIFCN-REGULAR.OTF


二進制
packages/pc/src/assets/fonts/SourceHanSansCN-Regular.otf


二進制
packages/pc/src/assets/images/bg-min.jpg


二進制
packages/pc/src/assets/images/btn_01-min.png


二進制
packages/pc/src/assets/images/btn_02-min.png


二進制
packages/pc/src/assets/images/icon_click.png


二進制
packages/pc/src/assets/images/icon_edit-min.png


二進制
packages/pc/src/assets/images/icon_like.png


二進制
packages/pc/src/assets/images/icon_portrait-min.png


二進制
packages/pc/src/assets/images/icon_search-min.png


二進制
packages/pc/src/assets/images/icon_unlike.png


二進制
packages/pc/src/assets/images/logo_01-min.png


二進制
packages/pc/src/assets/images/logo_02-min.png


+ 153 - 0
packages/pc/src/assets/main.css

@@ -0,0 +1,153 @@
+html,
+body,
+div,
+span,
+applet,
+object,
+iframe,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+blockquote,
+pre,
+a,
+abbr,
+acronym,
+address,
+big,
+cite,
+code,
+del,
+dfn,
+em,
+img,
+ins,
+kbd,
+q,
+s,
+samp,
+small,
+strike,
+strong,
+sub,
+sup,
+tt,
+var,
+b,
+u,
+i,
+center,
+dl,
+dt,
+dd,
+ol,
+ul,
+li,
+fieldset,
+form,
+label,
+legend,
+table,
+caption,
+tbody,
+tfoot,
+thead,
+tr,
+th,
+td,
+article,
+aside,
+canvas,
+details,
+embed,
+figure,
+figcaption,
+footer,
+header,
+hgroup,
+menu,
+nav,
+output,
+ruby,
+section,
+summary,
+time,
+mark,
+audio,
+video {
+  margin: 0;
+  padding: 0;
+  border: 0;
+  font-size: 100%;
+  font: inherit;
+  vertical-align: baseline;
+}
+/* HTML5 display-role reset for older browsers */
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section {
+  display: block;
+}
+body {
+  font-size: 14px;
+  color: #464646;
+  font-family: "Source Han Sans CN-Regular";
+}
+ol,
+ul {
+  list-style: none;
+}
+blockquote,
+q {
+  quotes: none;
+}
+blockquote:before,
+blockquote:after,
+q:before,
+q:after {
+  content: "";
+  content: none;
+}
+table {
+  border-collapse: collapse;
+  border-spacing: 0;
+}
+
+.limit-line {
+  display: -webkit-box;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  -webkit-line-clamp: 1;
+  -webkit-box-orient: vertical;
+  word-break: break-all;
+  word-wrap: break-word;
+}
+
+.line-2 {
+  -webkit-line-clamp: 2;
+}
+
+@font-face {
+  font-family: "Source Han Sans CN-Regular";
+  src: url("@/assets/fonts/SourceHanSansCN-Regular.otf");
+}
+@font-face {
+  font-family: "Source Han Serif CN-Bold";
+  src: url("@/assets/fonts/SOURCEHANSERIFCN-BOLD.otf");
+}
+@font-face {
+  font-family: "Source Han Serif CN-Regular";
+  src: url("@/assets/fonts/SOURCEHANSERIFCN-REGULAR.otf");
+}

+ 114 - 0
packages/pc/src/components/BookCard/index.vue

@@ -0,0 +1,114 @@
+<template>
+  <div class="book-card" :class="{ row: isRow, large: size === 'large' }">
+    <div class="book-card-img">
+      <el-image src="" fit="cover" />
+
+      <img
+        v-if="showLike"
+        class="book-card-img__like"
+        src="@/assets/images/icon_like.png"
+        draggable="false"
+      />
+    </div>
+
+    <div class="book-card-inner">
+      <p class="book-card__name limit-line">刘少奇传</p>
+      <p v-if="isRow" class="limit-line">刘少奇</p>
+      <p class="limit-line">中共中央文献研究室 编</p>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { computed } from "vue";
+
+const props = defineProps({
+  // 模式 row-横版 column-竖版
+  type: {
+    type: String,
+    required: false,
+    default: "row",
+  },
+  // 尺寸 normal large
+  size: {
+    type: String,
+    required: false,
+    defualt: "normal",
+  },
+  showLike: {
+    type: Boolean,
+    required: false,
+    default: false,
+  },
+});
+
+const isRow = computed(() => props.type === "row");
+</script>
+
+<style lang="scss" scoped>
+.book-card {
+  display: flex;
+  flex-direction: column;
+  width: 150px;
+  cursor: pointer;
+
+  // 横版样式
+  &.row {
+    width: 100%;
+    flex-direction: row;
+    gap: 18px;
+    line-height: 16px;
+
+    .book-card-img {
+      width: 90px;
+      height: 115px;
+    }
+    .book-card-inner {
+      flex: 1;
+      text-align: left;
+    }
+    .book-card__name {
+      margin-top: unset;
+      margin-bottom: 5px;
+      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%;
+      height: 100%;
+    }
+    &__like {
+      position: absolute;
+      top: 4px;
+      right: 4px;
+      width: 30px;
+      height: 30px;
+    }
+  }
+  &-inner {
+    text-align: center;
+  }
+  &__name {
+    margin-top: 8px;
+    font-size: 18px;
+    font-family: "Source Han Serif CN-Bold";
+    opacity: 1 !important;
+  }
+  p {
+    opacity: 0.8;
+  }
+}
+</style>

+ 51 - 0
packages/pc/src/components/RankPanel/index.vue

@@ -0,0 +1,51 @@
+<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>
+
+    <ul class="rank-panel-list">
+      <li v-for="key in 8" :key="key">
+        <book-card />
+      </li>
+    </ul>
+  </div>
+</template>
+
+<script setup>
+import BookCard from "@/components/BookCard/index.vue";
+
+defineProps(["subTitle"]);
+</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;
+    }
+  }
+  &-list {
+    display: flex;
+    flex-wrap: wrap;
+    margin: 0 -15px;
+
+    li {
+      margin: 15px;
+      width: calc(50% - 30px);
+    }
+  }
+}
+</style>

+ 83 - 0
packages/pc/src/components/TopNav/index.scss

@@ -0,0 +1,83 @@
+.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;
+    }
+  }
+
+  &-rg {
+    display: flex;
+    align-items: center;
+
+    &-first {
+      display: flex;
+      align-items: center;
+      gap: 57px;
+      font-size: 18px;
+      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;
+    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;
+  }
+}

+ 82 - 0
packages/pc/src/components/TopNav/index.vue

@@ -0,0 +1,82 @@
+<template>
+  <div class="top-nav">
+    <div
+      class="top-nav-container"
+      :class="{ simple: hideBgColor }"
+      :style="{ backgroundColor: bgColor }"
+    >
+      <div>
+        <div class="top-nav-lf">
+          <img
+            v-if="showLogo"
+            class="top-nav__logo"
+            draggable="false"
+            src="@/assets/images/logo_02-min.png"
+          />
+        </div>
+
+        <div class="top-nav-rg">
+          <ul class="top-nav-rg-first">
+            <li>手机版</li>
+            <li>书库</li>
+          </ul>
+
+          <div class="top-nav-rg__divider" />
+
+          <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="" :size="30" />
+                <p>用户名</p>
+              </div>
+            </template>
+
+            <ul class="top-nav-user-toolbar">
+              <li>我的书架</li>
+              <li>退出登录</li>
+            </ul>
+          </el-popover>
+
+          <div class="top-nav__login">微信登录</div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { watch, ref } from "vue";
+import { useRoute } from "vue-router";
+import { useBaseStore } from "@/stores";
+
+const route = useRoute();
+const { isLogin } = useBaseStore();
+const showLogo = ref(false);
+const hideBgColor = ref(false);
+const bgColor = ref("");
+
+watch(route, (v) => {
+  showLogo.value = v.meta.showLogo ?? false;
+  hideBgColor.value =
+    (v.meta.hideTopNavBgColor || Boolean(v.meta.topNavBgColor)) ?? true;
+  bgColor.value = v.meta.topNavBgColor ?? "";
+});
+</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;
+}
+</style>

+ 14 - 0
packages/pc/src/main.js

@@ -0,0 +1,14 @@
+import "./assets/main.css";
+
+import { createApp } from "vue";
+import { createPinia } from "pinia";
+
+import App from "./App.vue";
+import router from "./router";
+
+const app = createApp(App);
+
+app.use(createPinia());
+app.use(router);
+
+app.mount("#app");

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

@@ -0,0 +1,34 @@
+import { createRouter, createWebHashHistory } from "vue-router";
+
+const router = createRouter({
+  history: createWebHashHistory(import.meta.env.BASE_URL),
+  routes: [
+    {
+      path: "/",
+      name: "home",
+      component: () => import("@/views/Home/index.vue"),
+      meta: {
+        hideTopNavBgColor: true,
+      },
+    },
+    {
+      path: "/home",
+      name: "home2",
+      component: () => import("@/views/Home2/index.vue"),
+      meta: {
+        showLogo: true,
+        topNavBgColor: "rgba(248, 246, 242, 0.2)",
+      },
+    },
+    {
+      path: "/bookshelf",
+      name: "bookshelf",
+      component: () => import("@/views/Bookshelf/index.vue"),
+      meta: {
+        showLogo: true,
+      },
+    },
+  ],
+});
+
+export default router;

+ 8 - 0
packages/pc/src/stores/base.js

@@ -0,0 +1,8 @@
+import { ref } from "vue";
+import { defineStore } from "pinia";
+
+export const useBaseStore = defineStore("base", () => {
+  const isLogin = ref(false);
+
+  return { isLogin };
+});

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

@@ -0,0 +1 @@
+export * from "./base";

+ 106 - 0
packages/pc/src/views/Bookshelf/index.scss

@@ -0,0 +1,106 @@
+.bookshelf {
+  padding-bottom: 50px;
+  min-width: 1343px;
+  min-height: calc(100vh - var(--topnav-height));
+  background: #f3f3f3;
+  box-sizing: border-box;
+
+  &-container {
+    margin: 0 auto;
+    width: 1343px;
+  }
+  &-header {
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    padding: 0 50px;
+    height: 207px;
+
+    &__logout {
+      width: 132px;
+      height: 55px;
+      border: 0;
+      border-radius: 0;
+      font-size: 20px;
+      font-family: "Source Han Serif CN-Bold";
+      background: url("@/assets/images/btn_02-min.png") no-repeat center / cover;
+    }
+  }
+
+  &-info {
+    display: flex;
+    align-items: center;
+    gap: 30px;
+
+    &-inner {
+      font-family: "Source Han Serif CN-Bold";
+    }
+    &__name {
+      font-size: 24px;
+      line-height: 28px;
+
+      img {
+        margin-left: 21px;
+        width: 19px;
+        height: 19px;
+        cursor: pointer;
+      }
+    }
+    &__id {
+      font-size: 18px;
+    }
+  }
+
+  &-avatar {
+    position: relative;
+    border-radius: 50%;
+    overflow: hidden;
+
+    &__mask {
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      background: rgba(44, 44, 44, 0.7);
+    }
+  }
+
+  &-inner {
+    padding: 43px 67px;
+    border-radius: 8px;
+    background: #ffffff;
+    box-shadow: 0px -1px 67px 0px rgba(171, 171, 171, 0.15);
+
+    &__label {
+      display: inline-block;
+      position: relative;
+      font-size: 32px;
+      font-family: "Source Han Serif CN-Bold";
+
+      span {
+        position: relative;
+        z-index: 1;
+      }
+      &::after {
+        content: "";
+        position: absolute;
+        right: -2px;
+        bottom: 4px;
+        width: 64px;
+        height: 7px;
+        background: #d1bb9e;
+      }
+    }
+
+    ul {
+      display: grid;
+      gap: 50px calc((100% - 192px * 5) / 4);
+      grid-template-columns: repeat(5, 192px);
+      margin-top: 47px;
+    }
+  }
+}

+ 69 - 0
packages/pc/src/views/Bookshelf/index.vue

@@ -0,0 +1,69 @@
+<template>
+  <div class="bookshelf">
+    <div class="bookshelf-container">
+      <div class="bookshelf-header">
+        <div class="bookshelf-info">
+          <el-upload
+            class="bookshelf-avatar"
+            action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
+            :show-file-list="false"
+            :before-upload="beforeAvatarUpload"
+          >
+            <el-avatar v-if="imageUrl" :size="100" :src="imageUrl" />
+
+            <!-- <div class="bookshelf-avatar__mask">
+              <img src="@/assets/images/icon_portrait-min.png" />
+            </div> -->
+          </el-upload>
+
+          <div class="bookshelf-info-inner">
+            <div class="bookshelf-info__name">
+              <span>SAMSARA</span>
+              <img draggable="false" src="@/assets/images/icon_edit-min.png" />
+            </div>
+            <p class="bookshelf-info__id">ID:6855576858</p>
+          </div>
+        </div>
+
+        <el-button type="primary" class="bookshelf-header__logout"
+          >退出登录</el-button
+        >
+      </div>
+
+      <div class="bookshelf-inner">
+        <p class="bookshelf-inner__label"><span>我的书架</span></p>
+
+        <ul>
+          <li v-for="key in 10" :key="key">
+            <book-card type="column" size="large" show-like />
+          </li>
+        </ul>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref } from "vue";
+import { ElMessage } from "element-plus";
+import BookCard from "@/components/BookCard/index.vue";
+
+const imageUrl = ref(
+  "https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100"
+);
+
+const beforeAvatarUpload = (rawFile) => {
+  if (rawFile.type !== "image/jpeg") {
+    ElMessage.error("Avatar picture must be JPG format!");
+    return false;
+  } else if (rawFile.size / 1024 / 1024 > 2) {
+    ElMessage.error("Avatar picture size can not exceed 2MB!");
+    return false;
+  }
+  return true;
+};
+</script>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>

二進制
packages/pc/src/views/Home/images/btn_more-min.png


+ 90 - 0
packages/pc/src/views/Home/index.scss

@@ -0,0 +1,90 @@
+.home {
+  margin-top: calc(var(--topnav-height) * -1);
+  height: 100vh;
+  overflow: hidden;
+  background: url("@/assets/images/bg-min.jpg") no-repeat top center / cover;
+
+  &-main {
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    margin: calc(45px + var(--topnav-height)) auto 0;
+    width: 800px;
+    z-index: 999;
+  }
+  &-search {
+    display: flex;
+    align-items: center;
+    gap: 10px;
+    margin: 50px 0 18px;
+    padding: 5px 5px 5px 24px;
+    width: 100%;
+    height: 60px;
+    box-sizing: border-box;
+    border-radius: 5px;
+    border: 1px solid var(--el-color-primary);
+    backdrop-filter: blur(2px);
+    background: rgba($color: white, $alpha: 0.5);
+
+    &__input {
+      flex: 1;
+      height: 100%;
+      border: 0;
+      font-size: 18px;
+      background: transparent;
+      outline: none;
+    }
+    &__btn {
+      flex-shrink: 0;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      gap: 12px;
+      width: 130px;
+      height: 100%;
+      border: 0;
+      font-size: 18px;
+      color: white;
+      cursor: pointer;
+      border-radius: 2px;
+      background: #d3bfa2;
+
+      &::before {
+        content: "";
+        display: block;
+        width: 30px;
+        height: 30px;
+        background: url("@/assets/images/icon_search-min.png") no-repeat center /
+          contain;
+      }
+    }
+  }
+  &-view {
+    padding: 0 54px 0 18px;
+    width: 300px;
+    height: 35px;
+    line-height: 35px;
+    font-size: 18px;
+    color: var(--el-color-primary);
+    background: url("./images/btn_more-min.png") no-repeat center / contain;
+    box-sizing: border-box;
+    cursor: pointer;
+  }
+  &-more {
+    position: absolute;
+    left: 50%;
+    bottom: 36px;
+    display: flex;
+    flex-direction: column;
+    gap: 5px;
+    align-items: center;
+    font-size: 16px;
+    color: var(--el-color-primary);
+    transform: translateX(-50%);
+    cursor: pointer;
+
+    img {
+      width: 30px;
+    }
+  }
+}

+ 33 - 0
packages/pc/src/views/Home/index.vue

@@ -0,0 +1,33 @@
+<template>
+  <div class="home">
+    <div class="home-main">
+      <img
+        class="home-main__logo"
+        draggable="false"
+        src="@/assets/images/logo_01-min.png"
+      />
+
+      <div class="home-search">
+        <input
+          class="home-search__input"
+          type="text"
+          placeholder="请输入关键词..."
+        />
+        <button class="home-search__btn">搜索</button>
+      </div>
+
+      <div class="home-view">
+        <p class="limit-line">共收录132件藏品,查看书库</p>
+      </div>
+    </div>
+
+    <div class="home-more" @click="$router.push({ name: 'home2' })">
+      <img draggable="false" src="@/assets/images/icon_click.png" />
+      <p>查看更多</p>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>

二進制
packages/pc/src/views/Home2/images/icon_more-min.png


二進制
packages/pc/src/views/Home2/images/text_readomg-min.png


二進制
packages/pc/src/views/Home2/images/text_recommend-min.png


+ 66 - 0
packages/pc/src/views/Home2/index.scss

@@ -0,0 +1,66 @@
+.home2 {
+  &-top {
+    margin-top: calc(var(--topnav-height) * -1);
+    padding-top: var(--topnav-height);
+    height: 408px;
+    background: url("@/assets/images/bg-min.jpg") no-repeat top center / cover;
+    box-sizing: border-box;
+
+    .w1100 {
+      display: flex;
+      gap: 220px;
+      padding: 38px 0;
+      height: 100%;
+      box-sizing: border-box;
+    }
+    &-lf {
+      display: flex;
+      flex-direction: column;
+      justify-content: space-between;
+
+      > div {
+        font-family: "Source Han Serif CN-Bold";
+
+        p:first-child {
+          font-size: 32px;
+        }
+        p:last-child {
+          position: relative;
+          margin-top: 12px;
+          font-size: 18px;
+
+          span {
+            font-size: 64px;
+            line-height: 54px;
+          }
+          img {
+            position: absolute;
+            top: 0;
+            right: 0;
+            cursor: pointer;
+          }
+        }
+      }
+    }
+
+    &__pick {
+      width: 131px;
+      height: 42px;
+      font-family: "Source Han Serif CN-Bold";
+      font-size: 20px;
+      border-radius: 0;
+      background: url("@/assets/images/btn_01-min.png") no-repeat center / cover;
+      border: none;
+    }
+  }
+
+  &-main {
+    display: flex;
+    gap: 128px;
+    margin-top: 30px;
+
+    .rank-panel {
+      flex: 1;
+    }
+  }
+}

+ 49 - 0
packages/pc/src/views/Home2/index.vue

@@ -0,0 +1,49 @@
+<template>
+  <div class="home2">
+    <div class="home2-top">
+      <div class="w1100">
+        <div class="home2-top-lf">
+          <div>
+            <p>我的书架</p>
+            <p>
+              <span>5</span>本<img
+                draggable="false"
+                src="./images/icon_more-min.png"
+                @click="$router.push({ name: 'bookshelf' })"
+              />
+            </p>
+          </div>
+
+          <el-button class="home2-top__pick" type="primary">去挑书 +</el-button>
+        </div>
+
+        <div class="home2-top-main">
+          <book-card type="column" />
+        </div>
+      </div>
+    </div>
+
+    <div class="home2-main w1100">
+      <rank-panel sub-title="用户最喜爱的文献">
+        <template #title-prepend>
+          <img draggable="false" src="./images/text_recommend-min.png" />
+        </template>
+      </rank-panel>
+
+      <rank-panel sub-title="阅读量最多的文献">
+        <template #title-prepend>
+          <img draggable="false" src="./images/text_readomg-min.png" />
+        </template>
+      </rank-panel>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import BookCard from "@/components/BookCard/index.vue";
+import RankPanel from "@/components/RankPanel/index.vue";
+</script>
+
+<style lang="scss" scoped>
+@import "./index.scss";
+</style>

+ 3 - 0
packages/pc/src/views/Stack/index.vue

@@ -0,0 +1,3 @@
+<template>
+  <div class="stack"></div>
+</template>

+ 42 - 0
packages/pc/vite.config.js

@@ -0,0 +1,42 @@
+import { fileURLToPath, URL } from "node:url";
+
+import { defineConfig } from "vite";
+import vue from "@vitejs/plugin-vue";
+
+import AutoImport from "unplugin-auto-import/vite";
+import Components from "unplugin-vue-components/vite";
+import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  base: "./",
+  server: {
+    proxy: {
+      "/api": {
+        target: "https://sit-shoubov2.4dage.com",
+        changeOrigin: true,
+      },
+    },
+  },
+  css: {
+    preprocessorOptions: {
+      scss: {
+        additionalData: `@use "@/assets/element.scss" as *;`,
+      },
+    },
+  },
+  plugins: [
+    vue(),
+    AutoImport({
+      resolvers: [ElementPlusResolver()],
+    }),
+    Components({
+      resolvers: [ElementPlusResolver({ importStyle: "sass" })],
+    }),
+  ],
+  resolve: {
+    alias: {
+      "@": fileURLToPath(new URL("./src", import.meta.url)),
+    },
+  },
+});

文件差異過大導致無法顯示
+ 1355 - 0
pnpm-lock.yaml


+ 3 - 0
pnpm-workspace.yaml

@@ -0,0 +1,3 @@
+packages:
+  - "packages/*"
+  - "packages/backend-cli/template"