panhui 4 жил өмнө
parent
commit
2104ba983f

+ 1 - 0
src/main/java/com/izouma/nineth/security/WebSecurityConfig.java

@@ -84,6 +84,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                 .antMatchers("/collection/all").permitAll()
                 .antMatchers("/collection/get/**").permitAll()
                 .antMatchers("/user/all").permitAll()
+                .antMatchers("/user/get/**").permitAll()
                 // all other requests need to be authenticated
                 .anyRequest().authenticated().and()
                 // make sure we use stateless session; session won't be used to

+ 1 - 1
src/main/java/com/izouma/nineth/web/UserController.java

@@ -87,7 +87,7 @@ public class UserController extends BaseController {
         return userService.toDTO(userService.all(pageQuery));
     }
 
-    @PreAuthorize("hasRole('ADMIN')")
+//    @PreAuthorize("hasRole('ADMIN')")
     @GetMapping("/get/{id}")
     public User get(@PathVariable Long id) {
         return userRepo.findById(id).orElseThrow(new BusinessException("无记录"));

+ 50 - 3
src/main/nine-space/src/components/creator/CreatorInfo.vue

@@ -1,5 +1,13 @@
 <template>
-  <div class="info">
+  <router-link
+    :to="{
+      path: '/creatorDetail',
+      query: {
+        id: info.id,
+      },
+    }"
+    class="info"
+  >
     <van-image
       width="88"
       height="88"
@@ -26,10 +34,19 @@
           <span>粉丝</span>
           <span>{{ info.followers }}</span>
         </div>
-        <van-button plain type="primary" size="mini" round>关注</van-button>
+        <van-button
+          @click="follow"
+          :class="{ follow: info.follow }"
+          plain
+          type="primary"
+          size="mini"
+          round
+        >
+          {{ info.follow ? "已关注" : "关注" }}
+        </van-button>
       </div>
     </div>
-  </div>
+  </router-link>
 </template>
 
 <script>
@@ -59,6 +76,29 @@ export default {
       return {};
     },
   },
+  methods: {
+    follow() {
+      if (!this.info.follow) {
+        this.$http.get(`/user/${this.info.id}/follow`).then((res) => {
+          this.$emit("update:info", {
+            ...this.info,
+            follow: true,
+            followers: this.info.followers + 1,
+          });
+          this.$toast.success("关注成功");
+        });
+      } else {
+        this.$http.get(`/user/${this.info.id}/unfollow`).then(() => {
+          this.$emit("update:info", {
+            ...this.info,
+            follow: false,
+            followers: this.info.followers - 1,
+          });
+          this.$toast.success("取消关注");
+        });
+      }
+    },
+  },
 };
 </script>
 
