Explorar o código

Merge branch 'master' of http://8.136.199.33:3000/jwyu/hongze_yb_pc

hbchen %!s(int64=2) %!d(string=hai) anos
pai
achega
c203b83c74

+ 13 - 2
src/api/common.js

@@ -165,6 +165,17 @@ export const apiGetTagTree = params=>{
 /**
  * 获取用户已绑定权限
  */
-export const apiUserBindPermission=()=>{
-    return get('/company/permission/bind',{})
+
+export const apiUserBindPermission=params=>{
+    return get('/company/permission/bind',params)
+}
+
+/**
+ * 更新媒体播放记录时长
+ * @param id 日志ID
+ * @param stop_seconds 访问时长
+ * @param source 来源:1-问答社区; 2-语音播报; 3-视频社区; 4-路演视频
+ */
+export const apiViewLogUpdate=params=>{
+    return post('/public/view_log/update',params)
 }

+ 4 - 0
src/api/question.js

@@ -88,6 +88,7 @@ export const apiCountAudioClick = params=>{
     "op_type": 1, 1-点赞 2-吐槽
     "enable": 1, 0取消 1-有效数据
     "source_agent": 1, 1:小程序,2:小程序 pc 3:弘则研究公众号,4:web pc
+    source:来源:1-问答社区(默认, 传0也是); 2-视频社区
  */
 export const apiSetLike = params => {
     let source_agent=2
@@ -106,6 +107,7 @@ export const apiSetLike = params => {
  "content": "这里是roc的测试评论",
     "is_show_name": 0,
     "source_agent": 1,
+    source:来源:1-问答社区(默认, 传0也是); 2-视频社区
 */
 export const apiPublishComment = params => {
     let source_agent=2
@@ -147,6 +149,7 @@ export const apiDelComment = params => {
  * community_question_id 
  * curr_page
  * page_size
+ * source:来源:1-问答社区(默认, 传0也是); 2-视频社区
  */
 export const apiHotComment = params => {
     return get('/community/comment/hot',params)
@@ -158,6 +161,7 @@ export const apiHotComment = params => {
  * community_question_id 
  * curr_page
  * page_size
+ * source:来源:1-问答社区(默认, 传0也是); 2-视频社区
  */
 export const apiMyComment = params => {
     return get('/community/comment/my',params)

+ 19 - 0
src/api/report.js

@@ -222,4 +222,23 @@ export const apiRddpShareImg=params=>{
  */
 export const apiReportPPtImgs=params=>{
     return get('/report/ppt_img',params)
+}
+
+/**
+ * 品种类型报告中品种筛选项
+ * @param classify_id 分类id
+ */
+export const apiGoodsPermissionList=params=>{
+    return get('/company/permission/commodities',params)
+}
+
+/**
+ * 按品种查询报告列表
+ * @param chart_permission_id 品种id
+ * @param classify_id 分类id
+ * @param current_index
+ * @param page_size
+ */
+export const apiReportListForVariety=params=>{
+    return get('/report/variety/list',params)
 }

+ 11 - 0
src/router/index.js

@@ -172,6 +172,17 @@ const routes=[
           hasBack:true
         },
       },
+      {
+        path: "varietyreportlist",
+        name: "VarietyReportList",
+        component: () => import("@/views/report/reportForVariety/List.vue"),
+        meta: {
+          title: "报告列表",
+          keepAlive:true,
+          isRoot:false,
+          hasBack:true
+        },
+      },
     ]
   },
   {

+ 120 - 3
src/store/index.js

@@ -2,8 +2,12 @@ import { createStore } from "vuex";
 import {ElMessage} from 'element-plus'
 import {apiUserInfo} from '@/api/user.js'
 import {apiActivityAudioPlayRecordAdd,apiActivityAudioPlayRecordUpate} from '@/api/activity'
+import {apiViewLogUpdate} from  '@/api/common'
+import{apiCountAudioClick}from '@/api/question'
+import {apiVoicePlayRecord} from '@/api/voice'
 
 let lastActivityAudioRecordId=0//上次新曾活动音频记录时的id
+let lastAudioRecordId=0//上次问答社区\语音播报 音频记录id
 
 const token=localStorage.getItem('token')||''
 let platform='web'
@@ -72,6 +76,19 @@ export default createStore({
 
     // 设置音频播放
     addAudio(state,e){
+      // 更新活动音频播放时长
+      if(state.audioData.activityId!=0&&lastActivityAudioRecordId!=0){
+        handleActivityAudioRecordUpdate(state.audioData)
+      }
+      // 更新问答\语音播报 音频播放时长
+      if(lastAudioRecordId!=0){
+        if(state.audioData.voiceId!=0){
+          handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:2})
+        }
+        if(state.audioData.questionId!=0){
+          handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:1})
+        }
+      }
       state.audioData.index=e.index
       state.audioData.list=e.list
       state.audioData.activityId=e.activityId||0
@@ -81,11 +98,14 @@ export default createStore({
       state.audioData.show=true
       state.audioData.INS.play()
       if(state.audioData.activityId!=0){
-        if(lastActivityAudioRecordId!=0){
-          handleActivityAudioRecordUpdate(state.audioData)
-        }
         handleActivityAudioRecordAdd(state.audioData)
       }
+      if(state.audioData.voiceId!=0){
+        handleVoiceAudioRecordAdd(state.audioData)
+      }
+      if(state.audioData.questionId!=0){
+        handleQuestionAudioRecordAdd(state.audioData)
+      }
     },
     //切换音频
     changeAudio(state,e){
@@ -96,7 +116,25 @@ export default createStore({
           if(state.audioData.activityId!=0){
             handleActivityAudioRecordUpdate(state.audioData)
           }
+          if(state.audioData.voiceId!=0){
+            handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:2})
+          }
+          if(state.audioData.questionId!=0){
+            handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:1})
+          }
+
           state.audioData.index--
+
+          if(state.audioData.activityId!=0){
+            handleActivityAudioRecordAdd(state.audioData)
+          }
+          if(state.audioData.voiceId!=0){
+            handleVoiceAudioRecordAdd(state.audioData)
+          }
+          if(state.audioData.questionId!=0){
+            handleQuestionAudioRecordAdd(state.audioData)
+          }
+          
         }
       }else if(e==='next'){//点击按钮切换下一首
         if(state.audioData.index==state.audioData.list.length-1){
@@ -105,8 +143,23 @@ export default createStore({
           if(state.audioData.activityId!=0){
             handleActivityAudioRecordUpdate(state.audioData)
           }
+          if(state.audioData.voiceId!=0){
+            handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:2})
+          }
+          if(state.audioData.questionId!=0){
+            handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:1})
+          }
           
           state.audioData.index++
+          if(state.audioData.activityId!=0){
+            handleActivityAudioRecordAdd(state.audioData)
+          }
+          if(state.audioData.voiceId!=0){
+            handleVoiceAudioRecordAdd(state.audioData)
+          }
+          if(state.audioData.questionId!=0){
+            handleQuestionAudioRecordAdd(state.audioData)
+          }
         }
       }else if(e==='auto'){//自动播放切换下一首
         if(state.audioData.index==state.audioData.list.length-1){
@@ -114,6 +167,12 @@ export default createStore({
           if(state.audioData.activityId!=0){
             handleActivityAudioRecordUpdate(state.audioData)
           }
+          if(state.audioData.voiceId!=0){
+            handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:2})
+          }
+          if(state.audioData.questionId!=0){
+            handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:1})
+          }
           
           state.audioData.list=[]
           state.audioData.index=0
@@ -128,8 +187,23 @@ export default createStore({
           if(state.audioData.activityId!=0){
             handleActivityAudioRecordUpdate(state.audioData)
           }
+          if(state.audioData.voiceId!=0){
+            handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:2})
+          }
+          if(state.audioData.questionId!=0){
+            handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:1})
+          }
           
           state.audioData.index++
+          if(state.audioData.activityId!=0){
+            handleActivityAudioRecordAdd(state.audioData)
+          }
+          if(state.audioData.voiceId!=0){
+            handleVoiceAudioRecordAdd(state.audioData)
+          }
+          if(state.audioData.questionId!=0){
+            handleQuestionAudioRecordAdd(state.audioData)
+          }
         }
       }
     },
