Przeglądaj źródła

全局-个人主页,数据绑定

martin.ma 4 lat temu
rodzic
commit
97db13c704

+ 42 - 5
assets/css/frontend/personal.scss

@@ -96,6 +96,13 @@
 .personal-share-area {
   margin-top: 14px;
 }
+
+// "github_name": " github账户名",
+//     "zhihu_name": "知乎账户",
+//     "gitee_name": "gitee账号",
+//     "csdn_name": "csdn账号",
+//     "wechat_name": "微信账户",
+//     "juejin_name": "掘金账户",
 .personal-share-btn {
   display: inline-block;
   width: 18px;
@@ -103,7 +110,29 @@
   margin-left: 21px;
   border-radius: 100%;
   overflow: hidden;
-  background-color: #ccc;
+  // background-color: #ccc;
+  background-repeat: no-repeat;
+  background-size: auto 100%;
+  background-position: center;
+  cursor: pointer;
+  &.github {
+    background-image: url('~@/assets/img/sign/github@2x.png');
+  }
+  &.zhihu {
+    background-image: url('~@/assets/img/sign/zhihu.png');
+  }
+  &.gitee {
+    background-image: url('~@/assets/img/credit/gitee.png');
+  }
+  &.csdn {
+    background-image: url('~@/assets/img/sign/csdn@2x.png');
+  }
+  &.wechat {
+    background-image: url('~@/assets/img/sign/wechat@2x.png');
+  }
+  &.juejin {
+    background-image: url('~@/assets/img/sign/juejin@2x.png');
+  }
 }
 
 .personal-follow-btn {
@@ -189,10 +218,7 @@
   line-height: 21px;
 }
 
-.personal-ad-container {
-  height: 247px;
-  @extend %block;
-}
+
 
 // tab框样式
 .personal-content-container {
@@ -275,3 +301,14 @@
   color: #828c99;
   padding:20px 0;
 }
+
+.personal-ad-container {
+  // height: 247px;
+  // padding:16px 0;
+  overflow: hidden;
+  @extend %block;
+}
+.ad-item{
+  margin:16px;
+  display:block;
+}

BIN
assets/img/credit/zhihu.png


+ 17 - 15
pages/frontend/personal/component/article-item.vue

@@ -2,31 +2,33 @@
 <div class="article-item-container">
     <div class="article-main">
         <div class="article-author-info">
-            <span>陈世杰jackey</span>
+            <span>{{articleUserInfo.nickname}}</span>
             <span class="article-time">2021-12-4</span>
-            <span class="article-job">前端工程师@阿里巴巴</span>
+            <span class="article-job">{{articleUserInfo.direction_op_name}}@{{articleUserInfo.company}}</span>
         </div>
-        <div class="article-title">技术人最应该提升系统设计方法论</div>
+        <div class="article-title">{{info.title}}</div>
         <div class="article-content">
-            在公司,只有我使用VSCode,其他同事都使用Web
-            Storm,我也向他们推荐过VSCode……
+            {{info.excerpt}}
         </div>
         <div class="article-count">
-            <div class="article-count-item read">8338</div>
-            <div class="article-count-item like">8338</div>
-            <div class="article-count-item comment">8338</div>
+            <div class="article-count-item read">{{info.view_count}}</div>
+            <div class="article-count-item like">{{info.like_count}}</div>
+            <div class="article-count-item comment">{{info.reply_count}}</div>
         </div>
     </div>