@@ -121,11 +161,18 @@ export default {
         background-origin: border-box;
         box-sizing: border-box;
         background-clip: content-box, border-box;
+
+        &.follow {
+          background-image: linear-gradient(@bg, @bg),
+            linear-gradient(135deg, #939599, #939599);
+          color: #939599;
+        }
       }
 
       .text4 {
         span {
           font-size: 14px;
+          color: #fff;
           &:first-child {
             color: #939599;
             margin-right: 5px;

+ 18 - 0
src/main/nine-space/src/router/index.js

@@ -30,6 +30,15 @@ const routes = [
           title: "第九空间",
         },
       },
+      {
+        path: "/creator",
+        name: "creator",
+        component: () => import("../views/Creator.vue"),
+        meta: {
+          pageType: Page.Every,
+          title: "第九空间",
+        },
+      },
       {
         path: "/store",
         name: "store",
@@ -106,6 +115,15 @@ const routes = [
       title: "第九空间",
     },
   },
+  {
+    path: "/creatorDetail",
+    name: "creatorDetail",
+    component: () => import("../views/CreatorDetail.vue"),
+    meta: {
+      pageType: Page.Every,
+      title: "第九空间",
+    },
+  },
   {
     path: "/submit",
     name: "submit",

+ 133 - 6
src/main/nine-space/src/views/Creator.vue

@@ -1,9 +1,31 @@
 <template>
-  <div>
-    <creator-info></creator-info>
-    <creator-info></creator-info>
-    <creator-info></creator-info>
-    <creator-info></creator-info>
+  <div class="discover">
+    <van-sticky ref="top" @change="change">
+      <div class="top">
+        <div class="top-btn">
+          <div class="btn" @click="$router.push('/discover')">收藏探索</div>
+          <div class="btn active">铸造者</div>
+        </div>
+        <div class="search">
+          <img src="../assets/svgs/search.svg" alt="" />
+        </div>
+      </div>
+
+      <van-tabs
+        v-model:active="sort"
+        @change="getList"
+        line-width="16"
+        line-height="2"
+      >
+        <van-tab title="全部" name="createdAt,desc"></van-tab>
+        <van-tab title="最新" name="createdAt,desc"></van-tab>
+        <van-tab title="人气" name="followers,desc"></van-tab>
+      </van-tabs>
+    </van-sticky>
+
+    <template v-for="(item, index) in miners" :key="index">
+      <creator-info v-model:info="miners[index]"></creator-info>
+    </template>
   </div>
 </template>
 
@@ -11,7 +33,112 @@
 import CreatorInfo from "../components/creator/CreatorInfo.vue";
 export default {
   components: { CreatorInfo },
+  inject: ["bs"],
+  data() {
+    return {
+      miners: [],
+      stiky: null,
+      sort: "createdAt,desc",
+    };
+  },
+  beforeUnmount() {
+    if (this.stiky.parentNode.nodeName == "BODY") {
+      this.$nextTick(() => {
+        document.body.removeChild(this.stiky);
+      });
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.stiky = this.$refs.top.$el.childNodes[0];
+    });
+    this.getList();
+  },
+  methods: {
+    change(isFixed) {
+      if (isFixed) {
+        this.$nextTick(() => {
+          document.body.appendChild(this.stiky);
+        });
+      } else {
+        // this.$refs.top.$el.appendChild(this.stiky);
+      }
+    },
+    getList() {
+      this.$toast.loading({
+        message: "加载中...",
+        forbidClick: true,
+      });
+      this.$http
+        .post(
+          "/user/all",
+          {
+            page: 0,
+            query: { hasRole: "ROLE_MINTER" },
+            size: 20,
+            sort: this.sort,
+          },
+          { body: "json" }
+        )
+        .then((res) => {
+          this.miners = res.content;
+          setTimeout(() => {
+            this.bs.value.refresh();
+          }, 500);
+        });
+    },
+  },
 };
 </script>
 
-<style lang="less" scoped></style>
+<style lang="less" scoped>
+.top {
+  display: flex;
+  padding: 10px 16px;
+  background-color: @bg;
+  .top-btn {
+    flex-grow: 1;
+    .btn {
+      font-size: 16px;
+      font-family: ZhenyanGB;
+      font-weight: 400;
+      line-height: 26px;
+      display: inline-block;
+      vertical-align: text-bottom;
+
+      &.active {
+        color: @prim;
+        font-size: 20px;
+        font-weight: bold;
+        line-height: 30px;
+      }
+    }
+
+    .btn + .btn {
+      margin-left: 30px;
+    }
+  }
+}
+
+.discover {
+  background-color: @bg3;
+  padding-bottom: 100px;
+  min-height: 100vh;
+}
+
+/deep/.van-tab {
+  color: #fff;
+  flex: 0;
+  padding: 20px;
+  flex-shrink: 0;
+  min-width: 74px;
+
+  &.van-tab--active {
+    color: @prim;
+  }
+}
+
+/deep/ .van-tabs__line {
+  bottom: 20px;
+}
+</style>

+ 185 - 0
src/main/nine-space/src/views/CreatorDetail.vue

@@ -0,0 +1,185 @@
+<template>
+  <div class="mine">
+    <div class="userInfo">
+      <van-image
+        width="100%"
+        height="35vw"
+        :src="userInfo.bg"
+        fit="cover"
+        class="top-img"
+      />
+      <div class="userInfo-content">
+        <div class="userInfo-top">
+          <van-image
+            round
+            width="78"
+            height="78"
+            :src="
+              userInfo.avatar || require('../assets/svgs/img_default_photo.svg')
+            "
+            fit="cover"
+            @click="$router.push('/setting')"
+          />
+          <div class="text">
+            <div class="text1 van-ellipsis">{{ userInfo.nickname }}</div>
+            <div class="text2">
+              <span>{{ userInfo.id }}</span>
+              <img @click="copy" src="../assets/svgs/copy_icon.svg" alt="" />
+            </div>
+          </div>
+        </div>
+
+        <div class="sub">
+          {{ userInfo.intro }}
+        </div>
+
+        <div class="btns">
+          <div class="collect">
+            <div class="text1">{{ userInfo.follows }}</div>
+            <div class="text2">关注</div>
+          </div>
+          <div class="collect">
+            <div class="text1">{{ userInfo.followers }}</div>
+            <div class="text2">粉丝</div>
+          </div>
+          <div class="flex1"></div>
+          <van-button
+            plain
+            color="#fff"
+            size="mini"
+            :icon="require('../assets/svgs/person.svg')"
+            round
+            @click="goAuth"
+          >
+            {{ authStatus }}
+          </van-button>
+          <van-button
+            plain
+            @click="$router.push('/setting')"
+            color="#fff"
+            size="mini"
+            round
+            >编辑资料</van-button
+          >
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapState } from "vuex";
+export default {
+  computed: {
+    ...mapState(["userInfo"]),
+  },
+  data() {
+    return {
+      info: {},
+    };
+  },
+  mounted() {
+    this.getInfo();
+  },
+  methods: {
+    getInfo() {
+      this.$http.get("/user/get/" + this.$route.query.id).then((res) => {
+        this.info = res;
+      });
+    },
+  },
+};
+</script>
+
+<style lang="less" scoped>
+.userInfo {
+  padding-top: 35vw;
+  border-bottom: 5px solid @bg3;
+  position: relative;
+
+  .top-img {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 1;
+  }
+}
+.userInfo-content {
+  padding: 0 16px;
+  z-index: 2;
+  position: relative;
+  transform: translateY(-8px);
+  .sub {
+    font-size: 14px;
+    color: #939599;
+    line-height: 22px;
+    padding: 16px 0;
+  }
+
+  .btns {
+    display: flex;
+    // padding-bottom: 16px;
+    align-items: center;
+    .collect {
+      width: 20%;
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      .text1 {
+        font-size: 16px;
+        color: #ffffff;
+        line-height: 24px;
+      }
+      .text2 {
+        font-size: 14px;
+        color: #939599;
+        line-height: 24px;
+      }
+    }
+
+    /deep/.van-button {
+      width: 90px;
+      .van-icon__image {
+        display: block;
+        width: 18px;
+        height: 18px;
+      }
+    }
+    .van-button + .van-button {
+      margin-left: 10px;
+    }
+  }
+}
+.userInfo-top {
+  display: flex;
+  align-items: center;
+  .van-image {
+    border: 5px solid #fff;
+    flex-shrink: 0;
+  }
+
+  .text {
+    margin: 0 40px 0 12px;
+    overflow: hidden;
+    .text1 {
+      font-size: 24px;
+      font-weight: bold;
+      color: #ffffff;
+      line-height: 34px;
+    }
+    .text2 {
+      font-size: 16px;
+      color: #949699;
+      line-height: 24px;
+      display: flex;
+      align-items: center;
+      margin-top: 6px;
+      img {
+        display: block;
+        margin-left: 6px;
+      }
+    }
+  }
+}
+</style>

+ 111 - 87
src/main/nine-space/src/views/Discover.vue

@@ -3,96 +3,62 @@
     <van-sticky ref="top" @change="change">
       <div class="top">
         <div class="top-btn">
-          <div
-            class="btn"
-            :class="{ active: active === 'explore' }"
-            @click="changeActive('explore')"
-          >
-            收藏探索
-          </div>
-          <div
-            class="btn"
-            :class="{ active: active === 'creator' }"
-            @click="changeActive('creator')"
-          >
-            铸造者
-          </div>
+          <div class="btn active">收藏探索</div>
+          <div class="btn" @click="$router.push('/creator')">铸造者</div>
         </div>
         <div class="search">
           <img src="../assets/svgs/search.svg" alt="" />
         </div>
       </div>
-
-      <van-tabs
-        v-if="active === 'creator'"
-        v-model:active="type"
-        line-width="16"
-        line-height="2"
-      >
-        <van-tab title="全部"></van-tab>
-        <van-tab title="最新"></van-tab>
-        <van-tab title="人气"></van-tab>
-        <van-tab title="关注"></van-tab>
-      </van-tabs>
     </van-sticky>
 
-    <template v-if="active === 'explore'">
-      <swiper pagination class="mySwiper">
-        <swiper-slide><img src="../assets/banner.jpg" /></swiper-slide>
-        <swiper-slide><img src="../assets/banner.jpg" /></swiper-slide>
-        <swiper-slide><img src="../assets/banner.jpg" /></swiper-slide>
-        <swiper-slide><img src="../assets/banner.jpg" /></swiper-slide>
-        <swiper-slide><img src="../assets/banner.jpg" /></swiper-slide>
-        <swiper-slide><img src="../assets/banner.jpg" /></swiper-slide>
-      </swiper>
-
-      <van-grid :border="false">
-        <van-grid-item text="精选推荐">
-          <template v-slot:icon>
-            <img
-              class="grid-img"
-              src="../assets/svgs/info_icon_jingxuanxilie.svg"
-            />
-          </template>
-        </van-grid-item>
-        <van-grid-item text="原创系列">
-          <template v-slot:icon>
-            <img
-              class="grid-img"
-              src="../assets/svgs/info_icon_yuanchangxilie.svg"
-            />
-          </template>
-        </van-grid-item>
-        <van-grid-item text="数字盲盒">
-          <template v-slot:icon>
-            <img
-              class="grid-img"
-              src="../assets/svgs/info_icon_manghexilie.svg"
-            />
-          </template>
-        </van-grid-item>
-        <van-grid-item text="拍卖系列">
-          <template v-slot:icon>
-            <img
-              class="grid-img"
-              src="../assets/svgs/info_icon_paimaixilie.svg"
-            />
-          </template>
-        </van-grid-item>
-      </van-grid>
+    <swiper pagination class="mySwiper" v-if="banners.length > 0">
+      <swiper-slide v-for="item in banners" :key="item.id">
+        <img :src="item.pic" />
+      </swiper-slide>
+    </swiper>
 
-      <div class="title">本期推荐</div>
-      <div class="box-list">
-        <product-info></product-info>
-        <product-info></product-info>
-        <product-info></product-info>
-        <product-info></product-info>
-        <product-info></product-info>
-        <product-info></product-info>
-      </div>
-    </template>
+    <van-grid :border="false">
+      <van-grid-item text="精选推荐">
+        <template v-slot:icon>
+          <img
+            class="grid-img"
+            src="../assets/svgs/info_icon_jingxuanxilie.svg"
+          />
+        </template>
+      </van-grid-item>
+      <van-grid-item text="原创系列">
+        <template v-slot:icon>
+          <img
+            class="grid-img"
+            src="../assets/svgs/info_icon_yuanchangxilie.svg"
+          />
+        </template>
+      </van-grid-item>
+      <van-grid-item text="数字盲盒">
+        <template v-slot:icon>
+          <img
+            class="grid-img"
+            src="../assets/svgs/info_icon_manghexilie.svg"
+          />
+        </template>
+      </van-grid-item>
+      <van-grid-item text="拍卖系列">
+        <template v-slot:icon>
+          <img
+            class="grid-img"
+            src="../assets/svgs/info_icon_paimaixilie.svg"
+          />
+        </template>
+      </van-grid-item>
+    </van-grid>
 
-    <creator v-else> </creator>
+    <div class="title">本期推荐</div>
+    <div class="box-list">
+      <template v-for="(item, index) in list" :key="item.id">
+        <product-info v-model:info="list[index]"></product-info>
+      </template>
+    </div>
   </div>
 </template>
 
@@ -108,7 +74,6 @@ import SwiperCore, { Pagination } from "swiper";
 SwiperCore.use([Pagination]);
 
 import ProductInfo from "../components/product/productInfo.vue";
-import Creator from "./Creator.vue";
 
 export default {
   name: "discover",
@@ -117,13 +82,12 @@ export default {
     Swiper,
     SwiperSlide,
     ProductInfo,
-    Creator,
   },
   data() {
     return {
-      active: "explore",
       stiky: null,
-      type: 0,
+      banners: [],
+      list: [],
     };
   },
   beforeUnmount() {
@@ -137,22 +101,80 @@ export default {
     this.$nextTick(() => {
       this.stiky = this.$refs.top.$el.childNodes[0];
     });
+    this.getInit();
   },
   methods: {
+    getInit() {
+      this.$toast.loading({
+        message: "加载中...",
+        forbidClick: true,
+      });
+      Promise.all([this.getBanner(), this.getList()]).then(() => {
+        setTimeout(() => {
+          this.bs.value.refresh();
+        }, 500);
+      });
+    },
+    getBanner() {
+      this.$http
+        .post(
+          "/banner/all",
+          {
+            query: {
+              type: "DISCOVER",
+            },
+            sort: "createdAt,desc",
+          },
+          { body: "json" }
+        )
+        .then((res) => {
+          this.banners = res.content;
+        });
+    },
+    getList() {
+      this.$http
+        .post(
+          "/collection/all",
+          {
+            page: 0,
+            size: 20,
+            query: {
+              onShelf: true,
+            },
+            sort: "createdAt,desc",
+          },
+          { body: "json" }
+        )
+        .then((res) => {
+          this.list = res.content;
+        });
+    },
     change(isFixed) {
       if (isFixed) {
         this.$nextTick(() => {
           document.body.appendChild(this.stiky);
         });
       } else {
-        this.$refs.top.$el.appendChild(this.stiky);
+        // this.$refs.top.$el.appendChild(this.stiky);
       }
     },
     changeActive(active) {
-      this.active = active;
+      if (this.active === active) {
+        return;
+      }
       this.$nextTick(() => {
         this.bs.value.scrollTo(0, 0);
         this.bs.value.refresh();
+        setTimeout(() => {
+          this.active = active;
+          this.$nextTick(() => {
+            if (active === "explore") {
+              this.getInit();
+            } else {
+              this.$refs.creator.init();
+            }
+          });
+        }, 100);
       });
     },
   },
@@ -190,11 +212,13 @@ export default {
 
 .discover {
   background-color: @bg3;
+  padding-bottom: 100px;
 }
 
 /deep/ .mySwiper {
   width: calc(100vw - 32px);
   height: calc(41vw - 13px);
+  padding-top: 12px;
 
   .swiper-pagination {
     bottom: 12px;

+ 15 - 3
src/main/nine-space/src/views/Home.vue

@@ -35,6 +35,7 @@
           v-for="item in box"
           :key="item.id"
           :info="item"
+          v-model:info="box[index]"
         ></product-info>
       </div>
     </div>
@@ -111,9 +112,20 @@ export default {
       forbidClick: true,
     });
     Promise.all([
-      this.$http.post("/banner/all", {}, { body: "json" }).then((res) => {
-        this.banners = res.content;
-      }),
+      this.$http
+        .post(
+          "/banner/all",
+          {
+            query: {
+              type: "HOME",
+            },
+            sort: "createdAt,desc",
+          },
+          { body: "json" }
+        )
+        .then((res) => {
+          this.banners = res.content;
+        }),
       this.getProduct("BLIND_BOX").then((res) => {
         this.box = res;
       }),

+ 28 - 12
src/main/nine-space/src/views/order/Orders.vue

@@ -5,15 +5,15 @@
         <div class="top-btn">
           <div
             class="btn"
-            :class="{ active: active === 'explore' }"
-            @click="changeActive('explore')"
+            :class="{ active: type === 'DEFAULT' }"
+            @click="changeActive('DEFAULT')"
           >
             商品订单
           </div>
           <div
             class="btn"
-            :class="{ active: active === 'creator' }"
-            @click="changeActive('creator')"
+            :class="{ active: type === 'BLIND_BOX' }"
+            @click="changeActive('BLIND_BOX')"
           >
             盲盒订单
           </div>
@@ -24,7 +24,7 @@
       </div>
 
       <van-tabs
-        v-model:active="type"
+        v-model:active="status"
         line-width="16"
         line-height="2"
         @click="changeStatus"
@@ -58,7 +58,8 @@ export default {
     return {
       active: "explore",
       stiky: null,
-      type: "PROCESSING,FINISH",
+      status: "PROCESSING,FINISH",
+      type: "DEFAULT",
       list: [],
       tabs: [
         {
@@ -85,8 +86,8 @@ export default {
     }
   },
   mounted() {
-    if (this.$route.query.type) {
-      this.type = this.$route.query.type;
+    if (this.$route.query.status) {
+      this.status = this.$route.query.status;
     }
     this.$nextTick(() => {
       this.stiky = this.$refs.top.$el.childNodes[0];
@@ -107,7 +108,8 @@ export default {
             size: 20,
             query: {
               userId: this.$store.state.userInfo.id,
-              status: this.type,
+              status: this.status,
+              type: this.type,
             },
             sort: "createdAt,desc",
           },
@@ -125,9 +127,13 @@ export default {
       this.$router.replace({
         path: "/orders",
         query: {
-          type: name,
+          status: name,
+          type: this.type,
         },
       });
+      this.$nextTick(() => {
+        this.bs.value.scrollTo(0, 0);
+      });
       this.getList();
     },
     change(isFixed) {
@@ -140,11 +146,21 @@ export default {
       }
     },
     changeActive(active) {
-      this.active = active;
+      if (this.type === active) {
+        return;
+      }
+      this.type = active;
+      this.$router.replace({
+        path: "/orders",
+        query: {
+          type: active,
+          status: this.status,
+        },
+      });
       this.$nextTick(() => {
         this.bs.value.scrollTo(0, 0);
-        this.bs.value.refresh();
       });
+      this.getList();
     },
   },
 };