@@ -138,6 +212,12 @@ export default createStore({
       if(state.audioData.activityId!=0){
         handleActivityAudioRecordUpdate(state.audioData)
       }
+      if(state.audioData.voiceId!=0){
+        handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:2})
+      }
+      if(state.audioData.questionId!=0){
+        handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:1})
+      }
       
       state.audioData.list=[]
       state.audioData.index=0
@@ -164,6 +244,12 @@ export default createStore({
       if(state.audioData.activityId!=0){
         handleActivityAudioRecordUpdate(state.audioData)
       }
+      if(state.audioData.voiceId!=0){
+        handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:2})
+      }
+      if(state.audioData.questionId!=0){
+        handleAudioRecordUpdate({audioCurrentTime:state.audioData.audioCurrentTime,source:1})
+      }
       
       state.audioData.show=false
     },
@@ -255,4 +341,35 @@ function handleActivityAudioRecordUpdate(params) {
       console.log('更新音频记录成功');
     }
   })
+}
+
+// 更新问答社区、语音播报模块 音频播放记录
+function handleAudioRecordUpdate(params){
+  apiViewLogUpdate({
+    id:lastAudioRecordId,
+    stop_seconds:parseInt(params.audioCurrentTime),
+    source:params.source,
+  }).then(res=>{
+    console.log('更新播放时长成功');
+  })
+}
+
+//新增语音播报音频播放记录
+function handleVoiceAudioRecordAdd(params){
+  apiVoicePlayRecord({
+    broadcast_id:params.voiceId
+  }).then(res=>{
+    console.log('上报音频播放记录');
+    lastAudioRecordId=res.data
+  })
+} 
+
+//新增问答社区语音播放记录
+function handleQuestionAudioRecordAdd(params){
+  apiCountAudioClick({
+    community_question_audio_id:params.list[params.index].id
+  }).then(res=>{
+    console.log('上报问答音频播放记录');
+    lastAudioRecordId=res.data
+  })
 }

+ 8 - 8
src/views/question/List.vue

@@ -276,17 +276,17 @@ const handlePlay=(item)=>{
     }
     const audioItem=item.audio_list[0]
     store.commit('addAudio',{
-        list:[{name:item.question_content,url:audioItem.audio_url,time:audioItem.audio_play_seconds}],
+        list:[{name:item.question_content,url:audioItem.audio_url,time:audioItem.audio_play_seconds,id:audioItem.community_question_audio_id}],
         questionId:item.community_question_id,
         index:0
     })
-    apiCountAudioClick({
-        community_question_audio_id:audioItem.community_question_audio_id
-    }).then((res)=>{
-        if(res.code===200){
-          console.log('音频id为'+audioItem.community_question_audio_id+'点击次数+1')  
-        }  
-    })
+    // apiCountAudioClick({
+    //     community_question_audio_id:audioItem.community_question_audio_id
+    // }).then((res)=>{
+    //     if(res.code===200){
+    //       console.log('音频id为'+audioItem.community_question_audio_id+'点击次数+1')  
+    //     }  
+    // })
 }
 
 

+ 8 - 8
src/views/question/MyList.vue