-    <div class="article-cover">
-        <img src="https://iph.href.lu/174x116?fg=666666&bg=cccccc" alt="" />
+    <div class="article-cover" v-if="info.cover_url">
+        <el-image style="width:174px;height:116px" fit="cover" :src="info.cover_url"></el-image>
     </div>
 </div>
 </template>
 
 <script>
 export default {
-    data() {
-        return {};
+    props: ["info"],
+    computed: {
+        articleUserInfo() {
+            return this.info.user_info || {};
+        }
     }
 };
 </script>
@@ -39,9 +41,9 @@ export default {
     align-items: center;
     border-bottom: 1px solid #ebeced;
 
-    &:nth-last-child(1) {
-        border-bottom: none;
-    }
+    // &:nth-last-child(1) {
+        // border-bottom: none;
+    // }
 }
 
 .article-main {

+ 27 - 14
pages/frontend/personal/component/course-item.vue

@@ -1,28 +1,40 @@
 <template>
-<div class="course-item-container">
+<div class="course-item-container" @click='linkTo'>
     <div class="course-main">
-        <div class="course-title">技术人最应该提升系统设计方法论</div>
+        <div class="course-title">{{info.title}}</div>
         <div class="course-content">
-            在公司,只有我使用VSCode,其他同事都使用WebStorm,我也向他们推荐…
+            {{info.desc}}
         </div>
         <div class="course-author">
-            <img class="course-author-avatar" src="https://iph.href.lu/200x200?fg=666666&bg=cccccc" alt="" />
-            <div class="course-author-name">神奇的命令行</div>
-            <div class="course-author-title">前端工程师@阿里巴巴</div>
+            <img class="course-author-avatar" :src="courseUserInfo.icon_url" alt="" />
+            <div class="course-author-name">{{courseUserInfo.nickname}}</div>
+            <div class="course-author-title">{{courseUserInfo.direction_op_name}}@{{courseUserInfo.company}}</div>
         </div>
         <div class="course-bug-info">
-            <div class="course-price">¥300</div>
-            <div class="course-lesson-count">共17小节 · 12人已购买</div>
+            <div class="course-price">¥{{info.price}}</div>
+            <div class="course-lesson-count">共{{info.zj_num}}小节 · {{info.buy_num}}人已购买</div>
         </div>
     </div>
-    <div class="course-cover">
-        <img src="https://iph.href.lu/174x116?fg=666666&bg=cccccc" alt="" />
+    <div class="course-cover" v-if="info.img_icon">
+        <el-image style="width:174px;height:116px" fit="cover" :src="info.cover_url"></el-image>
     </div>
 </div>
 </template>
 
 <script>
-export default {};
+export default {
+    props: ["info"],
+    computed: {
+        courseUserInfo() {
+            return this.info.user_info || {};
+        },
+    },
+    methods:{
+        linkTo(){
+            location.href = this.info.link;
+        }
+    }
+};
 </script>
 
 <style lang="scss" scoped>
@@ -34,10 +46,11 @@ export default {};
     border-bottom: 1px solid #ebeced;
     display: flex;
     align-items: center;
+    cursor: pointer;
 
-    &:nth-last-child(1) {
-        border-bottom: none;
-    }
+    // &:nth-last-child(1) {
+    //     border-bottom: none;
+    // }
 }
 
 .course-main {

+ 196 - 144
pages/frontend/personal/component/dynamic-item.vue

@@ -1,203 +1,255 @@
 <template>
-  <div class="dynamic-item-container">
+<div class="dynamic-item-container">
     <div class="dynamic-item-avatar">
-      <img src="https://iph.href.lu/200x200?fg=666666&bg=cccccc" alt="" />
+        <img :src="dynamicUserInfo.icon_url" alt="" />
     </div>
     <div class="dynamic-main">
-      <div class="dynamic-user-name">神奇的命令行</div>
-      <div class="dynamic-user-login-info">Architect@Cml · 3小时前</div>
-      <p class="dynamic-content">
-        随着自然资源的减少和气候危机的加剧,循环经济的概念在全球范围内越来越受到关注。大多数现代经济都是线性的——它们遵循“获取、制造、废弃”的模式,在这种模式下,自然资源被提取,有价值的元素被转化为产品,剩下的一切(连同不再有用的产品本身)作为废物被丢弃。相比之下,循环经济以现有产品的改造取代资源开采,从根本上完全……
-      </p>
-      <div class="dynamic-more">
+        <div class="dynamic-user-name">{{ dynamicUserInfo.nickname }}</div>
+        <div class="dynamic-user-login-info" v-if="dynamicUserInfo.tag.length > 0">
+            <span>{{ dynamicUserInfo.tag[0].name }}</span>
+            <span v-if="dynamicUserInfo.tag[1]">· {{ dynamicUserInfo.tag[1].name }}</span>
+        </div>
+        <p class="dynamic-content">
+            {{ info.title }}
+        </p>
+        <!-- <div class="dynamic-more">
         展开
-      </div>
-      <div class="dynamic-link">
-        <div class="dynamic-link-content">
-          <p class="dynamic-link-title">芬兰计划到2050年消除所有垃圾</p>
-          <p class="dynamic-link-herf">www.solidot.org</p>
+      </div> -->
+        <div class="dynamic-link"  @click.capture.stop="clickResource(dynamicResources)"  v-if="dynamicResources.resources_status == 1">
+            <div class="dynamic-link-content">
+                <p class="dynamic-link-title">
+                    {{ dynamicResources.resources_title }}
+                </p>
+                <p class="dynamic-link-herf">{{ dynamicResources.resources_url }}</p>
+            </div>
+            <div class="dynamic-link-img">
+                <img :src="dynamicResources.resources_img" alt="" />
+            </div>
+        </div>
+        <div class="dynamic-images" v-if="dynamicImg.length > 0">
+            <div v-for="(item, index) in dynamicImg" :key="index" class="dynamic-image-item">
+                <el-image style="width:90px;height:90px" fit="cover" :src="item.img" :preview-src-list="dynamicImgBig">
+                </el-image>
+            </div>
         </div>
-        <div class="dynamic-link-img">
-          <img src="https://iph.href.lu/200x200?fg=666666&bg=cccccc" alt="" />
+        <div class="dynamic-type">
+            {{ info.type_text }}
         </div>
-      </div>
-      <div class="dynamic-images">
-        <div
-          v-for="(item, index) in 10"
-          :key="index"
-          class="dynamic-image-item"
-        >
-          <img src="https://iph.href.lu/200x200?fg=666666&bg=cccccc" alt="" />
+        <div class="dynamic-operation">
+            <div class="dynamic-operation-btn share" @click="gotoAppTips">分享</div>
+            <div class="dynamic-operation-btn like" @click="gotoAppTips">点赞</div>
+            <div class="dynamic-operation-btn comment" @click="gotoAppTips">
+                评论
+            </div>
         </div>
-      </div>
-      <div class="dynamic-type">
-        今日新鲜事
-      </div>
-      <div class="dynamic-operation">
-        <div class="dynamic-operation-btn share">分享</div>
-        <div class="dynamic-operation-btn like">点赞</div>
-        <div class="dynamic-operation-btn comment">评论</div>
-      </div>
     </div>
-  </div>
+</div>
 </template>
 
 <script>
 export default {
-  data() {
-    return {};
-  }
+    props: ["info"],
+    computed: {
+        dynamicUserInfo() {
+            return this.info.user_info || {};
+        },
+        dynamicResources() {
+            return this.info.resources || {};
+        },
+        dynamicImg() {
+            return this.info.img || [];
+        },
+        dynamicImgBig() {
+            let imgList = this.info.img || [];
+            imgList = imgList.map(item => {
+                return item.img
+            })
+            return imgList
+        }
+    },
+    methods: {
+        gotoAppTips() {
+            this.checkLogin(true);
+            this.$message("请前往APP查看");
+        },
+        clickResource(resources){
+            if(resources.resources_status != 1){
+                this.$message.info(resources.resources_text)
+            }else{
+                location.href = resources.resources_url
+            }
+        },
+    }
 };
 </script>
 
 <style lang="scss" scoped>
 .dynamic-item-container {
-  padding: 29px 24px 16px;
-  border-bottom: 1px solid #ebeced;
-  display: flex;
-  &:nth-last-child(1){
-      border-bottom: none
-  }
+    padding: 29px 24px 16px;
+    border-bottom: 1px solid #ebeced;
+    display: flex;
+
+    // &:nth-last-child(1) {
+    //     border-bottom: none;
+    // }
 }
 
 .dynamic-item-avatar {
-  width: 24px;
-  height: 24px;
-  margin-right: 10px;
-  img {
-    width: 100%;
-    height: 100%;
-    border-radius: 100%;
-  }
+    width: 24px;
+    height: 24px;
+    margin-right: 10px;
+
+    img {
+        width: 100%;
+        height: 100%;
+        border-radius: 100%;
+    }
 }
 
 .dynamic-main {
-  flex: 1;
+    flex: 1;
 }
 
 .dynamic-user-name {
-  font-size: 14px;
-  font-family: PingFangSC-Medium, PingFang SC;
-  font-weight: 500;
-  color: #0b121a;
-  line-height: 20px;
+    font-size: 14px;
+    font-family: PingFangSC-Medium, PingFang SC;
+    font-weight: 500;
+    color: #0b121a;
+    line-height: 20px;
 }
+
 .dynamic-user-login-info {
-  margin-top: 3px;
-  font-size: 12px;
-  font-family: PingFangSC-Regular, PingFang SC;
-  font-weight: 400;
-  color: #828c99;
-  line-height: 17px;
+    margin-top: 3px;
+    font-size: 12px;
+    font-family: PingFangSC-Regular, PingFang SC;
+    font-weight: 400;
+    color: #828c99;
+    line-height: 17px;
 }
+
 .dynamic-content {
-  margin-top: 12px;
-  font-size: 14px;
-  font-family: PingFangSC-Regular, PingFang SC;
-  font-weight: 400;
-  color: #0b111a;
-  line-height: 21px;
+    margin-top: 12px;
+    font-size: 14px;
+    font-family: PingFangSC-Regular, PingFang SC;
+    font-weight: 400;
+    color: #0b111a;
+    line-height: 21px;
+    margin-bottom: 16px;
 }
+
 .dynamic-more {
-  margin-top: 6px;
-  font-size: 14px;
-  font-family: PingFangSC-Regular, PingFang SC;
-  font-weight: 400;
-  color: #308eff;
-  line-height: 21px;
+    margin-top: 6px;
+    font-size: 14px;
+    font-family: PingFangSC-Regular, PingFang SC;
+    font-weight: 400;
+    color: #308eff;
+    line-height: 21px;
 }
 
 .dynamic-link {
-  margin-top: 16px;
-  background: #f7f8fa;
-  padding: 12px 14px;
-  display: flex;
+    margin-top: 16px;
+    background: #f7f8fa;
+    padding: 12px 14px;
+    display: flex;
+    margin-bottom: 16px;
+    cursor: pointer;
 }
+
 .dynamic-link-content {
-  flex: 1;
+    flex: 1;
 }
+
 .dynamic-link-title {
-  font-size: 16px;
-  font-family: PingFangSC-Medium, PingFang SC;
-  font-weight: 500;
-  color: #0b111a;
-  line-height: 21px;
+    font-size: 16px;
+    font-family: PingFangSC-Medium, PingFang SC;
+    font-weight: 500;
+    color: #0b111a;
+    line-height: 21px;
 }
+
 .dynamic-link-herf {
-  margin-top: 21px;
-  font-size: 14px;
-  font-family: PingFangSC-Regular, PingFang SC;
-  font-weight: 400;
-  color: #828c99;
-  line-height: 20px;
+    margin-top: 21px;
+    font-size: 14px;
+    font-family: PingFangSC-Regular, PingFang SC;
+    font-weight: 400;
+    color: #828c99;
+    line-height: 20px;
 }
 
 .dynamic-link-img {
-  width: 66px;
-  height: 66px;
-  margin-left: 20px;
-  img {
-    width: 100%;
-    height: 100%;
-  }
+    width: 66px;
+    height: 66px;
+    margin-left: 20px;
+
+    img {
+        width: 100%;
+        height: 100%;
+    }
 }
 
 .dynamic-images {
-  display: flex;
-  //   justify-content: space-between;
-  flex-wrap: wrap;
-  margin-top: 16px;
+    display: flex;
+    //   justify-content: space-between;
+    flex-wrap: wrap;
 }
+
 .dynamic-image-item {
-  width: 90px;
-  height: 90px;
-  margin-right: 10px;
-  margin-bottom: 16px;
-  img {
-    width: 100%;
-    height: 100%;
-  }
+    width: 90px;
+    height: 90px;
+    margin-right: 10px;
+    margin-bottom: 16px;
+
+    img {
+        width: 100%;
+        height: 100%;
+    }
 }
+
 .dynamic-type {
-  width: 80px;
-  height: 23px;
-  background: #ebf4ff;
-  border-radius: 12px;
-  text-align: center;
-  line-height: 23px;
-
-  font-size: 12px;
-  font-family: PingFangSC-Regular, PingFang SC;
-  font-weight: 400;
-  color: #288bff;
+    margin-top: 16px;
+    width: 80px;
+    height: 23px;
+    background: #ebf4ff;
+    border-radius: 12px;
+    text-align: center;
+    line-height: 23px;
+
+    font-size: 12px;
+    font-family: PingFangSC-Regular, PingFang SC;
+    font-weight: 400;
+    color: #288bff;
 }
+
 .dynamic-operation {
-  display: flex;
-  margin-top: 26px;
-  justify-content: space-around;
+    display: flex;
+    margin-top: 26px;
+    justify-content: space-around;
 }
 
 .dynamic-operation-btn {
-  // flex: 1;
-  font-size: 14px;
-  font-family: PingFangSC-Regular, PingFang SC;
-  font-weight: 400;
-  color: #333333;
-  line-height: 20px;
-  padding-left: 26px;
-
-  background-size: auto 100%;
-  background-repeat: no-repeat;
-  background-position: left center;
-  cursor: pointer;
-  &.share {
-      background-image: url('~@/assets/img/frontend/personal/share.png');
-  }
-  &.like {
-      background-image: url('~@/assets/img/frontend/personal/like2.png');
-  }
-  &.comment {
-      background-image: url('~@/assets/img/frontend/personal/comment2.png');
-  }
+    // flex: 1;
+    font-size: 14px;
+    font-family: PingFangSC-Regular, PingFang SC;
+    font-weight: 400;
+    color: #333333;
+    line-height: 20px;
+    padding-left: 26px;
+
+    background-size: auto 100%;
+    background-repeat: no-repeat;
+    background-position: left center;
+    cursor: pointer;
+
+    &.share {
+        background-image: url("~@/assets/img/frontend/personal/share.png");
+    }
+
+    &.like {
+        background-image: url("~@/assets/img/frontend/personal/like2.png");
+    }
+
+    &.comment {
+        background-image: url("~@/assets/img/frontend/personal/comment2.png");
+    }
 }
 </style>

+ 369 - 260
pages/frontend/personal/index.vue

@@ -1,112 +1,138 @@
 <template>
-  <div
-    :class="mobile ? 'mobileMain' : ''"
-    :style="{
+<div :class="mobile ? 'mobileMain' : ''" :style="{
       marginTop: mainMarginTop,
       marginBottom: mobile ? '0px' : '30px !important'
-    }"
-  >
+    }">
     <div v-if="!mobile" class="personal-container">
