Przeglądaj źródła

研报5.1 还剩一小部分

hbchen 2 lat temu
rodzic
commit
528218747a

BIN
src/assets/audio-waveform1.png


BIN
src/assets/audio-waveform2.png


BIN
src/assets/icon-question-ask.png


BIN
src/assets/icon-question-askTip.png


BIN
src/assets/recordpause.png


BIN
src/assets/recordplay.png


+ 1 - 1
src/layout/Index.vue

@@ -19,7 +19,7 @@ import LoginPop from '@/components/LoginPop.vue'
         <el-aside width="160px">
           <Aside />
         </el-aside>
-        <el-main style="padding-left:180px">
+        <el-main style="padding-left:180px;overflow:visible"> <!-- 使用粘性布局 需要overflow设置为visible 否则粘性布局会失效 -->
           <div class="page-container">
           <router-view v-slot="{ Component }">
               <keep-alive>

+ 2 - 0
src/router/index.js

@@ -272,6 +272,8 @@ const routes=[
           component: () => import("@/views/question/MyList.vue"),
           meta: {
             title: "我的问答",
+            keepAlive:true,
+            isRoot:false
           }
         }
       ]

+ 548 - 162
src/views/question/List.vue

@@ -1,218 +1,604 @@
 <script setup>
 import{
-  apiOptiongroupList
+  apiOptiongroupList,
+  apiQuestionList,
+  apipubAsk
 }from '@/api/question'
-import{ref} from "vue"
-let optionList = ref([]) //分组列表
+import{ref,reactive} from "vue"
+import {onBeforeRouteLeave} from "vue-router"
+import { useElementSize } from '@vueuse/core'
+import {ElMessage} from "element-plus"
+import moment from 'moment';
+
+
+moment.locale('zh-cn');
+//监听列表页面版心宽度
+const listPageEl=ref('')
+const {width}=useElementSize(listPageEl)
+
+const askForm = ref(null)
+
+let question = reactive({
+  // 问题列表
+  list:[],
+  page_index:1,
+  page_size:20,
+  //分组列表
+  optionList:[],
+  // 二级分组列表数据
+  secondGroupList:[],
+  // 一级分组Id
+  selectedGroupId_first :0,
+  // 二级分组Id
+  selectedGroupId_second:0,
+  // 正在播放的音频问题索引,没有为-1
+  audioPlayingIndex:-1,
+  // 正在播放的音频问题,没有为-1
+  audioPlayingItem:null,
+  // 是否加载完成
+  isFinish:false,
+  // 数据是否全部加载完成
+  isTotalData:false,
+  // 是否在加载中
+  isLoading:false,
+  noAuthorData:{},
+  // 权限状态
+  Author:0,
+  // 显示/隐藏 提问弹窗
+  showAskDia:false,
+  askForm:{
+    problemDescription:''
+  }
+})  
+
+let audio = ref(null)
+let timer = null
+
+
 // 获取分组列表
 const getOptionList =async ()=>{
   const res = await apiOptiongroupList()
   if(res.code===200){
-   optionList.value = res.data||[]
+   question.optionList = res.data||[]
+    // 默认第一个一级分组
+    question.selectedGroupId_first = question.optionList[0].research_group_id
+    // 默认第一个一级分组的第一个二级分组
+    question.selectedGroupId_second = question.optionList[0].children[0].research_group_id
+    question.secondGroupList = question.optionList[0].children
+    getQuestionList()
+  }else if(res.code==403){
+    question.isFinish=true
+    question.noAuthorData = res.data
+  }
+}
+// 请求已回答列表
+const getQuestionList=()=>{
+  question.isLoading = true
+  let params = {
+    group_id:question.selectedGroupId_second,
+    reply_status:3,
+    page_index:question.page_index,
+    page_size:question.page_size,
+  }
+  apiQuestionList(params).then(res=>{
+    question.isFinish = true
+    if(res.code == 200){
+      let arr =res.data || []
+      if(params.page_index ==1){
+        if(arr.length==0) return 
+        question.list = arr
+      }else{
+        if(arr.length==0){
+          question.isTotalData = true
+          return 
+        }
+        question.list = [...question.list,...arr]
+      }
+      for (const item of question.list) {
+        if(!item.audio_status){
+          item.audio_status={
+            isPlay:false,
+            // 已播放时间
+            playedTime:0,
+            // 总共的时长
+            audioTime:item.audio_list[0].audio_play_seconds*1000,
+            // 是否在加载中
+            loading:false
+          }
+        } 
+      }
+    }
+    console.log(question.list);
+  })
+  .finally(()=>{
+    question.isLoading = false
+  })
+}
+
+const loadingMore = ()=>{
+  question.page_index++
+  getQuestionList()
+}
+
+// 切换一级分类
+const ChangeFirstGroup = (item)=>{
+
+  question.secondGroupList = item.children
+  question.selectedGroupId_first = item.research_group_id
+  ChangeSecGroup(question.secondGroupList[0])
+}
+// 切换二级分类
+const ChangeSecGroup = (item)=>{
+  question.list=[]
+  question.page_index=1
+  question.isFinish = false
+  question.isTotalData = false
+  question.isLoading = false
+  question.selectedGroupId_second = item.research_group_id
+  getQuestionList()
+}
+// 提问问题
+const askQuestion = ()=>{
+  if(askForm.value){
+    // 重置表单
+   askForm.value.resetFields()
+  }
+  question.showAskDia = true
+  
+}
+
+// 提交问题
+const submit = (formEl)=>{
+  formEl.validate((valid)=>{
+    if(valid){
+      apipubAsk({question_content:question.askForm.problemDescription}).then(res=>{
+        ElMessage({
+          type:'success',
+          message:'问题提交成功'
+        })
+        question.showAskDia = false
+      })
+    }
+  })
+}
+
+const audioPlay = (item,index)=>{
+  if(item.audio_status.isPlay){
+    pause(item,index)
+  }else{
+    play(item,index)
+  }
+}
+
+
+const pause=(item,index,type='pause')=>{
+    audio.value[index].pause()
+    clearInterval(timer)
+    if(type == 'end'){
+      audio.value[index].currentTime = 0
+      item.audio_status.playedTime=0
+    }
+    item.audio_status.isPlay = false
+    question.audioPlayingIndex=-1
+    question.audioPlayingItem = null
+    item.audio_status.loading = false
+}
+
+const play=(item,index)=>{
+  if(audio.value[index].readyState!=4){
+    item.audio_status.loading=true
+    return 
+  }
+  if( question.audioPlayingIndex!= -1 ){
+    console.log(question.audioPlayingIndex);
+    pause(question.audioPlayingItem,question.audioPlayingIndex,'end')
+  }
+  audio.value[index].play()
+  question.audioPlayingIndex = index
+  question.audioPlayingItem = item
+  timer = setInterval(()=>{
+    if(audio.value[index].ended){
+      item.audio_status.playedTime = 0
+      item.audio_status.isPlay = false
+      question.audioPlayingIndex=-1
+      question.audioPlayingItem = null
+      clearInterval(timer)
+      return 
+    }
+    item.audio_status.playedTime += 1000
+  },1000)
+  item.audio_status.isPlay = true
+  item.audio_status.loading = false
+}
+
+const audioWaiting = (item,index)=>{
+  console.log("waiting");
+  item.audio_status.loading = true
+}
+
+const audioCanPlay = (item,index)=>{
+  item.audio_status.loading = false
+  console.log("canplay");
+  if(!audio.value[index].played){
+    console.log('rttt');
+    play(item,index)
   }
 }