@@ -300,17 +300,17 @@ const handlePlay=(item)=>{
     }
     const audioItem=item.audio_list[0]
     store.commit('addAudio',{
-        list:[{name:item.question_content,url:audioItem.audio_url,time:audioItem.audio_play_seconds}],
+        list:[{name:item.question_content,url:audioItem.audio_url,time:audioItem.audio_play_seconds,id:audioItem.community_question_audio_id}],
         questionId:item.community_question_id,
         index:0
     })
-    apiCountAudioClick({
-        community_question_audio_id:audioItem.community_question_audio_id
-    }).then((res)=>{
-        if(res.code===200){
-          console.log('音频id为'+audioItem.community_question_audio_id+'点击次数+1')  
-        }  
-    })
+    // apiCountAudioClick({
+    //     community_question_audio_id:audioItem.community_question_audio_id
+    // }).then((res)=>{
+    //     if(res.code===200){
+    //       console.log('音频id为'+audioItem.community_question_audio_id+'点击次数+1')  
+    //     }  
+    // })
 }
 
 getBarList()

+ 10 - 2
src/views/report/Classify.vue

@@ -28,7 +28,7 @@ getClassifyList()
 
 // 跳转下一级
 const goNext=(item)=>{
-    // redirect_type : 跳转页面类型:1专栏列表,2报告列表,3专栏详情
+    // redirect_type : 跳转页面类型:1专栏列表,2报告列表,3专栏详情,4品种类型列表
     if(item.redirect_type===1){
         router.push({
             path:'/report/specialcolumnlist',
@@ -55,7 +55,15 @@ const goNext=(item)=>{
             }
         })
     }
-
+    if(item.redirect_type===4){
+        router.push({
+            path:'/report/varietyreportlist',
+            query:{
+                classifyId:item.classify_id_first,
+                classifyName:item.classify_name_first
+            }
+        })
+    }
 
 }
 

+ 2 - 0
src/views/report/List.vue

@@ -184,12 +184,14 @@ const posterParams=computed(()=>{
         obj.title_1=reportState.list[0].title 
         obj.abstract_1=reportState.list[0].classify_name_second
         obj.time_1=`${reportState.list[0].stage}期 | ${moment(reportState.list[0].publish_time).format('YYYY.MM.DD')}`
+        obj.abstract_1_style=reportState.list[0].classify_name_second?'':'display:none'
     }
     if(reportState.list[1]){
         obj.img_2=reportState.list[1].report_img_url
         obj.title_2=reportState.list[1].title 
         obj.abstract_2=reportState.list[1].classify_name_second
         obj.time_2=`${reportState.list[1].stage}期 | ${moment(reportState.list[1].publish_time).format('YYYY.MM.DD')}`
+        obj.abstract_2_style=reportState.list[1].classify_name_second?'':'display:none'
     }
     return obj
 })

+ 458 - 0
src/views/report/reportForVariety/List.vue