-      <div class="personal-main">
-        <!-- 个人信息框 -->
-        <div class="personal-info-container">
-          <div class="personal-user">
-            <div class="personal-user-avatar">
-              <img
-                class="personal-user-avatar-img"
-                :src="userInfo.icon_url"
-              />
-              <span class="personal-user-tag"></span>
+        <div class="personal-main">
+            <!-- 个人信息框 -->
+            <div class="personal-info-container">
+                <div class="personal-user">
+                    <div class="personal-user-avatar">
+                        <img class="personal-user-avatar-img" :src="personalUserInfo.icon" />
+                        <span class="personal-user-tag" v-if="personalUserInfo.person_vip_status == 1"></span>
+                    </div>
+                    <div class="personal-user-info">
+                        <div class="personal-user-name">
+                            <span class="name-cotent">{{ personalUserInfo.nickname
+                  }}<span v-if="personalUserInfo.direction_name">({{ personalUserInfo.direction_name }})</span></span>
+                            <LevelTag :level="personalUserInfo.fw_freework_level"></LevelTag>
+                        </div>
+                        <div class="personal-user-text">
+                            {{ personalUserInfo.lasttime }} ·
+                            {{ personalUserInfo.dynamic_view_num }}浏览
+                        </div>
+                        <div class="personal-user-text" v-if="registerTime">
+                            {{ registerTime }}加入
+                        </div>
+                    </div>
+                </div>
+                <div class="personal-user-follow">
+                    <p class="personal-report">
+                        <a :href="'/otherpage/report/' + personalUserInfo.uid" target="view_window">举报</a>
+                    </p>
+                    <div class="personal-share-area">
+                        <span v-if="personalUserInfo.github_name" @click="
+                  linkToThirdParty(personalUserInfo.github_name, 'github_name')
+                " class="personal-share-btn github"></span>
+                        <span v-if="personalUserInfo.gitee_name" @click="
+                  linkToThirdParty(personalUserInfo.gitee_name, 'gitee_name')
+                " class="personal-share-btn gitee"></span>
+                        <span v-if="personalUserInfo.csdn_name" @click="
+                  linkToThirdParty(personalUserInfo.csdn_name, 'csdn_name')
+                " class="personal-share-btn csdn"></span>
+                        <span v-if="personalUserInfo.wechat_name" @click="
+                  linkToThirdParty(personalUserInfo.wechat_name, 'wechat_name')
+                " class="personal-share-btn wechat"></span>
+                        <span v-if="personalUserInfo.juejin_name" @click="
+                  linkToThirdParty(personalUserInfo.juejin_name, 'juejin_name')
+                " class="personal-share-btn juejin"></span>
+                        <span v-if="personalUserInfo.zhihu_name" class="personal-share-btn zhihu"></span>
+                    </div>
+                    <div class="personal-follow-btn" @click="toggleFollow" v-if="isShowFollow">
+                        {{ isFollowing ? "已关注" : "关注" }}
+                    </div>
+                </div>
             </div>