+
+
 getOptionList()
+onBeforeRouteLeave(()=>{
+  console.log('onBeforeRouteLeave','离开路由');
+  if( question.audioPlayingIndex!= -1 ){
+    console.log(question.audioPlayingIndex);
+    pause(question.audioPlayingItem,question.audioPlayingIndex,'end')
+  }
+})
+
 </script>
 
 <template>
-  <div class="question-wrap">
-      <!-- 筛选框 -->
-      <div class="top-nav-wrap">
-        <div class="flex first-nav">
-          <div class="nav-move-box move-left"></div>
-          <div class="nav-move-box move-right"></div>
-          <div 
-            :class="['item', item.research_group_name == selectFirstType && 'item-active']" 
-            v-for="item in optionList" 
-            :key="item.research_group_id" 
-          >{{ item.research_group_name }}</div>
-        </div>
-       <!--  <div class="sub-nav">
-            <span 
-              :class="['sub-item', item.chart_permission_id == selectSubType && 'sub-active']" 
-              v-for="item in subTypeList.slice(0,6)" 
-              :key="item.chart_permission_id" 
-              @click="clickSubType(item)"
-            >{{ item.chart_permission_name }}</span>
-            <el-popover
-              :width="500"
-              trigger="click"
-            >
-              <template #reference>
-                <img v-if="subTypeList.length>6" style="width:16px;transform: rotate(90deg);cursor: pointer" src="@/assets/icon-more.png" alt="">
-              </template>
-              <template #default>
-                <div class="flex top-nav-filter-box">
-                  <div 
-                      :class="['item',item.chart_permission_id == selectSubType&&'active']" 
-                      v-for="item in subTypeList.slice(6)" 
-                      :key="item.chart_permission_id"
-                      @click="clickSubType(item)"
-                  >{{item.chart_permission_name}}</div>
-                </div>
-              </template>
-            </el-popover>
-        </div> -->
-      </div>
-      <div class="question-list">
-        <div class="question-item">
-          <div class="question-info">
-            <span class="label">苯乙烯</span>
-            疫情下全球苯乙烯市场有什么动荡?
-          </div>
-          <div class="question-time">
-            提问时间:2022.02.02
+
+  <div class="question-list-container" ref="listPageEl">
+      <div class="top-nav-box" :style="{width:width+'px'}">
+          <div class="first-nav-box">
+              <span 
+                  v-for="item in question.optionList" 
+                  :key="item.research_group_id"
+                  :class="item.research_group_id==question.selectedGroupId_first?'active':''"
+                  @click="ChangeFirstGroup(item)"
+              >{{item.research_group_name}}</span>
+              <span class="ask-icon" @click="askQuestion"><img src="@/assets/icon-question-ask.png" /> 我要提问  </span>
           </div>