@@ -0,0 +1,458 @@
+<script setup>
+import {apiReportListForVariety,apiGoodsPermissionList} from '@/api/report'
+import SelfList from '@/components/SelfList.vue'
+import moment from 'moment';
+import { reactive,onMounted,onActivated,computed,ref } from 'vue'
+import { useRoute,useRouter } from 'vue-router';
+import { useStore } from 'vuex';
+import { ElMessage } from 'element-plus'
+
+const route=useRoute()
+const router=useRouter()
+const store=useStore()
+
+let classifyId=ref(route.query.classifyId||0) //一级分类id
+document.title=decodeURIComponent(route.query.classifyName)
+
+// 获取用户已绑定品种
+let permissionList=reactive({
+    list:[],
+    firstPerId:0,
+    secList:[],
+    secPerId:0,
+})
+const getPermissionList=async ()=>{
+    const res=await apiGoodsPermissionList({
+        classify_id:Number(classifyId.value),
+    })
+    if(res.code===200){
+        let arr=res.data.permission_list||[]
+        if(arr.length===0){
+            ElMessage.warning('暂无权限')
+            setTimeout(() => {
+                router.replace('/report/classify')
+            }, 2000);
+            return
+        }
+        permissionList.list=arr
+        handleSelectFirstVariety(res.data.permission_list[0])
+    }
+}
+getPermissionList()
+// 选择一级品种
+const handleSelectFirstVariety=(item)=>{
+    permissionList.firstPerId=item.id 
+    permissionList.secList=item.list
+    handleSelectSecVariety(item.list[0])
+}
+//选择二级品种
+const handleSelectSecVariety=(item)=>{
+    permissionList.secPerId=item.chart_permission_id
+    reportState.page=1
+    reportState.list=[]
+    reportState.finished=false
+    getReportList()
+}
+
+// 获取报告列表
+let reportState=reactive({
+    list:[],
+    page:1,
+    pageSize:20,
+    loading:false,
+    finished:false,
+})
+const getReportList=async ()=>{
+    reportState.loading=true
+    const res=await apiReportListForVariety({
+        chart_permission_id:Number(permissionList.secPerId),
+        classify_id:Number(classifyId.value),
+        current_index:reportState.page,
+        page_size:reportState.pageSize
+    })
+    reportState.loading=false
+    if(reportState.page==1){
+        document.body.scrollTop=document.documentElement.scrollTop=0
+    }
+    if(res.code===200){
+        let arr=res.data.list||[]
+        reportState.list=[...reportState.list,...arr]
+        reportState.finished=res.data.paging.is_end 
+    }
+}
+
+// 加载更多列表数据
+const onLoad=()=>{
+    reportState.page++
+    getReportList()
+}
+
+//跳转详情
+const goReportDetail=(item)=>{
+    if(['晨报','周报'].includes(item.classify_name_first)){
+        router.push({
+            path:'/report/chapterdetail',
+            query:{
+                chapterId:item.report_chapter_id
+            }
+        })
+    }else{
+        router.push({
+            path:'/report/detail',
+            query:{
+                reportId:item.report_id
+            }
+        })
+    }
+}
+
+//播放音频
+const handlePlayAudio=(item)=>{
+    if(item.video_list){
+        if(store.state.audioData.reportId==item.report_id){
+            if(store.state.audioData.paused){
+                store.state.audioData.INS.play()
+            }else{
+                store.state.audioData.INS.pause()
+            }
+            return
+        }
+        const arr=item.video_list.map(_item=>{
+            return {
+                name:_item.video_name,
+                url:_item.video_url,
+                time:_item.video_play_seconds
+            }
+        })
+        store.commit('addAudio',{
+            list:arr,
+            reportId:item.report_id,
+            index:0
+        })
+    }
+}
+
+// 向小程序发送数据
+const handleDataToXcx=()=>{
+    const postData={
+        path:'/pages-report/reportForVariety/list',
+        params:{
+            classifyId:classifyId.value,
+            classifyName:route.query.classifyName
+        },
+        title:`FICC【${route.query.classifyName}】`,
+        shareImg:''
+    }
+    wx.miniProgram.postMessage({ data: postData })
+}
+
+onMounted(()=>{
+    handleDataToXcx()
+})
+
+// 组件激活时
+onActivated(()=>{
+    const temClassifyId=route.query.classifyId||0
+    if(temClassifyId!=classifyId.value){
+        classifyId.value=temClassifyId
+        reportState.list=[]
+        reportState.page=1
+        reportState.finished=false
+        permissionList.list=[]
+        permissionList.firstPerId=0
+        permissionList.secList=[]
+        permissionList.secPerId=0
+        getPermissionList()
+    }
+    handleDataToXcx()
+})
+
+const code_scene=computed(()=>{
+    return JSON.stringify({classifyId:classifyId.value,classifyName:route.query.classifyName})
+})
+
+const posterParams=computed(()=>{
+    let obj={
+        list_title:route.query.classifyName,
+        stage_1:'',
+        avatar_1:'',
+        title_1:'',
+        author_1:'',
+        tag_1:'',
+        stage_2:'',
+        avatar_2:'',
+        title_2:'',
+        author_2:'',
+        tag_2:'',
+        abstract_2_style:'',
+        abstract_1_style:'',
+    }
+    if(reportState.list[0]){
+        obj.img_1=reportState.list[0].report_img_url
+        obj.title_1=reportState.list[0].title 
+        obj.abstract_1=reportState.list[0].classify_name_second
+        obj.time_1=`${reportState.list[0].stage}期 | ${moment(reportState.list[0].publish_time).format('YYYY.MM.DD')}`
+        obj.abstract_1_style=reportState.list[0].classify_name_second?'':'display:none'
+    }
+    if(reportState.list[1]){
+        obj.img_2=reportState.list[1].report_img_url
+        obj.title_2=reportState.list[1].title 
+        obj.abstract_2=reportState.list[1].classify_name_second
+        obj.time_2=`${reportState.list[1].stage}期 | ${moment(reportState.list[1].publish_time).format('YYYY.MM.DD')}`
+        obj.abstract_2_style=reportState.list[1].classify_name_second?'':'display:none'
+    }
+    return obj
+})
+</script>
+
+<template>
+    <div class="variety-report-list-page">
+        <div class="top-nav-warp">
+            <div class="flex first-nav-box">
+                <span 
+                    :class="['item',item.id===permissionList.firstPerId?'active':'']" 
+                    v-for="item in permissionList.list" 
+                    :key="item.id"
+                    @click="handleSelectFirstVariety(item)"
+                >{{item.classify_name}}</span>
+            </div>
+            <div class="sec-nav-box">
+                <span 
+                    :class="['item',item.chart_permission_id===permissionList.secPerId?'active':'']"
+                    v-for="item in permissionList.secList.slice(0,6)" 
+                    :key="item.chart_permission_id"
+                    @click="handleSelectSecVariety(item)"
+                >{{item.chart_permission_name}}</span>
+                <el-popover
+                    :width="500"
+                    trigger="click"
+                >
+                    <template #reference>
+                        <img v-if="permissionList.secList.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 == permissionList.secPerId&&'active']" 
+                            v-for="item in permissionList.secList.slice(6)" 
+                            :key="item.chart_permission_id"
+                            @click="handleSelectSecVariety(item)"
+                        >{{item.chart_permission_name}}</div>
+                        </div>
+                    </template>
+                </el-popover>
+            </div>
+        </div>
+        <SelfList 
+            :finished="reportState.finished" 
+            :isEmpty="reportState.list.length === 0 && reportState.finished" 
+            :loading="reportState.loading" 
+            :count="reportState.list.length"
+            @listOnload="onLoad"
+            emptyMsg="暂无报告"
+        >
+            <div class="flex list-wrap">
+                <div class="flex item" v-for="item in reportState.list" :key="item.report_id" @click="goReportDetail(item)">
+                    <el-image class="report-img" :src="item.report_img_url" fit="cover" lazy />
+                    <div class="con">
+                        <div class="top-name" v-html="item.title_info"></div>
+                        <div class="title" v-html="item.title"></div>
+                        <div class="des" v-html="item.abstract"></div>
+                        <div class="clear-float bot">
+                            <span class="time">{{moment(item.publish_time).format('YYYY.MM.DD HH:mm')}}</span>
+                            <div 
+                                class="btn" 
+                                v-if="item.auth_ok" 
+                                @click.stop="handlePlayAudio(item)"
+                            >{{$store.state.audioData.reportId==item.report_id?$store.state.audioData.paused?'已暂停':'播放中':'立即播放'}}</div>
+                        </div>  
+                    </div>
+                </div>
+                <div class="last-add-item"></div>
+                <div class="last-add-item"></div>
+            </div>
+        </SelfList>
+    </div>
+    <!-- 生成海报 -->
+    <SharePoster  
+        :shareData="{
+            type:'report_list',
+            code_page:'pages-report/reportForVariety/list',
+            code_scene:code_scene,
+            data:posterParams
+        }"
+    ></SharePoster>
+</template>
+
+<style lang="scss" scoped>
+.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;
+    }
+}
+
+.variety-report-list-page{
+    .top-nav-warp{
+        position: sticky;
+        top: 60px;
+        z-index: 50;
+        background: #FFFFFF;
+        box-shadow: 0px 4px 8px rgba(0, 0, 0, 0.04);
+        padding: 30px 30px 12px 30px;
+        margin-bottom: 30px;
+        .first-nav-box{
+            .item{
+                width: 140px;
+                height: 40px;
+                flex-shrink: 0;
+                background: #F6F6F6;
+                border-radius: 20px;
+                text-align: center;
+                line-height: 40px;
+                font-size: 16px;
+                margin-right: 30px;
+                cursor: pointer;
+                &:hover {
+                    background: #FFFBF5;
+                    color: #F3A52F;
+                    border: 1px solid #F3A52F;
+                    box-shadow: 0px 6px 7px 1px #FFF7EB;
+                }
+            }
+            .active {
+                background: #FFFBF5;
+                color: #F3A52F;
+                border: 1px solid #F3A52F;
+                box-shadow: 0px 6px 7px 1px #FFF7EB;
+            }
+            @media screen and (max-width: 1350px){
+                .item{
+                    width: 90px;
+                    height: 30px;
+                    line-height: 30px;
+                    margin-right: 15px;
+                    font-size: 14px;
+                }
+            }
+        }
+        .sec-nav-box{
+            margin-top: 30px;
+            .item{
+                flex-shrink: 0;
+                margin-right: 30px;
+                font-size: 16px;
+                color: #666666;
+                cursor: pointer;
+            }
+            .active{
+                color: #F3A52F;
+            }
+        }
+    }
+    .list-wrap{
+        flex-wrap: wrap;
+        justify-content: center;
+        // &::after{
+        //     content:'';
+        //     display: block;
+        //     height:0;
+        //     flex-shrink: 0;
+        //     width: 380px;
+        //     margin-bottom: 20px;
+        //     margin-left: 10px;
+        //     margin-right: 10px;
+        // }
+
+        // 末尾补充的两个元素 为了整体能居中
+        .last-add-item{
+            height:0;
+            flex-shrink: 0;
+            width: 380px;
+            margin-left: 10px;
+            margin-right: 10px;
+        }
+        .item{
+            flex-shrink: 0;
+            width: 380px;
+            background: #FFFFFF;
+            box-shadow: 3px 3px 12px 1px rgba(184, 184, 184, 0.16);
+            border-radius: 8px;
+            border: 1px solid #F2F2F2;
+            padding: 20px;
+            margin-bottom: 20px;
+            margin-left: 10px;
+            margin-right: 10px;
+            overflow: hidden;
+            .report-img{
+                flex-shrink: 0;
+                width: 110px;
+                height: 160px;
+                border-radius: 8px;
+                margin-right: 15px;
+            }
+            .con{
+                flex: 1;
+                display: flex;
+                flex-direction: column;
+                justify-content: space-between;
+                overflow: hidden;
+            }
+            .top-name{
+                background-color: #FFFBF5;
+                // text-align: center;
+                font-size: 14px;
+                color: #F3A52F;
+                padding: 4px 0;
+            }
+            .title{
+                :deep(span){
+                    color:#F3A52F !important;
+                }
+            }
+            .des{
+                color: #999;
+            }
+            .bot{
+                display: flex;
+                align-items: flex-end;
+                justify-content: space-between;
+                .time{
+                    flex-shrink: 0;
+                    font-size: 14px;
+                    color: #999;
+                }
+                .btn{
+                    flex-shrink: 0;
+                    width: 88px;
+                    height: 30px;
+                    background: #F3A52F;
+                    border-radius: 15px;
+                    color: #fff;
+                    text-align: center;
+                    line-height: 30px;
+                    font-size: 14px;
+                    cursor: pointer;
+                }
+            }
+        }
+    }
+}
+</style>