-            <div class="personal-user-info">
-              <div class="personal-user-name">
-                <span class="name-cotent">{{userInfo.nickname}}({{userInfo.title}})</span>
-                <LevelTag :level="2"></LevelTag>
-              </div>
-              <div class="personal-user-text">2天前在线 · 431浏览</div>
-              <div class="personal-user-text">2022年2月加入</div>
-            </div>
-          </div>
-          <div class="personal-user-follow">
-            <p class="personal-report"><a href="">举报</a></p>
-            <div class="personal-share-area">
-              <span class="personal-share-btn"></span>
-              <span class="personal-share-btn"></span>
-            </div>
-            <div class="personal-follow-btn">
-              关注
-            </div>
-          </div>
-        </div>
 
-        <!-- 内容tab -->
-        <div class="personal-content-container">
-          <div class="personal-content-tab">
-            <!-- tab框 -->
-            <div
-              v-for="item in tabs"
-              @click="tabSelected = item.id"
-              :key="item.id"
-              class="personal-tab-item"
-              :class="{ cur: tabSelected == item.id }"
-            >
-              {{ item.label }} {{ item.count }}
-            </div>
-          </div>
-          <div class="personal-content-main">
-            <template v-if="tabSelected == 1">
-              <div v-for="(item, index) in list" :key="index">
-                <DynamicItem></DynamicItem>
-              </div>
-            </template>
+            <!-- 内容tab -->
+            <div class="personal-content-container">
+                <div class="personal-content-tab">
+                    <!-- tab框 -->
+                    <div class="personal-tab-item" :class="{ cur: tabSelected == 1 }" @click="tabSelected = 1">
+                        动态 {{ dynamicCount }}
+                    </div>
+                    <div class="personal-tab-item" :class="{ cur: tabSelected == 2 }" @click="tabSelected = 2">
+                        文章 {{ articleCount }}
+                    </div>
+                    <div class="personal-tab-item" :class="{ cur: tabSelected == 3 }" @click="tabSelected = 3">
+                        视频课程 {{ courseCount }}
+                    </div>
+                </div>
+                <div class="personal-content-main">
+                    <template v-if="tabSelected == 1">
+                        <div v-for="item in list" :key="item.dynamicId">
+                            <DynamicItem :info="item"></DynamicItem>
+                        </div>
+                    </template>
 