-          <div class="question-audio">
-            <div class="audio-icon">播放</div>
-            <div class="audio-pic"></div>
-            <div class="audio-time">02:30</div>
+          <div class="sec-nav-box">
+              <span
+                  :class="['sec-item',item.research_group_id==question.selectedGroupId_second?'active':'']"
+                  v-for="item in question.secondGroupList.slice(0,6)"
+                  :key="item.research_group_id"
+                  @click="ChangeSecGroup(item)"
+              >{{item.research_group_name}}</span>
+              <el-popover
+                  :width="560"
+                  trigger="click"
+              >
+                  <template #reference>
+                      <img v-if="question.secondGroupList.length>6" style="width:16px;transform: rotate(90deg);cursor: pointer" src="@/assets/icon-more.png" alt="">
+                  </template>
+                  <template #default>
+                      <div class="flex top-nav-filter-box">
+                          <div 
+                              :class="['item',item.research_group_id == question.selectedGroupId_second&&'active']" 
+                              v-for="item in question.secondGroupList.slice(6)" 
+                              :key="item.research_group_id"
+                              @click="ChangeSecGroup(item)"
+                          >{{item.research_group_name}}</div>
+                      </div>
+                  </template>
+              </el-popover>
           </div>
-
-        </div>
-        <div class="question-item">
+      </div>
+      <div class="question-noData" v-show="question.list.length==0 && question.isFinish">
+        <img :src="$store.state.globalImgUrls.activityNoAuth" alt="没有数据">
+        <span>暂无数据</span>
+      </div>
+      <div class="question-list" v-show = "question.list.length>0 && question.isFinish">
+        <div class="question-item" v-for="(item,index) in question.list" :key="item.community_question_id">
           <div class="question-info">
-            <span class="label">苯乙烯</span>
-            疫情下全球苯乙烯市场有什么动荡?
+            <div class="label">{{item.research_group_second_name}}</div>
+            {{item.question_content}}
           </div>
           <div class="question-time">
-            提问时间:2022.02.02
+            提问时间:{{moment(item.create_time).format('YYYY.MM.DD')}}
           </div>
           <div class="question-audio">
-            <div class="audio-icon">播放</div>
-            <div class="audio-pic"></div>
-            <div class="audio-time">02:30</div>
+            <audio :autoplay="false" :loop="false" preload ref="audio"
+            @waiting="audioWaiting(item,index)" @canplay="audioCanPlay(item,index)">
+              <source :src="item.audio_list[0].audio_url" type="audio/mp3"  />
+              <p>你的浏览器不支持 HTML5 音频,请直接下载<a :href="item.audio_list[0].audio_url">音频文件</a>。</p>
+            </audio>
+            <div class="audio-icon" @click="audioPlay(item,index)" v-if="!item.audio_status.loading">
+              <img src="@/assets/recordplay.png" alt="播放" v-show="!item.audio_status.isPlay" />
+              <img src="@/assets/recordpause.png" alt="暂停" v-show="item.audio_status.isPlay" />
+            </div>
+            <div class="audio-icon loading-icon" @click="pause(item,index)" v-else>
+              <img class="load-img" src="@/assets/loading.png" alt="加载中">
+            </div>
+            <div class="audio-pic">
+              <img src="@/assets/audio-waveform1.png">
+              <img src="@/assets/audio-waveform2.png">
+            </div>
+            <div class="audio-time">{{moment((item.audio_status.audioTime - item.audio_status.playedTime)).format('mm:ss')}}</div>
           </div>
-
+        </div>
+        <div class="bottom-tip-contain">
+          <div class="bottom-tip-loadMore" v-show="!question.isTotalData && !question.isLoading" @click="loadingMore">加载更多</div>
+          <div class="loading-text" v-show="question.isLoading">加载中······</div>
+          <div class="bottom-tip-noMore" v-show="question.isTotalData && !question.isLoading">没有更多了~</div>
         </div>
       </div>
+      <el-dialog title="提问详情" v-model="question.showAskDia" :close-on-click-modal="false" draggable 
+      :width="600" >
+        <el-form :model="question.askForm" ref="askForm" class="ask-form">
+          <div class="ask-label">
+            问题描述
+            <el-tooltip content="实际发布的问题会以提炼出的精简内容为准" placement="bottom-start" trigger="click">
+              <img src="@/assets/icon-question-askTip.png" alt="提示" />
+            </el-tooltip>
+          </div>
+          <el-form-item prop="problemDescription" :rules="{required:true,message:'提问内容不能为空',trigger:'blur'}">
+            <el-input type="textarea" v-model.trim="question.askForm.problemDescription" placeholder="点击输入提问"
+            resize="none" maxlength="50" rows="7"></el-input>
+          </el-form-item>
+          <p>剩余可输入字数:{{50 - question.askForm.problemDescription.length}} 字</p>
+          <div class="askForm-button">
+            <el-button @click="question.showAskDia = false">取消</el-button>
+            <el-button type="warning" @click="submit(askForm)">发布</el-button>
+          </div>
+        </el-form>
+      </el-dialog>
   </div>
 </template>
 
+
 <style scoped lang="scss">