+ 22 - 5
src/views/roadShow/video/List.vue

@@ -3,7 +3,7 @@ import {ref,reactive,onMounted,onActivated} from 'vue'
 import { useElementSize } from '@vueuse/core'
 import { ElMessage, ElMessageBox } from 'element-plus'
 
-import {apiGetWechatQRCode,apiUserBindPermission} from '@/api/common'
+import {apiGetWechatQRCode,apiUserBindPermission,apiViewLogUpdate} from '@/api/common'
 import {apiRoadShowVideoList,apiRoadShowVideoPlayLog} from '@/api/roadShow'
 import {apiApplyPermission} from '@/api/user'
 
@@ -210,15 +210,31 @@ const onLoad=()=>{
 
 //当前正在播放哪个
 let curVideoId=ref(0)
+let videoRecordId=0//音频播放记录id
 const handelClickPlay=(item)=>{
     curVideoId.value=item.road_video_id
     //记录播放
     apiRoadShowVideoPlayLog({video_id:Number(item.road_video_id)}).then(res=>{
         if(res.code===200){
             console.log('视频埋点成功');
+            videoRecordId=res.data
         }
     })
 }
+//视频播放暂停事件
+const handleVideoPause=(e)=>{
+    const target=e.target||e.path[0]
+    const t=target.currentTime||0
+    console.log('记录播放时长',t);
+    if(!videoRecordId||t==0) return
+    apiViewLogUpdate({
+        id:videoRecordId,
+        stop_seconds:parseInt(t),
+        source:4
+    }).then(res=>{
+        console.log('记录播放时长成功');
+    })
+}
 
 
 //获取视频单个对应的小程序二维码
@@ -226,7 +242,7 @@ const handelGetQRCodeImg=async (item)=>{
     if(item.QRCodeImg) return
     const res=await apiGetWechatQRCode({
         CodeScene:JSON.stringify({videoId:item.road_video_id}),
-        CodePage:'pages-roadShow/video/list'
+        CodePage:'pages/roadShow/video/list'
     })
     if(res.code===200){
         item.QRCodeImg=res.data
@@ -236,7 +252,7 @@ const handelGetQRCodeImg=async (item)=>{
 onMounted(() => {
   //向小程序发送消息
   let postData = {
-    path: "/pages-roadShow/video/list",
+    path: "/pages/roadShow/video/list",
     params:{},
     title: "FICC线上路演",
     shareImg:''
@@ -245,10 +261,10 @@ onMounted(() => {
 });
 
 onActivated(()=>{
-    curVideoId.value=0
+    // curVideoId.value=0
     //向小程序发送消息
     let postData = {
-        path: "/pages-roadShow/video/list",
+        path: "/pages/roadShow/video/list",
         params:{},
         title: "FICC线上路演",
         shareImg:''
@@ -344,6 +360,7 @@ onActivated(()=>{
                         autoplay
                         v-if="item.road_video_id==curVideoId"
                         @ended="curVideoId=0"
+                        @pause="handleVideoPause"
                     ></video>
                     <div v-else class="poster-img" :style="'background-image:url('+item.cover_img_url+')'" @click="handelClickPlay(item)"></div>
                     <div class="time">发布时间:{{item.publish_time}}</div>

+ 36 - 14
src/views/video/List.vue

@@ -1,13 +1,13 @@
 <script setup>
 import {ref,reactive,onMounted,onActivated} from 'vue'
-import { useElementSize } from '@vueuse/core'
 import { ElMessage, ElMessageBox } from 'element-plus'
 
-import {apiFICCPermissionList,apiGetWechatQRCode,apiGetTagTree} from '@/api/common'
+import {apiFICCPermissionList,apiGetWechatQRCode,apiGetTagTree,apiViewLogUpdate} from '@/api/common'
 import {apiVideoList,apiVideoPlayLog} from '@/api/video'
 import {apiApplyPermission} from '@/api/user'
 
 import SelfList from '@/components/SelfList.vue'
+import Comment from './components/Comment.vue'
 import { useRoute, useRouter } from 'vue-router'
 import { useStore } from 'vuex'
 
@@ -18,10 +18,6 @@ const store=useStore()
 //分享进入的videoid 
 let videoId=ref(0)
 
-//监听列表页面版心宽度
-const listPageEl=ref('')
-const {width}=useElementSize(listPageEl)
-
 // 获取品种权限数据
 let permissionState=reactive({
     firstNavList:[],
@@ -213,15 +209,31 @@ const onLoad=()=>{
 
 //当前正在播放哪个
 let curVideoId=ref(0)
+let videoRecordId=0//音频播放记录id
 const handelClickPlay=(item)=>{
     curVideoId.value=item.community_video_id
     //记录播放
     apiVideoPlayLog({video_id:Number(item.community_video_id)}).then(res=>{
         if(res.code===200){
             console.log('视频埋点成功');
+            videoRecordId=res.data
         }
     })
 }
+//视频播放暂停事件
+const handleVideoPause=(e)=>{
+    const target=e.target||e.path[0]
+    const t=target.currentTime||0
+    console.log('记录播放时长',t);
+    if(!videoRecordId||t==0) return
+    apiViewLogUpdate({
+        id:videoRecordId,
+        stop_seconds:parseInt(t),
+        source:3
+    }).then(res=>{
+        console.log('记录播放时长成功');
+    })
+}
 
 
 //获取视频单个对应的小程序二维码
@@ -248,7 +260,7 @@ onMounted(() => {
 });
 
 onActivated(()=>{
-    curVideoId.value=0
+    // curVideoId.value=0
     //向小程序发送消息
     let postData = {
         path: "/pages/video/videoList",
@@ -277,8 +289,8 @@ onActivated(()=>{
             <div class="global-main-btn btn" @click="handleApply" style="margin-bottom: 20px;">立即申请</div>
         </template>
     </div>
-    <div class="video-list-page" ref="listPageEl" v-else>
-        <div class="top-nav-box" :style="{width:width+'px'}">
+    <div class="video-list-page" v-else>
+        <div class="top-nav-box">
             <div class="first-nav-box">
                 <span 
                     v-for="item in permissionState.firstNavList" 
@@ -323,7 +335,7 @@ onActivated(()=>{
             @listOnload="onLoad"
         >
             <div class="flex list-wrap">
-                <div class="flex video-item" v-for="item in listState.list" :key="item.community_video_id">
+                <div class="video-item" v-for="item in listState.list" :key="item.community_video_id">
                     <el-popover
                         :width="200"
                         trigger="hover"
@@ -336,8 +348,14 @@ onActivated(()=>{
                             <img style="width:100%" :src="item.QRCodeImg" alt="">
                         </template>
                     </el-popover>
-                    <div class="title">{{item.title}}</div>
-                    <div>
+                    <el-tooltip
+                        effect="dark"
+                        :content="item.title"
+                        placement="top-start"
+                    >
+                    <div class="multi-ellipsis title">{{item.title}}</div>
+                    </el-tooltip>
+                    <div class="time">发布时间:{{item.publish_time}}</div>
                     <video 
                         :src="item.video_url" 
                         controls
@@ -347,10 +365,11 @@ onActivated(()=>{
                         autoplay
                         v-if="item.community_video_id==curVideoId"
                         @ended="curVideoId=0"
+                        @pause="handleVideoPause"
                     ></video>
                     <div v-else class="poster-img" :style="'background-image:url('+item.cover_img_url+')'" @click="handelClickPlay(item)"></div>
-                    <div class="time">发布时间:{{item.publish_time}}</div>
-                    </div>
+             
+                    <Comment :videoInfo="item"></Comment>
                 </div>
                 <div class="last-add-item"></div>
                 <div class="last-add-item"></div>
@@ -482,6 +501,8 @@ onActivated(()=>{
                 height: 200px;
                 object-fit: contain;
                 margin: 19px 0;
+                display: block;
+                box-sizing: border-box;
             }
             .poster-img{
                 width: 100%;
@@ -507,6 +528,7 @@ onActivated(()=>{
             .time{
                 color: #999;
                 font-size: 14px;
+                margin-top: 10px;
             }
         }
         .last-add-item{

+ 312 - 0
src/views/video/components/Comment.vue

@@ -0,0 +1,312 @@
+<script setup>
+import likeIcon from '@/assets/question/like.png'
+import likeactIcon from '@/assets/question/like_act.png'
+import teaseIcon from '@/assets/question/tease.png'
+import teaseactIcon from '@/assets/question/tease_act.png'
+
+import {reactive,ref} from 'vue'
+import {apiSetLike,apiHotComment,apiMyComment,apiPublishComment,apiDelComment} from '@/api/question'
+import { ElMessage, ElMessageBox } from 'element-plus'
+
+const props=defineProps({
+    videoInfo:null
+})
+
+let info=ref(props.videoInfo)
+
+//点赞\吐槽
+const handleSetLike=async (type)=>{
+    const res=await apiSetLike({
+        community_question_id:info.value.community_video_id,
+        op_type: type,
+        enable: type === 1 ? Number(info.value.op_type!==1) : Number(info.value.op_type!==2),
+        source:2
+    })
+    if(res.code===200){
+        const { enabled,op_type,like_total,tease_total } = res.data;
+        info.value.tease_total = tease_total;
+        info.value.like_total = like_total;
+        info.value.op_type = enabled === 0 ? 0 : op_type ;
+        ElMessage({
+            message: enabled === 0 ? '取消成功' : op_type=== 1 ? '点赞成功' : '吐槽成功',
+            type: 'success',
+        })
+    }
+}
+
+let popData=reactive({
+    show:false,
+    msg:'',
+    list:[],
+    select_comment_type:1,
+    total:0,
+    myTotal:0,
+})
+//点击显示评论弹窗
+const handleShowPop=()=>{
+    popData.show=true
+    popData.select_comment_type=1
+    popData.msg=''
+    getComment()
+}
+
+//获取评论
+const getComment=async (flag)=>{
+    const params={
+        community_question_id:info.value.community_video_id,
+        curr_page: 1,
+        page_size: 10000,
+        source:2
+    }
+    const { code,data } = popData.select_comment_type===1 ? await apiHotComment(params) : await apiMyComment(params);
+    if(code !== 200) return
+    popData.list = data.list || [];
+    popData.total=data.hot_total
+    popData.myTotal=data.my_total
+
+    // 如果flag='refresh' 则获取一次全部留言 更新到列表上面去
+    if(flag==='refresh'){
+        let res={
+            data:{}
+        }
+        if(popData.select_comment_type===1){
+            res.data=data
+        }else{
+            res=await apiHotComment(params)
+        }
+        const arr=res.data.list||[]
+        info.value.comment_list=arr.map(item=>{
+            return {
+                comment:item.content,
+                qa_avatar_url:item.qa_avatar_url
+            }
+        })
+        info.value.comment_total=arr.length
+    }
+}
+
+//切换评论类型
+const  handleChangeCommentType=(type)=>{
+    popData.select_comment_type=type 
+    getComment()
+}
+
+// 发布评论
+const handlePublish=async ()=>{
+    if(!popData.msg){
+        ElMessage({
+            message: '请输入留言内容',
+            type: 'warning',
+        })
+    }
+
+    const { code } = await apiPublishComment({
+        content: popData.msg,
+        community_question_id: info.value.community_video_id,
+        source:2,
+    })
+    if(code===200){
+        ElMessage({
+            message: '发布成功',
+            type: 'success',
+        })
+        popData.msg=''
+        getComment('refresh')
+    }
+}
+
+//删除评论
+const handleDelMyComment=(item)=>{
+    ElMessageBox({
+        title:`温馨提示`,
+        message:'评论删除后不可恢复,确认删除吗?',
+        dangerouslyUseHTMLString: true,
+        center: true,
+        confirmButtonText:'确定',
+        confirmButtonClass:'self-elmessage-confirm-btn',
+        showCancelButton:true,
+        cancelButtonText:'取消',
+        cancelButtonClass:'self-elmessage-cancel-btn'
+    }).then(res=>{
+        apiDelComment({ community_question_comment_id:item.community_question_comment_id}).then(res=>{
+            if(res.code===200){
+                ElMessage({
+                    message: '删除成功',
+                    type: 'success',
+                })
+                getComment('refresh')
+            }
+        })
+    }).catch(()=>{})
+}
+
+</script>
+
+<template>
+    <div class="video-comment-wrap">
+        <div class="flex action-wrap">
+            <div class="item" @click="handleSetLike(1)">
+                <img :src="info.op_type===1?likeactIcon:likeIcon" alt="">
+                <span>{{info.like_total>0?info.like_total:''}}</span>
+            </div>
+            <div class="item" @click="handleSetLike(2)">
+                <img :src="info.op_type===2?teaseactIcon:teaseIcon" alt="">
+                <span>{{info.tease_total>0?info.tease_total:''}}</span>
+            </div>
+            <div class="item" @click="handleShowPop">
+                <img src="@/assets/question/comment.png" alt="">
+                <span>{{info.comment_total>0?info.comment_total:''}}</span>
+            </div>
+        </div>
+        <div class="list-comment-wrap" v-if="info.comment_list.length>0">
+            <template v-for="(item,index) in info.comment_list" :key="index">
+                <img class="avatar" :src="item.qa_avatar_url" mode="aspectFill" lazy-load="false" />
+				<span>{{item.comment}}</span>
+            </template>
+        </div>
+        <el-dialog 
+            v-model="popData.show"
+            width="50%" 
+            title="评论"
+            draggable
+        >
+            <div class="write-wrap">
+                <el-input
+                    v-model="popData.msg"
+                    :rows="6"
+                    type="textarea"
+                    placeholder="发布一条友善的评论"
+                />
+                <div class="clear-float" style="margin-top:20px">
+                    <el-button type="info" text @click="popData.show=false">取消发布</el-button>
+                    <div class="global-main-btn" style="float:right;width:140px" @click="handlePublish">发布</div>
+                </div>
+            </div>
+            <div class="all-commnet-list-wrap">
+                <div class="type-box">
+                    <span :class="popData.select_comment_type==1?'act':''" @click="handleChangeCommentType(1)">全部评论<span v-if="popData.total>0">({{popData.total}})</span></span>
+                    <span :class="popData.select_comment_type==2?'act':''" @click="handleChangeCommentType(2)">我的评论<span v-if="popData.myTotal>0">({{popData.myTotal}})</span></span>
+                </div>
+                <ul>
+                    <li class="item" v-for="item in popData.list" :key="item.community_question_comment_id">
+                        <div class="flex" style="align-items: center;">
+                            <img :src="item.qa_avatar_url" alt="">
+                            <div class="flex con">{{item.content}}</div>
+                        </div>
+                        <span class="del-btn" v-if="popData.select_comment_type==2" @click="handleDelMyComment(item)">删除</span>
+                    </li>
+                </ul>
+                <div class="empty-box" v-if="popData.list.length==0">
+                    <img :src="$store.state.globalImgUrls.chartEmpty" alt="">
+                    <p>暂无评论</p>
+                </div>
+            </div>
+        </el-dialog>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.video-comment-wrap{
+    ::v-deep(.el-dialog__header){
+        border-bottom: 1px solid #E9E9E9;
+        margin-right: 0;
+    }
+    ::v-deep(.el-dialog__body){
+        padding: 0;
+    }
+    margin-top: 20px;
+    .action-wrap{
+        justify-content: space-between;
+        .item{
+            cursor: pointer;
+            img{
+                width: 22px;
+                height: 22px;
+                vertical-align: middle;
+            }
+            span{
+                font-size: 16px;
+                color: #999;
+                vertical-align: middle;
+            }
+        }
+    }
+
+    .list-comment-wrap{
+        margin-top: 22px;
+        font-size: 16px;
+        color: #666;
+        .avatar{
+            width: 28px;
+            height: 28px;
+            object-fit: cover;
+            margin-right: 8px;
+			vertical-align: middle;
+            border-radius: 50%;
+        }
+        span{
+            vertical-align: middle;
+            margin-right: 20px;
+        }
+    }
+
+    .write-wrap{
+        padding: 30px;
+        border-bottom: 1px solid #E9E9E9;
+    }
+
+    .all-commnet-list-wrap{
+        max-height: 40vh;
+        overflow-y: auto;
+        padding: 30px;
+        .type-box{
+            span{
+                font-size: 16px;
+                color: #999;
+                display: inline-block;
+                margin-right: 30px;
+                cursor: pointer;
+            }
+            .act{
+                font-size: 18px;
+                color: #F3A52F;
+            }
+        }
+        ul{
+            margin-top: 30px;
+        }
+        .item{
+            
+            margin-bottom: 14px;
+            img{
+                width: 28px;
+                height: 28px;
+                object-fit: cover;
+                margin-right: 8px;
+                flex-shrink: 0;
+                border-radius: 50%;
+            }
+            .con{
+                align-items: center;
+                font-size: 16px;
+                color: #666;
+            }
+            .del-btn{
+                color: #D63535;
+                cursor: pointer;
+                margin-left: 37px;
+                margin-top: 5px;
+                display: block;
+            }
+        }
+        .empty-box{
+            text-align: center;
+            color: #666;
+            img{
+                width: 200px;
+            }
+        }
+    }
+}
+</style>
+

+ 1 - 1
src/views/voice/Detail.vue

@@ -220,7 +220,7 @@ const handlePlay=(item)=>{
         voiceId:item.BroadcastId,
         index:0
     })
-    handleVoiceRecord(item)
+    // handleVoiceRecord(item)
 }
 
 //上报音频播放记录

+ 1 - 1
src/views/voice/List.vue

@@ -269,7 +269,7 @@ const handlePlay=(item)=>{
         voiceId:item.BroadcastId,
         index:0
     })
-    handleVoiceRecord(item)
+    // handleVoiceRecord(item)
 }
 
 //上报音频播放记录

+ 1 - 1
src/views/voice/Mine.vue

@@ -239,7 +239,7 @@ const handlePlay=(item)=>{
         index:0
     })
     if(item.PublishState==0) return //待发布的不记录
-    handleVoiceRecord(item)
+    // handleVoiceRecord(item)
 }
 
 //上报音频播放记录