-            <template v-if="tabSelected == 3">
-              <div v-for="(item, index) in list" :key="index">
-                <ArticleItem></ArticleItem>
-              </div>
-            </template>
-            <template v-if="tabSelected == 4">
-              <div v-for="(item, index) in list" :key="index">
-                <CourseItem></CourseItem>
-              </div>
-            </template>
+                    <template v-if="tabSelected == 2">
+                        <div v-for="(item, index) in list" :key="index">
+                            <ArticleItem :info="item"></ArticleItem>
+                        </div>
+                    </template>
+                    <template v-if="tabSelected == 3">
+                        <div v-for="(item, index) in list" :key="index">
+                            <CourseItem :info="item"></CourseItem>
+                        </div>
+                    </template>
 
-            <div class="data-empty" v-if="list.length == 0 && !loading">
-              <Empty></Empty>
-              <p>暂无内容</p>
-            </div>
+                    <div class="data-empty" v-if="list.length == 0 && !pageLoading">
+                        <Empty></Empty>
+                        <p>暂无内容</p>
+                    </div>
 
-            <div class="loading" v-if="loading">加载中</div>
+                    <div class="loading" v-if="pageLoading">加载中</div>
 
-            <!-- 列表内容 -->
-          </div>
-        </div>
-      </div>
-      <div class="personal-side">
-        <div class="personal-page-link">
-          <span>Ta的开发工作主页</span>
-          <span class="arrow"></span>
+                    <!-- 列表内容 -->
+                </div>
+            </div>
         </div>
+        <div class="personal-side">
+            <a class="personal-page-link" :href="'/wo/'+personUid" target="view_window">
+                <span>Ta的开发工作主页</span>
+                <span class="arrow"></span>
+            </a>
 
-        <div class="personal-follow-info">
-          <div class="personal-follow-item">
-            <span class="personal-follow-label">关注了</span>
-            <span class="personal-follow-count">{{followers_count}}</span>
-          </div>
-          <div class="personal-follow-item">
-            <span class="personal-follow-label">关注者</span>
-            <span class="personal-follow-count">{{fans_count}}</span>
-          </div>
-        </div>
+            <div class="personal-follow-info">
+                <div class="personal-follow-item">
+                    <span class="personal-follow-label">关注了</span>
+                    <span class="personal-follow-count">{{
+              personalUserInfo.my_followers
+            }}</span>
+                </div>
+                <div class="personal-follow-item">
+                    <span class="personal-follow-label">关注者</span>
+                    <span class="personal-follow-count">{{
+              personalUserInfo.followers_my
+            }}</span>
+                </div>
+            </div>
 
-        <div class="personal-ad-container"></div>
-      </div>
+            <div class="personal-ad-container">
+                <a class="ad-item" v-for="(item, index) in adList" :key="index" :href="item.url" target="view_window">
+                    <el-image style="width:318px;height:233px" fit="cover" :src="item.image"></el-image>
+                </a>
+            </div>
+        </div>
     </div>