-.question-wrap{
+.top-nav-filter-box{
+    flex-wrap: wrap;
+    .item{
+        margin: 5px 10px;
+        width: 113px;
+        height: 40px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        background-color: #f6f6f6;
+        border-radius: 4px;
+        font-size: 16px;
+        cursor: pointer;
+        :hover{
+            color: #fff;
+            background-color: #F3A52F;
+        }
+    }
+    .active{
+        color: #fff;
+        background-color: #F3A52F;
+    }
+}
+.question-list-container{
   border-left: 1px solid #F2F2F2;
   border-right: 1px solid #F2F2F2;
-  .top-nav-wrap {
-      position: fixed;
-      top: 60px;
-      z-index: 99;
-      background-color: #fff;
-      padding-top: 30px;
-      padding-bottom: 12px;
-      width: 100%;
-      box-shadow: 0px 4px 8px 1px rgba(0,0,0,0.0400);
-      .first-nav {
-        width: calc(100vw - 500px);
-        overflow-x: auto;
-        overflow-y: hidden;
-        position: relative;
-        &::-webkit-scrollbar{
-          display: none;
+  .top-nav-box{
+    padding: 30px 30px 12px 30px;
+    background: #FFFFFF;
+    box-shadow: 0px 4px 8px 1px rgba(0, 0, 0, 0.04);
+    position: sticky;
+    top: 60px;
+    width: 100%;
+    max-width: 1240px;
+    z-index: 10;
+    .first-nav-box{
+        span{
+            display: inline-flex;
+            align-items:center;
+            justify-content:center;
+            width: 140px;
+            line-height: 40px;
+            text-align: center;
+            border-radius: 20px;
+            background-color: #F6F6F6;
+            font-size: 16px;
+            margin-right: 30px;
+            cursor: pointer;
+            margin-bottom:10px;
         }
-        .item {
-          width: 140px;
-          height: 40px;
-          flex-shrink: 0;
-          background: #F6F6F6;
+        .ask-icon{
+          display:inline-flex;
+          background: #F3A52F;
+          border: 1px solid #F3A52F;
+          box-shadow: 0px 6px 7px #FFF7EB;
           border-radius: 20px;
-          text-align: center;
-          line-height: 40px;
+          font-family: 'PingFang SC';
+          font-style: normal;
+          font-weight: 400;
           font-size: 16px;
-          margin-right: 30px;
-          cursor: pointer;
-          &:hover {
-            background: #FFFBF5;
+          color: #FFFFFF;
+          img{
+            margin-right:6px;
+          }
+        }
+        .active{
+            background-color: #FFFBF5;
+            box-shadow: 0px 6px 7px 1px #FFF7EB;
             color: #F3A52F;
             border: 1px solid #F3A52F;
-            box-shadow: 0px 6px 7px 1px #FFF7EB;
-          }
         }
-        .item-active {
-          background: #FFFBF5;
+    }
+    .sec-nav-box{
+        margin-top: 30px;
+        .sec-item{
+            color: #666;
+            margin-right: 30px;
+            cursor: pointer;
+            display: inline-block;
+        }
+        .active{
+            color: #F3A52F;
+        }
+    }
+  }
+  .question-noData{
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+    justify-content: center;
+    margin-top: 50px;
+    img{
+        height: 360px;
+    }
+    span{
+        margin-top: 30px;
+        font-family: 'PingFang SC';
+        font-style: normal;
+        font-weight: 400;
+        font-size: 16px;
+        color: #333333;
+    }
+  }
+  .question-list{
+    .question-item{
+      padding: 32px 30px;
+      border: 1px solid #F2F2F2;
+      border-top: 1px solid transparent ;
+      box-sizing: border-box;
+      .question-info{
+        display: flex;
+        align-items: center;
+        font-size: 16px;
+        font-family: PingFang SC-Medium, PingFang SC;
+        font-weight: 500;
+        color: #333333;
+        margin-bottom: 16px;
+        .label{
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          min-width: 68px;
+          background: #333333;
+          border-radius: 21px 21px 21px 21px;
+          height: 24px;
+          padding: 0 12px;
+          font-size: 12px;
+          font-family: PingFang SC-Medium, PingFang SC;
+          font-weight: 500;
           color: #F3A52F;
-          border: 1px solid #F3A52F;
-          box-shadow: 0px 6px 7px 1px #FFF7EB;
+          margin-right: 14px;
         }
-        .see-more{
-          height: 20px;
-          flex-shrink: 0;
-          color: #f3a52f;
-          font-size: 16px;
-          position: relative;
-          top: 10px;
-          margin-left: 30px;
+      }
+      .question-time{
+        font-size: 16px;
+        font-family: PingFang SC-Regular, PingFang SC;
+        font-weight: 400;
+        color: #666666;
+        margin-bottom: 24px;
+      }
+      .question-audio{
+        width: 443px;
+        height: 46px;
+        background-color: #F3A52F;
+        border: 1px solid #F3A52F;
+        border-radius: 23px;
+        display: flex;
+        align-items: center;
+        padding: 0 54px 0 27px;
+        .audio-icon{
           cursor: pointer;
-          z-index: 1;
-          &::after{
-            content: '';
-            display: inline-block;
+          img{
             width: 16px;
-            height: 16px;
-            background-image: url('../../assets/icon-more.png');
-            background-size: cover;
-            position: relative;
-            top: 2px;
-            left: 5px;
           }
-        }
-        @media screen and (max-width: 1350px){
-          .item{
-            width: 90px;
-            height: 30px;
-            line-height: 30px;
-            margin-right: 15px;
-            font-size: 14px;
+          .load-img{
+            width: 20px;
+            animation: circle 0.5s linear infinite;
           }
-          .see-more{
-            font-size: 14px;
-            margin-left: 10px;
-            top: 5px;
+          @keyframes circle {
+            0%{
+                transform: rotateZ(0);
+            }
+            100%{
+                transform: rotateZ(360deg);
+            }
           }
         }
-      }
-
-      .sub-nav {
-        margin-top: 30px;
-        overflow-y: hidden;
-        .sub-item {
-          flex-shrink: 0;
-          margin-right: 30px;
+        .audio-pic{
+          margin: 0 27px 0 27px;
+        }
+        .audio-time{
           font-size: 16px;
-          color: #666666;
-          cursor: pointer;
+          font-family: PingFang SC-Regular, PingFang SC;
+          font-weight: 400;
+          color: #FFFFFF;
+        }
+      }
+    }
+    .bottom-tip-contain{
+        .bottom-tip-loadMore{
+            margin: 20px auto;
+            width: 112px;
+            height: 30px;
+            background: #FFFFFF;
+            border-radius: 20px;
+            border: 1px solid #F3A52F;
+            color: #F3A52F;
+            font-size: 14px;
+            text-align: center;
+            line-height: 30px;
+            cursor: pointer;
         }
-        .sub-active {
+        .loading-text{
+            margin: 20px auto;
+            text-align: center;
+            color: #666;
+            height: 30px;
+        }
+        .bottom-tip-noMore{
+          text-align: center;
           color: #F3A52F;
         }
+    }
+  }
+  .ask-form{
+    .ask-label{
+      margin-bottom: 12px;
+      display: flex;
+      align-items: center;
+      img{
+        margin-left: 6px;
       }
-      
     }
-  .question-list{
-    margin-top: 130px;
-    .question-item{
-      padding:25px 30px;
-      border-bottom: 1px solid #F2F2F2;
-      .question-info{
-        display: flex;
+    p{
+      text-align: right;
+      margin-top: 10px;
+      color: #999999;
+      font-family: 'PingFang SC';
+      font-style: normal;
+      font-weight: 400;
+      font-size: 16px;
+    }
+    .askForm-button{
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      margin-top: 48px;
+      margin-bottom: 10px;
+      button{
+        box-sizing: border-box;
+        background: #F3A52F;
+        border-radius: 41px;
+        width: 160px;
+        height: 40px;
+        color: #FFFFFF;
+        font-family: 'PingFang SC';
+        font-style: normal;
+        font-weight: 500;
+        font-size: 16px;
+        margin-left: 0;
+      }
+      button:first-child{
+        margin-right: 60px;
+        border: 1px solid #CCCCCC;
+        background-color: transparent;
         color: #333333;
-        font-weight: 600;
-        span.label{
-          display: inline-block;
-          width:68px;
-          height:24px;
-          line-height: 24px;
-          text-align: center;
-          background-color:#333333 ;
-          color:#F3A52F;
-          font-size: 12px;
-          font-weight: normal;
-          margin-right:14px;
-          border-radius: 34px;
-        }
       }
     }
   }
 }
+// element 样式重写
+:deep(.el-dialog__title){
+  color: #303133;
+  font-family: 'Noto Sans SC';
+  font-style: normal;
+  font-weight: 400;
+  font-size: 18px;
+}
+
 </style>
 

+ 472 - 3
src/views/question/MyList.vue

@@ -1,12 +1,481 @@
 <script setup>
+import{
+  apiQuestionList,
+  apiBarTotal
+}from '@/api/question'
+import{ref,reactive} from "vue"
+import {useStore} from 'vuex'
+import {onBeforeRouteLeave} from "vue-router"
+import { useElementSize } from '@vueuse/core'
+import {ElMessage} from "element-plus"
+import moment from 'moment';
+
+const store = useStore()
+// await store.dispatch("getUserInfo"); //获取个人信息
+
+moment.locale('zh-cn');
+//监听列表页面版心宽度
+const listPageEl=ref('')
+const {width}=useElementSize(listPageEl)
+
+const askForm = ref(null)
+
+let question = reactive({
+  // 问题列表
+  list:[],
+  // 顶部导航
+  barList:[],
+  page_index:1,
+  page_size:20,
+  // 用于 顶部导航栏
+  selectKey:store.state.userInfo.is_inner==1?'Wait':'Replied',
+  // 研究员 + 内部人员
+  isUserResearcher:store.state.userInfo.is_inner==1&&store.state.userInfo.is_researcher==1 ? true:false,
+  // 问题列表状态
+  questionStatus:0,
+  //分组列表
+  optionList:[],
+  // 录音索引
+  audioIndex:0,
+  // 正在播放的音频问题索引,没有为-1
+  audioPlayingIndex:-1,
+  // 正在播放的音频问题,没有为-1
+  audioPlayingItem:null,
+  // 是否加载完成
+  isFinish:false,
+  // 数据是否全部加载完成
+  isTotalData:false,
+  // 是否在加载中
+  isLoading:false
+})  
+
+let audio = ref(null)
+let timer = null
+
+// 顶部导航栏
+const getBarList = async ()=>{
+      const res = await apiBarTotal();
+      if (res.code !== 200) return;
+      const { replied, wait, total,distribute } = res.data;
+      //客户: 已回答 未回答 全部
+      const customBar = [
+        {
+          label: "已回答",
+          key: "Replied",
+          num: replied,
+        },
+        {
+          label: "未回答",
+          key: "Wait",
+          num: wait,
+        },
+        {
+          label: "全部",
+          key: "Total",
+          num: total,
+        },
+      ];
+      //研究员: 待回答 未回答 已回答 全部
+      const researBar = [
+        {
+          label: "待回答",
+          key: "Distribute",
+          num: distribute,
+        },
+        {
+          label:'未回答',
+          key:'Wait',
+          num:wait,
+        },
+        {
+          label: "已回答",
+          key: "Replied",
+          num: replied,
+        },
+        {
+          label: "全部",
+          key: "Total",
+          num: total,
+        },
+      ];
+      question.barList = question.isUserResearcher ? researBar : customBar;
+      getQuestionList()
+    }
+
+const changeTopTar = (key)=>{
+  question.selectKey = key
+  question.list=[]
+  question.page_index=1
+  question.isFinish = false
+  question.isTotalData = false
+  question.isLoading = false
+  question.audioIndex=0
+  getQuestionList()
+}
+
+// 请求回答列表
+const getQuestionList=()=>{
+  question.isLoading = true
+  const reply_status = { Wait: 2, Replied: 3, Total: 0 ,Distribute:4};
+  let params = {
+    reply_status:reply_status[question.selectKey],
+    page_index:question.page_index,
+    page_size:question.page_size,
+    only_mine:1
+  }
+  question.questionStatus = params.reply_status
+  apiQuestionList(params).then(res=>{
+    question.isFinish = true
+    if(res.code == 200){
+      let arr =res.data || []
+      if(params.page_index ==1){
+        if(arr.length==0) return 
+        question.list = arr
+      }else{
+        if(arr.length==0){
+          question.isTotalData = true
+          return 
+        }
+        question.list = [...question.list,...arr]
+      }
+      for (const item of question.list) {
+        if(!item.audio_status && item.reply_status==3){
+          item.audio_status={
+            isPlay:false,
+            // 已播放时间
+            playedTime:0,
+            // 总共的时长
+            audioTime:item.audio_list[0].audio_play_seconds*1000,
+            // 是否在加载中
+            loading:false,
+            audioIndex:question.audioIndex
+          }
+          question.audioIndex++
+        }
+      }
+    }
+    console.log(question.list);
+  })
+  .finally(()=>{
+    question.isLoading = false
+  })
+}
+
+const loadingMore = ()=>{
+  question.page_index++
+  getQuestionList()
+}
+
+const toDetail = (item)=>{
+    // 未回答的不进行操作
+  if(question.questionStatus == 2) return 
+    //reply_status:1-待分配 2-待回答 3-已回答
+    if (question.isUserResearcher && item.reply_status === 2 && item.replier_user_id == store.state.userInfo.user_id) {
+    // 是研究员 && 问题是待回答 && 回答者是我
+      console.log('detail');
+    }
+}
+
+const audioPlay = (item)=>{
+  let index = item.audio_status.audioIndex
+  if(item.audio_status.isPlay){
+    pause(item,index)
+  }else{
+    play(item,index)
+  }
+}
+
+
+const pause=(item,index,type='pause')=>{
+    audio.value[index].pause()
+    clearInterval(timer)
+    if(type == 'end'){
+      audio.value[index].currentTime = 0
+      item.audio_status.playedTime=0
+    }
+    item.audio_status.isPlay = false
+    question.audioPlayingIndex=-1
+    question.audioPlayingItem = null
+    item.audio_status.loading = false
+}
+
+const play=(item,index)=>{
+  console.log(index);
+  if(audio.value[index].readyState!=4){
+    item.audio_status.loading=true
+    return 
+  }
+  if( question.audioPlayingIndex!= -1 ){
+    console.log(question.audioPlayingIndex);
+    pause(question.audioPlayingItem,question.audioPlayingIndex,'end')
+  }
+  audio.value[index].play()
+  question.audioPlayingIndex = index
+  question.audioPlayingItem = item
+  timer = setInterval(()=>{
+    if(audio.value[index].ended){
+      item.audio_status.playedTime = 0
+      item.audio_status.isPlay = false
+      question.audioPlayingIndex=-1
+      question.audioPlayingItem = null
+      clearInterval(timer)
+      return 
+    }
+    item.audio_status.playedTime += 1000
+  },1000)
+  item.audio_status.isPlay = true
+  item.audio_status.loading = false
+}
+
+const audioWaiting = (item)=>{
+  console.log("waiting");
+  item.audio_status.loading = true
+}
+
+const audioCanPlay = (item)=>{
+  item.audio_status.loading = false
+  let index = item.audio_status.audioIndex
+  console.log(index);
+  console.log("canplay");
+  if(!audio.value[index].played){
+    play(item,index)
+  }
+}
+
+
+onBeforeRouteLeave(()=>{
+  console.log('onBeforeRouteLeave','离开路由');
+  if( question.audioPlayingIndex!= -1 ){
+    console.log(question.audioPlayingIndex);
+    pause(question.audioPlayingItem,question.audioPlayingIndex,'end')
+  }
+})
+
+getBarList()
 </script>
 
 <template>
-  <div>
-      我的问答
+  <div class="my-questionList-contain" ref="listPageEl">
+    <div class="top-tabbar-box" :style="{width:width+'px'}">
+      <div class="top-tabbar-row" >
+        <div v-for="item in question.barList" :key="item.key" @click="changeTopTar(item.key)"
+        :class="['top-tabbar-item',item.key == question.selectKey?'tabbar-active':'']">
+          <span class="top-tabbar-item-title">
+            {{item.label}}<span style="margin-left: 12px;">({{item.num}})</span>
+          </span>
+        </div>
+      </div>
+    </div>
+      <div class="question-noData" v-show="question.list.length==0 && question.isFinish">
+        <img :src="$store.state.globalImgUrls.activityNoAuth" alt="没有数据">
+        <span>暂无数据</span>
+      </div>
+      <div class="question-list" v-show = "question.list.length>0 && question.isFinish">
+        <div class="question-item" v-for="(item,index) in question.list" :key="item.community_question_id"
+        @click="toDetail(item)">
+          <div class="question-info">
+            <div class="label" 
+            v-if="(item.reply_status === 3 || item.replier_user_id == $store.state.userInfo.user_id) && question.questionStatus!=2">
+            {{item.research_group_second_name}}
+            </div>
+            {{item.question_content}}
+          </div>
+          <div class="question-time">
+            提问时间:{{moment(item.create_time).format('YYYY.MM.DD')}}
+          </div>
+          <div class="question-audio" v-if="item.reply_status === 3">
+            <audio :autoplay="false" :loop="false" preload ref="audio"
+            @waiting="audioWaiting(item)" @canplay="audioCanPlay(item)">
+              <source :src="item.audio_list[0].audio_url" type="audio/mp3"  />
+              <p>你的浏览器不支持 HTML5 音频,请直接下载<a :href="item.audio_list[0].audio_url">音频文件</a>。</p>
+            </audio>
+            <div class="audio-icon" @click="audioPlay(item)" v-if="!item.audio_status.loading">
+              <img src="@/assets/recordplay.png" alt="播放" v-show="!item.audio_status.isPlay" />
+              <img src="@/assets/recordpause.png" alt="暂停" v-show="item.audio_status.isPlay" />
+            </div>
+            <div class="audio-icon loading-icon" @click="pause(item,item.audio_status.audioIndex)" v-else>
+              <img class="load-img" src="@/assets/loading.png" alt="加载中">
+            </div>
+            <div class="audio-pic">
+              <img src="@/assets/audio-waveform1.png">
+              <img src="@/assets/audio-waveform2.png">
+            </div>
+            <div class="audio-time">{{moment((item.audio_status.audioTime - item.audio_status.playedTime)).format('mm:ss')}}</div>
+          </div>
+        </div>
+        <div class="bottom-tip-contain">
+          <div class="bottom-tip-loadMore" v-show="!question.isTotalData && !question.isLoading" @click="loadingMore">加载更多</div>
+          <div class="loading-text" v-show="question.isLoading">加载中······</div>
+          <div class="bottom-tip-noMore" v-show="question.isTotalData && !question.isLoading">没有更多了~</div>
+        </div>
+      </div>
   </div>
+
 </template>
 
 <style scoped lang="scss">
-
+  .my-questionList-contain{
+    border-left: 1px solid #F2F2F2;
+    border-right: 1px solid #F2F2F2;
+    .top-tabbar-box{
+      padding: 30px 30px 12px 30px;
+      background: #FFFFFF;
+      box-shadow: 0px 4px 8px 1px rgba(0, 0, 0, 0.04);
+      position: sticky;
+      top: 60px;
+      width: 100%;
+      max-width: 1240px;
+      z-index: 10;
+      .top-tabbar-row{
+        display: flex;
+        flex-wrap: wrap;
+        .top-tabbar-item{
+          min-width: 140px;
+          height: 40px;
+          box-sizing: border-box;
+          background: #F6F6F6;
+          border-radius: 20px;
+          display: flex;
+          align-items: center;
+          justify-content: center;
+          margin-right: 30px;
+          cursor: pointer;
+          margin-bottom: 10px;
+          .top-tabbar-item-title{
+            font-family: 'PingFang SC';
+            font-style: normal;
+            font-weight: 400;
+            font-size: 16px;
+            color: #333333;
+          }
+        }
+        .tabbar-active{
+          border: 1px solid #F3A52F;
+          box-shadow: 0px 6px 7px #FFF7EB;
+          .top-tabbar-item-title{
+            color: #F3A52F;
+          }
+        }
+      }
+    }
+    .question-noData{
+      display: flex;
+      flex-direction: column;
+      align-items: center;
+      justify-content: center;
+      margin-top: 50px;
+      img{
+          height: 360px;
+      }
+      span{
+          margin-top: 30px;
+          font-family: 'PingFang SC';
+          font-style: normal;
+          font-weight: 400;
+          font-size: 16px;
+          color: #333333;
+      }
+    }
+    .question-list{
+      .question-item{
+        padding: 32px 30px;
+        border: 1px solid #F2F2F2;
+        border-top: 1px solid transparent ;
+        box-sizing: border-box;
+        .question-info{
+          display: flex;
+          align-items: center;
+          font-size: 16px;
+          font-family: PingFang SC-Medium, PingFang SC;
+          font-weight: 500;
+          color: #333333;
+          margin-bottom: 16px;
+          .label{
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            min-width: 68px;
+            background: #333333;
+            border-radius: 21px 21px 21px 21px;
+            height: 24px;
+            padding: 0 12px;
+            font-size: 12px;
+            font-family: PingFang SC-Medium, PingFang SC;
+            font-weight: 500;
+            color: #F3A52F;
+            margin-right: 14px;
+          }
+        }
+        .question-time{
+          font-size: 16px;
+          font-family: PingFang SC-Regular, PingFang SC;
+          font-weight: 400;
+          color: #666666;
+          margin-bottom: 24px;
+        }
+        .question-audio{
+          width: 443px;
+          height: 46px;
+          background-color: #F3A52F;
+          border: 1px solid #F3A52F;
+          border-radius: 23px;
+          display: flex;
+          align-items: center;
+          padding: 0 54px 0 27px;
+          .audio-icon{
+            cursor: pointer;
+            img{
+              width: 16px;
+            }
+            .load-img{
+              width: 20px;
+              animation: circle 0.5s linear infinite;
+            }
+            @keyframes circle {
+              0%{
+                  transform: rotateZ(0);
+              }
+              100%{
+                  transform: rotateZ(360deg);
+              }
+            }
+          }
+          .audio-pic{
+            margin: 0 27px 0 27px;
+          }
+          .audio-time{
+            font-size: 16px;
+            font-family: PingFang SC-Regular, PingFang SC;
+            font-weight: 400;
+            color: #FFFFFF;
+          }
+        }
+      }
+      .bottom-tip-contain{
+          .bottom-tip-loadMore{
+              margin: 20px auto;
+              width: 112px;
+              height: 30px;
+              background: #FFFFFF;
+              border-radius: 20px;
+              border: 1px solid #F3A52F;
+              color: #F3A52F;
+              font-size: 14px;
+              text-align: center;
+              line-height: 30px;
+              cursor: pointer;
+          }
+          .loading-text{
+              margin: 20px auto;
+              text-align: center;
+              color: #666;
+              height: 30px;
+          }
+          .bottom-tip-noMore{
+            text-align: center;
+            color: #F3A52F;
+          }
+      }
+    }
+  }
 </style>

+ 80 - 0
src/views/question/questionMixins.js

@@ -0,0 +1,80 @@
+import{
+    apiQuestionList
+  }from '@/api/question'
+
+export const questionMixin = {
+    data() {
+        return {
+            // 问题列表
+            list:[],
+            page_index:1,
+            page_size:20,
+            //分组列表
+            optionList:[],
+            // 二级分组列表数据
+            secondGroupList:[],
+            // 一级分组Id
+            selectedGroupId_first :0,
+            // 二级分组Id
+            selectedGroupId_second:0,
+            // 正在播放的音频问题索引,没有为-1
+            audioPlayingIndex:-1,
+            // 正在播放的音频问题,没有为-1
+            audioPlayingItem:null,
+            reply_status:3,
+            // 是否加载完成
+            isFinish:false,
+            // 数据是否全部加载完成
+            isTotalData:false,
+            // 是否在加载中
+            isLoading:false,
+        }
+    },
+    methods: {
+        getQuestionList(){
+            console.log(this);
+            this.isLoading = true
+            console.log(this);
+            let params = {
+              group_id:this.selectedGroupId_second,
+              reply_status:this.reply_status,
+              page_index:this.page_index,
+              page_size:this.page_size,
+            }
+            console.log(params);
+            apiQuestionList(params).then(res=>{
+              this.isFinish = true
+              if(res.code == 200){
+                let arr =res.data || []
+                if(params.page_index ==1){
+                  if(arr.length==0) return 
+                  this.list = arr
+                }else{
+                  if(arr.length==0){
+                    this.isTotalData = true
+                    return 
+                  }
+                  this.list = [...this.list,...arr]
+                }
+                for (const item of this.list) {
+                  if(!item.audio_status){
+                    item.audio_status={
+                      isPlay:false,
+                      // 已播放时间
+                      playedTime:0,
+                      // 总共的时长
+                      audioTime:item.audio_list[0].audio_play_seconds*1000,
+                      // 是否在加载中
+                      loading:false
+                    }
+                  } 
+                }
+              }
+              console.log(this.list);
+            })
+            .finally(()=>{
+              this.isLoading = false
+            })
+        }
+    },
+}