-  </div>
+</div>
 </template>
 
 <script>
-import { mapState } from "vuex";
+import {
+    mapState
+} from "vuex";
 import qs from "qs";
 import DynamicItem from "./component/dynamic-item.vue";
 import ArticleItem from "./component/article-item.vue";
@@ -115,193 +141,276 @@ import CourseItem from "./component/course-item.vue";
 import Empty from "@/components/empty.vue";
 
 import LevelTag from "@/components/level-tag.vue";
+import PersonalSeoData from "./personalData";
+import moment from "moment";
 export default {
-  name: "PersonalIndex",
-  components: {
-    LevelTag,
-    DynamicItem,
-    ArticleItem,
-    CourseItem,
-    Empty
-  },
-  data() {
-    return {
-      baseUrl: "",
-      mobile: false,
-      // firstLoad: true,
-      isWeixinApp: true,
-      tabSelected: 1,
-      tabs: [
-        {
-          id: 1,
-          label: "动态",
-          count: 10
-        },
-        {
-          id: 3,
-          label: "文章",
-          count: 10
-        },
-        {
-          id: 4,
-          label: "视频课程",
-          count: 10
-        }
-      ],
+    name: "PersonalIndex",
+    components: {
+        LevelTag,
+        DynamicItem,
+        ArticleItem,
+        CourseItem,
+        Empty
+    },
+    data() {
+        return {
+            baseUrl: "",
+            mobile: false,
+            // firstLoad: true,
+            isWeixinApp: true,
+            tabSelected: 1,
+            tabs: [{
+                    id: 1,
+                    label: "动态",
+                    count: 10
+                },
+                {
+                    id: 2,
+                    label: "文章",
+                    count: 10
+                },
+                {
+                    id: 3,
+                    label: "视频课程",
+                    count: 10
+                }
+            ],
 
-      list: [],
-      loading: true,
-      page: 0,
-      pageSize: 10,
+            list: [],
+            page: 1,
+            pageSize: 10,
 
-      user: {
-      },
-      uid: "",
-    };
-  },
-  watch: {
-    tabSelected: function() {
-      this.resetTab();
-    }
-  },
-  head() {
-    const {
-      title = "",
-      keyword = "",
-      description = "",
-      h1 = "",
-      canonical = "",
-      metaLocation
-    } = this.head || {};
-    let obj = {
-      title: title,
-      meta: [
-        {
-          name: "keywords",
-          content: keyword
-        },
-        {
-          name: "description",
-          content: description
-        },
-        {
-          name: "h1",
-          content: h1
+            isMore: true,
+            pageLoading: false,
+
+            user: {},
+            personUid: ""
+        };
+    },
+    watch: {
+        tabSelected: function () {
+            this.resetTab();
         }
-      ],
-      link: [
-        {
-          rel: "canonical",
-          href: canonical
+    },
+    head() {
+        const {
+            title = "",
+                keyword = "",
+                description = "",
+                h1 = "",
+                canonical = "",
+                metaLocation
+        } = this.head || {};
+        let obj = {
+            title: title,
+            meta: [{
+                    name: "keywords",
+                    content: keyword
+                },
+                {
+                    name: "description",
+                    content: description
+                },
+                {
+                    name: "h1",
+                    content: h1
+                }
+            ],
+            link: [{
+                rel: "canonical",
+                href: canonical
+            }]
+        };
+        if (metaLocation) {
+            obj.meta.push({
+                name: "location",
+                content: metaLocation
+            });
         }
-      ]
-    };
-    if (metaLocation) {
-      obj.meta.push({
-        name: "location",
-        content: metaLocation
-      });
-    }
-    return obj;
-  },
-  computed: {
-    ...mapState(["deviceType"]),
-    showWxHeader() {
-      return (
-        !this.deviceType.app &&
-        !this.isWeixinApp &&
-        (this.deviceType.android || this.deviceType.ios)
-      );
+        return obj;
     },
-    mainMarginTop() {
-      if (this.mobile && this.showWxHeader) {
-        return "64px !important";
-      } else if (this.mobile) {
-        return "0px !important";
-      } else {
-        return "20px !important";
-      }
-    }
-  },
-
-  mounted() {
-    const { id: uid } = this.$route.params;
-    this.uid = uid;
-    this.baseUrl = this.$store.state.domainConfig.siteUrl;
-    this.isWeixinApp = navigator.userAgent.indexOf("miniProgram") > -1;
-
-    if (uid) {
-      this.fetchData();
-      this.fetchPersonInfo()
-      this.$nextTick(() => {
-        this.listenToEnd();
-      });
-    }
-  },
-  methods: {
-    async fetchPersonInfo() {
-      let uid = this.uid
-      let result =  await this.$axios.$post("/uapi/dynamic/get_dynamic_list_my", {
-        to_uid: uid,
-        page: 1,
-      });
-
-      if(result.status === 1){
-        let {
-         user
-        } = result.data
-
-        this.user = {
-          ...user
+    computed: {
+        ...mapState(["deviceType"]),
+        showWxHeader() {
+            return (
+                !this.deviceType.app &&
+                !this.isWeixinApp &&
+                (this.deviceType.android || this.deviceType.ios)
+            );
+        },
+        mainMarginTop() {
+            if (this.mobile && this.showWxHeader) {
+                return "64px !important";
+            } else if (this.mobile) {
+                return "0px !important";
+            } else {
+                return "20px !important";
+            }
+        },
+        registerTime() {
+            if (this.personalUserInfo.logintime) {
+                let time = moment(this.personalUserInfo.logintime * 1000).format(
+                    "YYYY年MM月"
+                );
+                return time;
+            } else {
+                return 0;
+            }
+        },
+        isShowFollow() {
+            let isLogin = this.userinfo.uid
+            let isMine = this.userinfo.uid == this.personUid ? true : false
+            if (!isLogin) return true
+            return isMine ? false : true
         }
-        this.followers_count = followers_count
-        this.fans_count = fans_count
-        this.has_follow = has_follow
-
-
+    },
 
-      }else{
-        // this.isExist = false;
-      }
+    mounted() {
+        this.personUid = this.$route.params.uid;
+        this.baseUrl = this.$store.state.domainConfig.siteUrl;
+        this.isWeixinApp = navigator.userAgent.indexOf("miniProgram") > -1;
 
+        this.$nextTick(() => {
+            this.listenToEnd();
+        });
     },
-    resetTab() {
-      this.list = [];
-      this.page = 0;
-      this.pageSize = 10;
-      this.loading = true;
+    async asyncData({
+        ...params
+    }) {
+        let dealDataObj = new PersonalSeoData(params);
+        let ans = await dealDataObj.dealData();
 
-      this.fetchData();
+        return {
+            ...ans
+        };
+    },
+    destroy: function () {
+        window.onscroll = null;
     },
-    async fetchData() {
-      this.loading = true;
+    methods: {
+        resetTab() {
+            this.list = [];
+            this.page = 0;
+            this.isMore = true;
+            this.pageSize = 10;
+            this.pageLoading = false;
 
-      await new Promise(resolve => {
-        setTimeout(resolve, 2000);
-      });
+            this.fetchData();
+        },
+        async fetchData() {
+            if (this.pageLoading || !this.isMore) return;
+            this.pageLoading = true;
 
-      let result = new Array(10);
+            let page = this.page + 1;
 
-      this.list.push(...result);
+            let tabSelected = this.tabSelected;
+            let uid = this.personUid;
+            let res;
+            let list = [];
+            if (tabSelected == 1) {
+                res = await this.$axios.post("/uapi/dynamic/get_dynamic_list_my", {
+                    to_uid: uid,
+                    page: page,
+                    pagesize: this.pageSize
+                });
+                list = res.data.data.list;
+            } else if (tabSelected == 2) {
+                res = await this.$axios.post("/uapi/news/index/list", {
+                    uid: uid,
+                    page: page,
+                    pagesize: this.pageSize
+                });
+                list = res.data.data.list;
+            } else if (tabSelected == 3) {
+                res = await this.$axios.post("/uapi/goods/video/list", {
+                    to_uid: uid,
+                    page: 1,
+                    pagesize: 1
+                });
+                list = res.data.data.list;
+            }
 
-      this.loading = false;
-    },
-    listenToEnd() {
-      let that = this;
-      window.onscroll = function() {
-        var scrollTop =
-          document.documentElement.scrollTop || document.body.scrollTop;
-        var windowHeight =
-          document.documentElement.clientHeight || document.body.clientHeight;
-        var scrollHeight =
-          document.documentElement.scrollHeight || document.body.scrollHeight;
+            if (Number(res.data.status) === 1) {
+                setTimeout(() => {
+                    this.pageLoading = false;
+                }, 100);
+                this.page = page;
+                this.list.push(...list);
+                this.isMore = list.length < this.pageSize ? false : true;
+            } else if (Number(res.status) === 40001) {
+                this.isExist = false;
+            }
+        },
+        listenToEnd() {
+            let that = this;
+            window.onscroll = function () {
+                var scrollTop =
+                    document.documentElement.scrollTop || document.body.scrollTop;
+                var windowHeight =
+                    document.documentElement.clientHeight || document.body.clientHeight;
+                var scrollHeight =
+                    document.documentElement.scrollHeight || document.body.scrollHeight;
 
-        if (scrollHeight - scrollTop - windowHeight < 400) {
-          that.fetchData();
+                if (scrollHeight - scrollTop - windowHeight < 400) {
+                    that.fetchData();
+                }
+            };
+        },
+        linkToThirdParty(content, type) {
+            let link = "";
+            switch (type) {
+                case "github_name":
+                    link = `https://github.com/${content}`;
+                    break;
+                case "gitee_name":
+                    link = `https://gitee.com/${content}`;
+                    break;
+                case "csdn_name":
+                    link = `https://blog.csdn.net/${content}`;
+                    break;
+                case "wechat_name":
+                    // link = `https://blog.csdn.net/${content}`;
+                    break;
+                case "juejin_name":
+                    link = "";
+                    break;
+            }
+
+            link && window.open(link, "view_window");
+        },
+        toggleFollow() {
+            if (this.isFollowing) {
+                this.unFollow();
+            } else {
+                this.follow();
+            }
+        },
+        async follow() {
+            if (this.pageLoading) return;
+            this.pageLoading = true;
+            let res = await this.$axios.$post('/uapi/dynamic/add_followers', {
+                to_uid: this.personUid
+            });
+            this.pageLoading = false;
+            if (Number(res.status) === 1) {
+                this.isFollowing = true;
+                this.personalUserInfo.followers_my++;
+            }
+
+        },
+        async unFollow() {
+            if (this.pageLoading) return;
+            this.pageLoading = true;
+            let res = await this.$axios.$post('/uapi/dynamic/del_followers', {
+                to_uid: this.personUid
+            });
+            this.pageLoading = false;
+            if (Number(res.status) === 1) {
+                this.isFollowing = false;
+                this.personalUserInfo.followers_my--;
+            }
         }
-      };
     }
-  }
 };
 </script>
 

+ 211 - 0
pages/frontend/personal/personalData.js

@@ -0,0 +1,211 @@
+export default class PersonalData {
+    constructor({ $axios, req, app, redirect, error }) {
+        this.$axios = $axios
+        this.req = req
+        this.app = app
+        this.redirect = redirect
+        this.error = error
+        this.from = ''
+        this.isExist = true
+
+        this.pagesize = 10
+    }
+
+    async dealData() {
+        let {
+            name,
+            path,
+            params,
+            fullPath,
+            query
+        } = this.app.context.route
+
+
+        let [
+            personalUserInfo,
+            dynamicData,
+            articleCount,
+            courseCount,
+            adList,
+            isFollowing
+        ] = await Promise.all([
+            this._getPersonalUserInfo(),
+            this._getDynamicCount(),
+            this._getArticleCount(),
+            this._getCourseCount(),
+            this._getAdvert(),
+            this._getFollowStatus()
+        ])
+        return {
+            isExist: this.isExist,
+            mobile: this.app.$deviceType.isMobile(),
+            // head: this.dealThisMeta(),
+            personalUserInfo,
+            dynamicCount:dynamicData.dynamicCount,
+            articleCount,
+            courseCount,
+            list:dynamicData.dynamicList,
+            adList,
+            isFollowing
+        }
+    }
+
+
+    // 获取开发者个人信息
+    async _getPersonalUserInfo() {
+        let {
+            name,
+            path,
+            params,
+            fullPath,
+            query
+        } = this.app.context.route
+
+        let res = await this.$axios.post('/uapi/user/info/action/other', {
+            uid: params.uid
+        })
+        let personalUserInfo = {}
+
+        if (Number(res.data.status) === 1) {
+            personalUserInfo = {
+                ...res.data.data
+            }
+
+        } else if (Number(res.status) === 40001) {
+            this.isExist = false
+        }
+
+        return personalUserInfo
+    }
+
+
+    async _getDynamicCount(){
+        let {
+            name,
+            path,
+            params,
+            fullPath,
+            query
+        } = this.app.context.route
+        let uid = params.uid
+
+        let res = await this.$axios.post('/uapi/dynamic/get_dynamic_list_my', {
+            to_uid: params.uid,
+            page:1,
+            pagesize:10
+        })
+        
+     
+        let count = 0
+        let dynamicList = []
+        if (Number(res.data.status) === 1) {
+            count = res.data.data.user.dynamic_num
+            dynamicList = res.data.data.list
+        } else if (Number(res.status) === 40001) {
+            this.isExist = false
+        }
+
+        return {
+            dynamicList,
+            dynamicCount:count
+        }
+
+    }
+    async _getArticleCount(){
+        let {
+            name,
+            path,
+            params,
+            fullPath,
+            query
+        } = this.app.context.route
+        let uid = params.uid
+
+        let res = await this.$axios.post('/uapi/news/index/list', {
+            uid: params.uid,
+            page:1,
+            pagesize:1
+        })
+        let count = 0
+        if (Number(res.data.status) === 1) {
+            count = res.data.data.total
+
+        } else if (Number(res.status) === 40001) {
+            this.isExist = false
+        }
+
+        return count
+    }
+    async _getCourseCount(){
+        let {
+            name,
+            path,
+            params,
+            fullPath,
+            query
+        } = this.app.context.route
+        let uid = params.uid
+
+        let res = await this.$axios.post('/uapi/goods/video/list', {
+            to_uid: params.uid,
+            page:1,
+            pagesize:1
+        })
+        let count = 0
+        if (Number(res.data.status) === 1) {
+            count = res.data.data.total
+
+        } else if (Number(res.status) === 40001) {
+            this.isExist = false
+        }
+
+        return count
+    }
+
+    // 获取广告位
+    async _getAdvert() {
+        let res = await this.$axios.post('/uapi/pub/adInfo', {
+            position: 'personal'
+        })
+        let adList = []
+
+        if (Number(res.data.status) === 1) {
+            adList = {
+                ...res.data.data.list
+            }
+
+        } else if (Number(res.status) === 40001) {
+            this.isExist = false
+        }
+
+        return adList
+    }
+
+    // 获取当前关注状态
+    async _getFollowStatus() {
+        let {
+            name,
+            path,
+            params,
+            fullPath,
+            query
+        } = this.app.context.route
+        let uid = params.uid
+        let res = await this.$axios.post('/uapi/dynamic/check_followers', {
+            to_uid: uid
+        })
+        let isFollowing = false
+
+        if (Number(res.data.status) === 1) {
+            if(res.data.data.result == 1){
+                isFollowing = true
+            }
+        } else if (Number(res.status) === 40001) {
+            this.isExist = false
+        }
+
+        return isFollowing
+    }
+
+
+}

+ 1 - 1
plugins/seoRouter.js

@@ -193,7 +193,7 @@ const extendRoutes = (routes, resolve) => {
       },
       {
         name: "PersonalIndex",
-        path: '/frontend/personal/:id',
+        path: '/u/:uid',
         component: resolve(__dirname, '../pages/frontend/personal/index.vue')
       }
     ],