浏览代码

合同yb3.0冲突

jwyu 2 年之前
父节点
当前提交
153affd218

+ 2 - 1
package.json

@@ -20,7 +20,8 @@
     "normalize.css": "^8.0.1",
     "vant": "^3.3.4",
     "vue": "^3.2.16",
-    "vue-router": "^4.0.12"
+    "vue-router": "^4.0.12",
+    "vuex": "^4.0.2"
   },
   "devDependencies": {
     "@vitejs/plugin-vue": "^1.9.3",

+ 23 - 0
src/api/hzyb/report.js

@@ -12,3 +12,26 @@ export const apiGetWeekReportDetail=params=>{
     return get('/report/research_report_chapter',params)
 }
 
+/**
+ * 研报详情
+ * @param report_id 
+ */
+export const apiReportDetail=params=>{
+    return get('/report/detail',params)
+}
+
+/**
+ * 章节详情
+ * @param report_chapter_id
+ */
+export const apiChapterDetail=params=>{
+    return get('/report/chapter/detail',params)
+}
+
+/**
+ * 章节详情中指标数据
+ * @param report_chapter_id
+ */
+export const apiChapterTickerValue=params=>{
+    return get('/report/chapter/ticker',params)
+}

+ 14 - 0
src/api/hzyb/user.js

@@ -7,4 +7,18 @@ import {get,post} from './http'
  */
 export const apiUserInfo=(params)=>{
 	return get('/user/info',params)
+}
+
+/**
+ * 用户权限申请
+ * @param business_card_url 名片地址
+ * @param company_name 公司名
+ * @param permission 选择的权限
+ * @param real_name 姓名
+ * @param source 来源:我的1、活动2、图库3、研报4
+ * @param source_agent 来源平台:1:小程序、2:pc
+ * @param from_page 来源页面: '活动列表'、'活动详情'等
+ */
+ export const apiApplyPermission=params=>{
+	return post('/user/apply',{...params,source_agent:1})
 }

二进制
src/assets/hzyb/report/audio-pause-small.png


二进制
src/assets/hzyb/report/audio-pause.png


二进制
src/assets/hzyb/report/audio-play-small.png


二进制
src/assets/hzyb/report/audio-play.png


二进制
src/assets/hzyb/report/back-top.png


+ 2 - 2
src/main.js

@@ -1,9 +1,9 @@
 import { createApp } from 'vue'
 import App from './App.vue'
 import router from './router'
+import store from './store'
 import 'normalize.css'
 import './style/common.scss'
 import '@vant/touch-emulator';//vant 
 
-
-createApp(App).use(router).mount('#app')
+createApp(App).use(router).use(store).mount('#app')

+ 18 - 0
src/router/hzyb/index.js

@@ -35,4 +35,22 @@ export const hzybRoutes=[
             }
         ]
     },
+    // 报告模块
+    {
+        path:'/hzyb/report',
+        name:'hzybReport',
+        component: () => import("@/views/hzyb/Index.vue"),
+        children:[
+            {
+                path:"detail",
+                name:"hzybReportDetailNew",
+                component: () => import("@/views/hzyb/report/Detail.vue"),
+            },
+            {
+                path:"chapterdetail",
+                name:"hzybChapterDetail",
+                component: () => import("@/views/hzyb/report/ChapterDetail.vue"),
+            },
+        ]
+    }
 ]

+ 24 - 0
src/store/index.js

@@ -0,0 +1,24 @@
+import { createStore, Store } from "vuex";
+import hzyb from "./modules/hzyb";
+
+const store = createStore({
+  state: {
+    userData: {
+      CompanyCode: "",
+      CompanyName: "",
+      Email: "",
+      Sign: null,
+    },
+  },
+  mutations: {
+    getUserData(state, payload) {
+      state.userData = payload;
+    },
+  },
+  actions: {},
+  modules: {
+    hzyb
+  }
+});
+
+export default store;

+ 34 - 0
src/store/modules/hzyb.js

@@ -0,0 +1,34 @@
+const hzybStore={
+    namespaced: true,
+    state:{
+        audioData:{
+            INS:null,
+            url:'',//音频链接
+            videoTime:0,//音频时长
+            videoName:'',//音频名称
+            paused:true,//音频是否在暂停
+        }
+    },
+    mutations: {
+        // 点击播放音频
+        addAudio(state,e){
+            state.audioData.url=e.video_url
+            state.audioData.videoTime=e.video_play_seconds
+            state.audioData.videoName=e.video_name
+            state.audioData.INS.play()
+        },
+        // 更新音频播放状态
+        upateAudioStatus(state,e){
+            if(e==='end'){
+                state.audioData.url=''
+                
+            }else if(e==='play'){
+                state.audioData.paused=false
+            }else if(e==='paused'){
+                state.audioData.paused=true
+            }
+        }
+    }
+}
+
+export default hzybStore

+ 122 - 0
src/views/hzyb/Index.vue

@@ -0,0 +1,122 @@
+<script setup>
+import {ref} from 'vue'
+import { Slider } from 'vant';
+import { useStore } from "vuex";
+
+const store=useStore()
+
+const audioIconPlaysmall=new URL('../../assets/hzyb/report/audio-play-small.png', import.meta.url).href
+const audioIconPausesmall=new URL('../../assets/hzyb/report/audio-pause-small.png', import.meta.url).href
+
+const formatVoiceTime = (e) => {
+  let minus = parseInt(e / 60);
+  let sec = parseInt(e % 60);
+  return `${minus > 9 ? minus : "0" + minus}分${sec > 9 ? sec : "0" + sec}秒`;
+};
+
+let currentTime=ref(0)
+const audioIns=ref('')
+store.state.hzyb.audioData.INS=audioIns
+
+// 以下为音频事件
+const audioError=()=>{
+    console.log('音频加载出错');
+}
+
+const audioPlay=()=>{
+    console.log('音频开始播放');
+    store.commit('hzyb/upateAudioStatus','play')
+}
+
+const audioPause=()=>{
+    console.log('音频暂停');
+    store.commit('hzyb/upateAudioStatus','paused')
+}
+
+const audioTimeupdate=(e)=>{
+    // console.log(e.target.currentTime);
+    currentTime.value=e.target.currentTime
+}
+
+const audioEnded=()=>{
+    console.log('音频播放结束');
+    store.commit('hzyb/upateAudioStatus','end')
+}
+
+// 音频进度条变化
+const SliderChange=(e)=>{
+    store.state.hzyb.audioData.INS.currentTime=e
+}
+
+const handleClickAudio=()=>{
+    if(store.state.hzyb.audioData.paused){
+        store.state.hzyb.audioData.INS.play()
+    }else{
+        store.state.hzyb.audioData.INS.pause()
+    }
+}
+
+
+</script>
+
+
+<template>
+    <router-view />
+    <audio
+        ref="audioIns"
+        autoplay
+        :src="$store.state.hzyb.audioData.url"
+        @error="audioError"
+        @play="audioPlay"
+        @pause="audioPause"
+        @timeupdate="audioTimeupdate"
+        @ended="audioEnded"
+        style="display:none"
+    />
+    <!-- 悬浮音频模块 -->
+    <div class="popup-audio-box" v-if="$store.state.hzyb.audioData.url">
+        <div>{{$store.state.hzyb.audioData.videoName}}</div>
+        <div class="flex">
+            <span>{{formatVoiceTime(currentTime)}}</span>
+            <Slider button-size="10px" v-model="currentTime" :max="$store.state.hzyb.audioData.videoTime" active-color="#D5AD79" @change="SliderChange" class="slider"></Slider>
+            <span>{{ formatVoiceTime($store.state.hzyb.audioData.videoTime) }}</span>
+            <img :src="$store.state.hzyb.audioData.paused?audioIconPausesmall:audioIconPlaysmall"  alt="" @click="handleClickAudio">
+        </div>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.popup-audio-box{
+    position: fixed;
+    z-index: 99;
+    bottom: 30px;
+    width: 90vw;
+    left: 5vw;
+    min-height: 100px;
+    background: #FFFFFF;
+    border: 2px solid rgba(240, 234, 226, 0.32);
+    border-radius: 10px;
+    padding: 10px 20px;
+    font-size: 24px;
+    text-align: center;
+    padding-bottom: 20px;
+    .flex{
+        display: flex;
+        align-items: center;
+        .slider{
+            margin-left: 15px;
+            margin-right: 10px;
+        }
+        span{
+            flex-shrink: 0;
+            display: inline-block;
+        }
+        img{
+            width: 36px;
+            height: 36px;
+            flex-shrink: 0;
+            margin-left: 10px;
+        }
+    }
+}
+</style>

+ 590 - 0
src/views/hzyb/report/ChapterDetail.vue

@@ -0,0 +1,590 @@
+<template>
+<van-pull-refresh v-model="loading" @refresh="onRefresh" style="min-height:100vh">
+  <div class="chapter-detail-page" v-if="info" :style="{paddingBottom:$store.state.hzyb.audioData.url&&'80px'}">
+    <div :class="['main-box',!info.auth_ok&&'main-box-noauth']">
+      <div class="title">【第{{info.report_chapter_item.stage}}期 | {{info.report_chapter_item.classify_name_first}}  | {{info.report_chapter_item.type_name}}】{{info.report_chapter_item.title}}</div>
+      <div class="flex time">
+        <span>FICC团队</span>
+        <span>{{formatTime(info.report_chapter_item.publish_time)}}</span>
+      </div>
+      <!-- 音频模块 -->
+      <AudioBox :audioData="audioData" v-if="info.report_chapter_item.video_url&&info.report_chapter_item.video_play_seconds>0"></AudioBox>
+      <div class="tips">
+        <span>注:请务必阅读</span>
+        <span style="color: #e3b377; margin-left: 20px" @click="showDisclaimers = true">免责声明</span>
+      </div>
+      <div class="rich-content">
+        <div v-html="info.report_chapter_item.content" v-if="info.auth_ok"></div>
+        <div v-html="info.report_chapter_item.content_sub" v-else ></div>
+      </div>
+      <!-- 指标数据模块 -->
+      <div class="ticker-wrap" v-if="tickerInfo">
+        <div class="top-title">{{tickerInfo.ticker_title.report_chapter_type_name}}数据表</div>
+        <div class="table-box">
+          <div class="table-row table-head">
+            <div class="table-item" v-for="item in tickerHead" :key="item.key">{{item.label}}</div>
+          </div>
+          <div class="table-row table-body" v-for="(tr,index) in tickerInfo.list" :key="tr.base_column_name">
+            <div :class="['table-item',index%2==0?'grey':'',tr[td.key]<0?'minus':'']" v-for="td in tickerHead" :key="td.key">{{tr[td.key]}}</div>
+          </div>
+        </div>
+        <div v-if="tickerInfo.ticker_title.report_chapter_type_id ===26" style="text-align:center;font-weight:bold">注:与新加坡TSR20相关数据均取展示日期前一交易日数据</div>
+      </div>
+      <!-- 无权限 -->
+      <div class="no-auth-wrap" v-if="!info.auth_ok">
+        <div class="apply-box" v-if="info.permission_check.type=='apply'">
+          <div>您暂无权限查看报告,若想查看请申请开通</div>
+          <div class="btn" @click="handleGoApply">立即申请</div>
+        </div>
+        <div class="apply-box" v-else>
+          <div>您暂无权限查看报告 </div>
+          <div>若想查看请联系对口销售:{{info.permission_check.name}}</div>
+          <a class="btn" :href="'tel:'+info.permission_check.mobile" tag="div">立即联系</a>
+        </div>
+      </div>
+      
+    </div>
+    <!-- 章节详情底部快速切换 -->
+    <div class="chapter-list-wrap" v-if="fromPage=='reportdetail'">
+      <div class="top-text">更多</div>
+      <van-row gutter="10">
+        <van-col span="6" v-for="item in info.report_chapter_menu_list" :key="item.report_chapter_id">
+          <div :class="['item',item.report_chapter_id==chapterId&&'active']" @click="handleChapterChange(item)">
+            <img :src="item.report_chapter_type_thumb" mode="aspectFill"/>
+            <text>{{item.report_chapter_type_name}}</text>
+          </div>
+        </van-col>
+      </van-row>
+    </div>
+
+    <!-- 返回顶部 -->
+    <img v-if="showToTop&&info.auth_ok" @click="handleBackTop" class="back-top-img" src="@/assets/hzyb/report/back-top.png" mode="aspectFill"/>
+
+    <!-- 免责声明 -->
+    <van-popup :show="showDisclaimers" @close="showDisclaimers = false" round closeable>
+      <div class="disclaimers-box">
+        <div style="text-align: center; font-size: 16px; font-weight: bold; margin-bottom: 20px">免责声明</div>
+        <div style="margin-bottom: 10rpx">1、本报告仅供弘则弥道(上海)投资咨询有限公司正式签约的机构客户使用,不会仅因接收人/接受机构收到本报告而将其视为客户。</div>
+        <div style="margin-bottom: 10rpx"
+          >2、本报告根据国际和行业通行的准则,以合法渠道获得这些信息,尽可能保证可靠、准确和完整,但并不保证报告所述信息的准确性和完整性,也不保证本报告所包含的信息或建议在本报告发出后不会发生任何变更。本报告中所提供的信息仅供参考。</div
+        >
+        <div style="margin-bottom: 10rpx"
+          >3、报告中的内容不对投资者做出的最终操作建议做任何的担保,也没有任何形式的分享投资收益或者分担投资损失的书面或口头承诺。不作为客户在投资、法律、会计或税务等方面的最终操作建议,也不作为道义的、责任的和法律的依据或者凭证,无论是否已经明示或者暗示。</div
+        >
+        <div style="margin-bottom: 10rpx">4、在任何情况下,本公司不对客户/接受人/接受机构因使用报告中内容所引致的一切损失负责任,客户/接受人/接受机构需自行承担全部风险。</div>
+      </div>
+    </van-popup>
+
+    <!-- 申请提示弹窗 -->
+    <van-popup :show="pupData.show" @close="pupData.show=false" :close-on-click-overlay="false">
+        <div class="global-pup">
+            <div class="content">
+                <div v-html="pupData.content"></div>
+            </div>
+            <div class="flex bot">
+                <div @click="pupData.show=false">知道了</div>
+            </div>
+        </div>
+    </van-popup>
+  </div>
+</van-pull-refresh>
+</template>
+
+<script>
+// 由于当时写在uni中 直接复制过来的 也不想改了就写成vue2形式吧
+import moment from 'moment'
+import 'moment/dist/locale/zh-cn'
+moment.locale('zh-cn')
+
+import {apiChapterDetail,apiChapterTickerValue} from '@/api/hzyb/report'
+import {apiApplyPermission} from '@/api/hzyb/user'
+import {Popup,Image as VanImage,PullRefresh,Col, Row} from 'vant'
+import AudioBox from './components/AudioBox.vue'
+export default {
+  components:{
+    [Popup.name]:Popup,
+    [VanImage.name]:VanImage,
+    [PullRefresh.name]:PullRefresh,
+    [Col.name]:Col,
+    [Row.name]:Row,
+    [PullRefresh.name]:PullRefresh,
+    AudioBox
+  },
+  data() {
+    return {
+      showDisclaimers: false, //显示免责声明
+      chapterId:0,
+      fromPage:'',//如果是从首页(home)来的则隐藏底部切换
+      info:null,
+      audioData:{},//音频数据
+
+      tickerInfo:null,
+      tickerHead:[],
+
+      pupData:{
+				show:false,
+				content:'',//弹窗html字符串
+			},
+
+      loading:false,
+
+      showToTop:false
+
+    };
+  },
+  beforeCreate(){
+    if(this.$route.query.token){
+      localStorage.setItem('hzyb-token',this.$route.query.token)
+    }
+  },
+  created(options) {
+    this.chapterId=this.$route.query.chapterId
+    this.fromPage=this.$route.query.fromPage||''
+    this.getDetail()
+  },
+  mounted(){
+        $(document).on('click', '.rich-content img',function(event) {
+            let imgArray = [];
+            let curImageSrc = $(this).attr('src');
+            let oParent = $(this).parent();
+            if (curImageSrc && !oParent.attr('href')) {
+                $('.rich-content img').each(function(index, el) {
+                    let itemSrc = $(this).attr('src');
+                    imgArray.push(itemSrc);
+                });
+                wx.previewImage({current:curImageSrc,urls:imgArray});
+            }
+        })
+    window.addEventListener('scroll',this.handelPageScroll)
+  },
+  destroyed () {
+    window.removeEventListener('scroll',this.handelPageScroll)
+  },
+  methods: {
+    handelPageScroll(){
+      const top=document.documentElement.scrollTop
+      if(top>window.outerHeight){
+        this.showToTop=true
+      }else{
+        this.showToTop=false
+      }
+    },
+
+    async getDetail(){
+      const res=await apiChapterDetail({report_chapter_id:Number(this.chapterId)})
+      if(res.code===200){
+        this.info=res.data
+        this.audioData={
+          auth_ok:res.data.auth_ok,
+          video_name:res.data.report_chapter_item.video_name,
+          video_play_seconds:res.data.report_chapter_item.video_play_seconds,
+          video_url:res.data.report_chapter_item.video_url
+        }
+        document.title=res.data.report_chapter_item.classify_name_first
+        if(res.data.auth_ok&&res.data.report_chapter_item.classify_name_first==='晨报'){
+          this.getTickerValue()
+        }
+
+        if(!res.data.auth_ok){
+          // 获取详情如果为联系销售根据判断条件是否主动申请一次
+          if(this.info.permission_check.type=='contact'&&!this.info.permission_check.customer_info.has_apply){
+              if(this.info.permission_check.customer_info.status=='冻结'||(this.info.permission_check.customer_info.status=='试用'&&this.info.permission_check.customer_info.is_suspend==1)){
+                  apiApplyPermission({
+                      company_name:this.info.permission_check.customer_info.company_name,
+                      real_name:this.info.permission_check.customer_info.name,
+                      source:4,
+                      from_page:'报告详情'
+                  }).then(res=>{
+                      if(res.code===200){
+                          console.log('主动申请成功');
+                      }
+                  }) 
+              }
+          }
+        }
+
+        //向小程序发送分享数据
+        wx.miniProgram.postMessage({ 
+          data: {
+            title:res.data.report_chapter_item.classify_name_first,
+            chapterId:this.chapterId
+          } 
+        });
+      }
+    },
+
+    //获取晨报中指标数据
+    async getTickerValue(){
+      const res=await apiChapterTickerValue({report_chapter_id:Number(this.chapterId)})
+      if(res.code===200){
+        if(!res.data||!res.data.list) return
+        this.tickerInfo=res.data
+        if(res.data.ticker_title.report_chapter_type_id===17){
+          this.tickerHead=[
+            {
+              label:res.data.ticker_title.ticker_title,
+              key:'base_column_name'
+            },
+            {
+              label:'公布日期',
+              key:'date'
+            },
+            {
+              label:'最新值',
+              key:'ticker_value'
+            },
+            {
+              label:'上期值',
+              key:'last_value'
+            }
+          ]
+        }else{
+          this.tickerHead=[
+            {
+              label:res.data.ticker_title.ticker_title,
+              key:'base_column_name'
+            },
+            {
+              label:res.data.list[0].date,
+              key:'ticker_value'
+            },
+            {
+              label:'当日涨跌',
+              key:'dd_value'
+            },
+            {
+              label:'一周涨跌',
+              key:'ww_value'
+            },
+            {
+              label:'一月涨跌',
+              key:'mm_value'
+            }
+          ]
+        }
+      }
+    },
+
+    handleBackTop() {
+      document.body.scrollTop=document.documentElement.scrollTop=0
+    },
+
+    //格式化音频时间
+    formatVoiceTime(e){
+      let minus=parseInt(e/60)
+      let sec=parseInt(e%60)
+      return `${minus>9?minus:'0'+minus}分${sec>9?sec:'0'+sec}秒`
+    },
+
+    formatTime(time){
+      return moment(time).format('YYYY.MM.DD HH:mm:ss')
+    },
+
+    handleChapterChange(item){
+      this.chapterId=item.report_chapter_id
+      this.info=null
+      this.getDetail()
+      this.handleBackTop()
+    },
+
+    // 联系销售
+    // handleContact(){
+    //   uni.makePhoneCall({
+    //     phoneNumber: this.info.permission_check.mobile
+    //   });
+    // },
+
+    //点击申请
+    async handleGoApply(){
+      if(this.info.permission_check.type=='apply'){
+        if(this.info.permission_check.customer_info.has_apply){// 已经申请过
+          this.pupData.show=true
+					this.pupData.content=`<p>您已提交过申请,请耐心等待</p>`
+        }else{
+          if(!this.info.permission_check.customer_info.status||this.info.permission_check.customer_info.status!='流失'){
+            wx.miniProgram.redirectTo({
+              url:"/pages-applyPermission/applyPermission?source=4&from_page=报告详情"
+            })
+          }else{//主动调一次申请权限接口 
+            const res=await apiApplyPermission({
+              company_name:this.info.permission_check.customer_info.company_name,
+              real_name:this.info.permission_check.customer_info.name,
+              source:4,
+              from_page:'报告详情'
+            })
+            if(res.code===200){
+              this.pupData.show=true
+					    this.pupData.content=`<p>申请已提交</p><p>请等待销售人员与您联系</p>`
+              this.getDetail()
+            }
+          }
+        }
+                
+      }
+    },
+
+    //下拉刷新
+    onRefresh(){
+      this.getDetail()
+      setTimeout(() => {
+        this.loading=false
+      }, 1500);
+    }
+
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+/* 公共弹窗 */
+.global-pup{
+    background-color: #fff;
+    width: 90vw;
+    min-height: 200px;
+    font-size: 32px;
+    .content{
+        padding: 34px;
+        text-align: center;
+        min-height: 250px;
+        display: flex;
+        align-items: center;
+        text-align: center;
+        line-height: 1.7;
+        div{
+            flex: 1;
+        }
+    }
+    .bot{
+        border-top: 1px solid #dedede;
+        div{
+            line-height: 96px;
+            flex: 1;
+            text-align: center;
+            border-right: 1px solid #dedede;
+            color:#E3B377;
+        }
+        div:last-child {
+            border: none;
+        }
+    }
+}
+.flex{
+  display: flex;
+}
+.chapter-detail-page {
+    // padding-bottom: 50px;
+    .main-box{
+        padding: 34px;
+    }
+    .main-box-noauth{
+        height: 100vh;
+        overflow: hidden;
+    }
+    .title{
+        font-size: 36px;
+        font-weight: bold;
+        margin-bottom: 30px;
+    }
+    .time{
+        justify-content: space-between;
+        font-size: 28px;
+    }
+
+    .tips{
+        font-size: 34px;
+        margin-bottom: 51px;
+        &::before{
+            content: '';
+            width: 10px;
+            height: 50px;
+            display: inline-block;
+            background-color: #E3B377;
+            margin-right: 20px;
+            position: relative;
+            top: 10px;
+        }
+    }
+
+    .disclaimers-box{
+        width: 94vw;
+        padding: 32px;
+    }
+
+    .rich-content{
+        line-height: 1.7;
+        font-size: 34px;
+        :deep(img){
+            width: 100% !important;
+        }
+    }
+
+    .no-auth-wrap{
+      min-height: 200px;
+      background: linear-gradient(360deg, #FFFFFF 60%, rgba(255, 255, 255, 0) 88%);
+      // position: relative;
+      // top: -150px;
+      padding: 0 34px 50px 34px;
+      position: fixed;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      z-index: 99;
+      text-align: center;
+      font-size: 32px;
+      color: #E3B377;
+      .apply-box{
+        padding-top: 250px;
+      }
+      .btn{
+        width: 100%;
+        margin-left: auto;
+        margin-right: auto;
+        line-height: 80px;
+        background-color: #E6B77D;
+        border-radius: 4px;
+        color: #fff;
+        margin-top: 100px;
+        display: block;
+      }
+    }
+
+    .back-top-img{
+        position: fixed;
+        z-index: 99;
+        width: 76px;
+        height: 76px;
+        right: 34px;
+        bottom: 150px;
+    }
+    .chapter-list-wrap {
+    background-color: #f5f6fa;
+    padding: 34px;
+    min-height: 300px;
+    .top-text {
+      text-align: center;
+      color: #666666;
+      margin-bottom: 30px;
+      &::before {
+        content: "";
+        width: 90px;
+        height: 1px;
+        background-color: #999;
+        display: inline-block;
+        vertical-align: middle;
+        margin-right: 10px;
+      }
+      &::after {
+        content: "";
+        width: 90px;
+        height: 1px;
+        background-color: #999;
+        display: inline-block;
+        vertical-align: middle;
+        margin-left: 10px;
+      }
+    }
+    .item {
+      background-color: #fff;
+      height: 160px;
+      margin-bottom: 20px;
+      text-align: center;
+      color: #C0CFDA;
+      font-size: 24px;
+      padding-top: 20px;
+      border-radius: 8px;
+      overflow: hidden;
+      img{
+        width: 88px;
+        height: 88px;
+        display: block;
+        margin-left: auto;
+        margin-right: auto;
+      }
+    }
+    .active{
+      border: 1px solid #E3B377;
+      position: relative;
+      &::before{
+        content: '';
+        display: block;
+        position: absolute;
+        left: 0;
+        top: 0;
+        width: 0;
+        height: 0;
+        border-top: 46px solid #E3B377;
+        border-right: 46px solid transparent;
+      } 
+    }
+    }
+
+  .ticker-wrap{
+    margin-top: 30px;
+    .top-title{
+      text-align: center;
+      font-size: 36px;
+      font-weight: bold;
+      vertical-align: middle;
+      &::before,&::after{
+        content: '';
+        display: inline-block;
+        width: 100px;
+        height: 4px;
+        background-color:rgb(204, 204, 204);
+        vertical-align: middle;
+        margin: 0 20px;
+      }
+
+    }
+    .table-box{
+      margin: 20px 0;
+      &::-webkit-scrollbar{
+        width: 0;
+      }
+      overflow: auto hidden;
+      .table-row{
+        display: flex;
+        width: 100%;
+      }
+      .table-item{
+        padding: 10px;
+        min-width: 200px;
+        max-width: 280px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+      }
+      .table-head{
+        color: #fff;
+        background-color: rgb(58, 76, 115);
+        .table-item{
+          &:first-child{
+            position: sticky;
+            left: 0;
+            z-index: 5;
+            border-right-color: rgb(58, 76, 115);
+          }
+          background-color: rgb(58, 76, 115);
+        }
+      }
+      .table-body{
+        .table-item{
+          background-color: #fff;
+          &:first-child{
+            position: sticky;
+            left: 0;
+            z-index: 5;
+          }
+        }
+        .grey{
+          background-color: #ddd;
+        }
+        .minus{
+          color: #006600;
+        }
+      }
+    }
+  }
+
+}
+</style>

+ 570 - 0
src/views/hzyb/report/Detail.vue

@@ -0,0 +1,570 @@
+<template>
+<van-pull-refresh v-model="loading" @refresh="onRefresh" style="min-height:100vh">
+    <div class="report-detail-page" v-if="info" :style="{paddingBottom:$store.state.hzyb.audioData.url&&'80px'}">
+        <!-- 晨报、周报章节 -->
+        <div class="chapter-list-wrap" v-if="['晨报','周报'].includes(info.report_info.classify_name_first)">
+            <div class="top-box" :style="'background-image:url(' + info.report_info.banner_url + ')'">
+                <div class="title">{{info.report_info.classify_name_first}}</div>
+                <div class="sub-title">{{info.report_info.title}}</div>
+                <div class="flex top-bot">
+                    <div class="flex time-box">
+                        <div class="day">{{formatChapterTime(info.report_info.publish_time,'day')}}</div>
+                        <div>
+                            <div>{{formatChapterTime(info.report_info.publish_time,'week')}}</div>
+                            <div>{{formatChapterTime(info.report_info.publish_time,'year-month')}}</div>
+                        </div>
+                    </div>
+                    <div class="num">第{{info.report_info.stage}}期</div>
+                </div>
+            </div>
+            <div class="list-box">
+                <div class="flex item" v-for="item in chapterList" :key="item.report_chapter_id" @click="goChapterDetail(item)">
+                    <van-image class="img" :src="item.report_chapter_type_thumb" mode="aspectFill" />
+                    <div class="con">
+                        <div class="title">
+                            {{item.report_chapter_type_name}} 
+                            <text class="tag" :style="{backgroundColor:getTagColor(tag)}" v-for="tag in item.trend.split(',')" :key="tag">{{tag}}</text>
+                        </div>
+                        <div class="van-multi-ellipsis--l2 sub-title">{{item.title}}</div>
+                        <div class="update-time">更新至:{{formatChapterTime(item.publish_time,'year-month-day')}}</div>
+                    </div>
+                </div>
+            </div>
+            <!-- 无权限 -->
+            <div class="no-auth-box" v-if="!info.auth_ok">
+                <img class="img" src="https://hzstatic.hzinsights.com/static/icon/hzyb/activity_no_auth.png" mode="widthFix" />
+                <div class="apply-box" v-if="info.permission_check.type=='apply'">
+                    <div>您暂无权限查看报告,若想查看请申请开通</div>
+                    <div class="btn" @click="handleGoApply">立即申请</div>
+                </div>
+                <div class="apply-box" v-else>
+                    <div>您暂无权限查看报告 </div>
+                    <div>若想查看请联系对口销售:{{info.permission_check.name}}</div>
+                    <a class="btn" :href="'tel:'+info.permission_check.mobile" tag="div">立即联系</a>
+                </div>
+            </div>
+        </div>
+
+        <!-- 报告详情 -->
+        <div :class="['main-box',!info.auth_ok&&'main-box-noauth']" v-else>
+            <div class="title">【第{{info.report_info.stage}}期|{{info.report_info.classify_name_second}}】{{info.report_info.title}}</div>
+            <div class="flex time">
+                <span>FICC团队</span>
+                <span>{{formatTime(info.report_info.publish_time)}}</span>
+            </div>
+            <!-- 音频模块 -->
+            <AudioBox :audioData="audioData" v-if="info.report_info.video_url&&info.report_info.video_play_seconds>0"></AudioBox>
+            <div class="tips">
+                <span>注:请务必阅读</span>
+                <span style="color:#E3B377;margin-left:20px" @click="showDisclaimers=true">免责声明</span>
+            </div>
+
+            <div class="rich-content">
+                <div v-html="info.report_info.content" v-if="info.auth_ok"></div>
+                <div v-html="info.report_info.content_sub" v-else></div>
+            </div>
+
+            <!-- 无权限 -->
+            <div class="no-auth-wrap" v-if="!info.auth_ok">
+                <div class="apply-box" v-if="info.permission_check.type=='apply'">
+                    <div>您暂无权限查看报告,若想查看请申请开通</div>
+                    <div class="btn" @click="handleGoApply">立即申请</div>
+                </div>
+                <div class="apply-box" v-else>
+                    <div>您暂无权限查看报告 </div>
+                    <div>若想查看请联系对口销售:{{info.permission_check.name}}</div>
+                    <a class="btn" :href="'tel:'+info.permission_check.mobile" tag="div">立即联系</a>
+                </div>
+            </div>
+
+            <!-- 返回顶部 -->
+            <img v-if="showToTop&&info.auth_ok" @click="handleBackTop" class="back-top-img" src="@/assets/hzyb/report/back-top.png" mode="aspectFill"/>
+        </div>
+
+        <!-- 免责声明 -->
+        <van-popup :show="showDisclaimers" @close="showDisclaimers=false" round closeable>
+            <div class="disclaimers-box">
+                <div style="text-align:center;font-size:16px;font-weight:bold;margin-bottom:20px">免责声明</div>
+                <div style="margin-bottom:10px">1、本报告仅供弘则弥道(上海)投资咨询有限公司正式签约的机构客户使用,不会仅因接收人/接受机构收到本报告而将其视为客户。</div>
+                <div style="margin-bottom:10px">2、本报告根据国际和行业通行的准则,以合法渠道获得这些信息,尽可能保证可靠、准确和完整,但并不保证报告所述信息的准确性和完整性,也不保证本报告所包含的信息或建议在本报告发出后不会发生任何变更。本报告中所提供的信息仅供参考。</div>
+                <div style="margin-bottom:10px">3、报告中的内容不对投资者做出的最终操作建议做任何的担保,也没有任何形式的分享投资收益或者分担投资损失的书面或口头承诺。不作为客户在投资、法律、会计或税务等方面的最终操作建议,也不作为道义的、责任的和法律的依据或者凭证,无论是否已经明示或者暗示。</div>
+                <div style="margin-bottom:10px">4、在任何情况下,本公司不对客户/接受人/接受机构因使用报告中内容所引致的一切损失负责任,客户/接受人/接受机构需自行承担全部风险。</div>
+            </div>
+        </van-popup>
+
+        <!-- 申请提示弹窗 -->
+        <van-popup :show="pupData.show" @close="pupData.show=false" :close-on-click-overlay="false">
+            <div class="global-pup">
+                <div class="content">
+                    <div v-html="pupData.content"></div>
+                </div>
+                <div class="flex bot">
+                    <div @click="pupData.show=false">知道了</div>
+                </div>
+            </div>
+        </van-popup>
+    </div>
+</van-pull-refresh>
+</template>
+
+<script>
+// 由于当时写在uni中 直接复制过来的 也不想改了就写成vue2形式吧
+import moment from 'moment'
+import 'moment/dist/locale/zh-cn'
+moment.locale('zh-cn')
+
+import {apiReportDetail} from '@/api/hzyb/report'
+import {apiApplyPermission} from '@/api/hzyb/user'
+import {Popup,Image as VanImage,PullRefresh} from 'vant'
+import AudioBox from './components/AudioBox.vue'
+export default {
+    components:{
+        [Popup.name]:Popup,
+        [VanImage.name]:VanImage,
+        [PullRefresh.name]:PullRefresh,
+        AudioBox
+    },
+    data () {
+        return {
+            showDisclaimers:false,//显示免责声明
+            reportId:0,
+            info:null,
+            audioData:{},//音频数据
+            chapterList:[],
+            pupData:{
+				show:false,
+				content:'',//弹窗html字符串
+			},
+            loading:false,
+            showToTop:false
+        }
+    },
+    beforeCreate(){
+        if(this.$route.query.token){
+            localStorage.setItem('hzyb-token',this.$route.query.token)
+        }
+    },
+    created(options) {
+        this.reportId=this.$route.query.reportId
+        this.getDetail()
+    },
+    mounted(){
+        $(document).on('click', '.rich-content img',function(event) {
+            let imgArray = [];
+            let curImageSrc = $(this).attr('src');
+            let oParent = $(this).parent();
+            if (curImageSrc && !oParent.attr('href')) {
+                $('.rich-content img').each(function(index, el) {
+                    let itemSrc = $(this).attr('src');
+                    imgArray.push(itemSrc);
+                });
+                wx.previewImage({current:curImageSrc,urls:imgArray});
+            }
+        })
+        window.addEventListener('scroll',this.handelPageScroll)
+    },
+    destroyed () {
+        window.removeEventListener('scroll',this.handelPageScroll)
+    },
+    methods: {
+        // 页面滚动
+        handelPageScroll(){
+            const top=document.documentElement.scrollTop
+            if(top>window.outerHeight){
+                this.showToTop=true
+            }else{
+                this.showToTop=false
+            }
+        },
+        
+        //获取报告详情
+        async getDetail(){
+            const res=await apiReportDetail({report_id:Number(this.reportId)})
+            if(res.code===200){
+                this.info=res.data
+                this.audioData={
+                    auth_ok:res.data.auth_ok,
+                    video_name:res.data.report_info.video_name,
+                    video_play_seconds:res.data.report_info.video_play_seconds,
+                    video_url:res.data.report_info.video_url
+                }
+                this.chapterList=res.data.report_chapter_list
+                document.title = res.data.report_info.classify_name_first
+                if(!res.data.auth_ok){
+                    // 获取详情如果为联系销售根据判断条件是否主动申请一次
+                    if(this.info.permission_check.type=='contact'&&!this.info.permission_check.customer_info.has_apply){
+                        if(this.info.permission_check.customer_info.status=='冻结'||(this.info.permission_check.customer_info.status=='试用'&&this.info.permission_check.customer_info.is_suspend==1)){
+                            apiApplyPermission({
+                                company_name:this.info.permission_check.customer_info.company_name,
+                                real_name:this.info.permission_check.customer_info.name,
+                                source:4,
+                                from_page:'报告详情'
+                            }).then(res=>{
+                                if(res.code===200){
+                                    console.log('主动申请成功');
+                                }
+                            }) 
+                        }
+                    }
+                }
+                //向小程序发送分享数据
+                wx.miniProgram.postMessage({ 
+                    data: {
+                        title:res.data.report_info.classify_name_first,
+                        reportId:this.reportId
+                    } 
+                });
+            }
+        },
+        
+        //返回顶部
+        handleBackTop(){
+            document.body.scrollTop=document.documentElement.scrollTop=0
+        },
+
+        //跳转章节详情
+        goChapterDetail(item){
+            // this.$router.push({
+            //     path:'/hzyb/report/chapterdetail',
+            //     query:{
+            //         chapterId:item.report_chapter_id
+            //     }
+            // })
+            wx.miniProgram.navigateTo({
+                url:`/pages-report/chapterDetail?chapterId=${item.report_chapter_id}&fromPage=reportdetail`
+            })
+        },
+        
+        // 格式化时间
+        formatTime(time){
+            return moment(time).format('YYYY.MM.DD HH:mm:ss')
+        },
+
+        //格式化音频时间
+        formatVoiceTime(e){
+            let minus=parseInt(e/60)
+            let sec=parseInt(e%60)
+            return `${minus>9?minus:'0'+minus}分${sec>9?sec:'0'+sec}秒`
+        },
+
+        // 格式化章节列表时间
+        formatChapterTime(time,type){
+            if(type==='day'){
+                return moment(time).format('DD')
+            }
+            if(type==='week'){
+                return moment(time).format('dddd')
+            }
+            if(type==='year-month'){
+                return moment(time).format('YYYY-MM')
+            }
+            if(type==='year-month-day'){
+                return moment(time).format('YYYY-MM-DD')
+            }
+        },
+
+        // 联系销售
+        // handleContact(){
+        //     uni.makePhoneCall({
+        //         phoneNumber: this.info.permission_check.mobile
+        //     });
+        // },
+
+        //点击申请
+        async handleGoApply(){
+            if(this.info.permission_check.type=='apply'){
+                if(this.info.permission_check.customer_info.has_apply){// 已经申请过
+                    this.pupData.show=true
+					this.pupData.content=`<p>您已提交过申请,请耐心等待</p>`
+                }else{
+                    if(!this.info.permission_check.customer_info.status||this.info.permission_check.customer_info.status!='流失'){
+                        wx.miniProgram.redirectTo({
+                            url:"/pages-applyPermission/applyPermission?source=4&from_page=报告详情"
+                        })
+                    }else{//主动调一次申请权限接口 
+                        const res=await apiApplyPermission({
+                            company_name:this.info.permission_check.customer_info.company_name,
+                            real_name:this.info.permission_check.customer_info.name,
+                            source:4,
+                            from_page:'报告详情'
+                        })
+                        if(res.code===200){
+                            this.pupData.show=true
+					        this.pupData.content=`<p>申请已提交</p><p>请等待销售人员与您联系</p>`
+                            this.getDetail()
+                        }
+                    }
+                }
+                
+            }
+        },
+
+        onRefresh() {
+            this.getDetail()
+            setTimeout(() => {
+                this.loading=false
+            }, 1500);
+        },
+
+        // 设置tag颜色
+        getTagColor(str){
+            if( str.includes('多')||str.includes('强')||str.includes('反弹') ){
+                return "#DF6051";
+            }else if( str.includes('空')||str.includes('调整') ){
+                return "#6FC5B4";
+            }else{
+                return "#009fe6";
+            }
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+/* 公共弹窗 */
+.global-pup{
+    background-color: #fff;
+    width: 90vw;
+    min-height: 200px;
+    font-size: 32px;
+    .content{
+        padding: 34px;
+        text-align: center;
+        min-height: 250px;
+        display: flex;
+        align-items: center;
+        text-align: center;
+        line-height: 1.7;
+        div{
+            flex: 1;
+        }
+    }
+    .bot{
+        border-top: 1px solid #dedede;
+        div{
+            line-height: 96px;
+            flex: 1;
+            text-align: center;
+            border-right: 1px solid #dedede;
+            color:#E3B377;
+        }
+        div:last-child {
+            border: none;
+        }
+    }
+}
+.flex{
+    display: flex;
+}
+.report-detail-page{
+    padding-bottom: 50px;
+    .main-box{
+        padding: 34px;
+    }
+    .main-box-noauth{
+        height: calc(100vh - 50px);
+        overflow: hidden;
+    }
+    .title{
+        font-size: 36px;
+        font-weight: bold;
+        margin-bottom: 30px;
+    }
+    .time{
+        justify-content: space-between;
+        font-size: 28px;
+    }
+    .audio-wrap{
+        height: 160px;
+        background: #FAF7EE;
+        border-radius: 16px;
+        margin-top: 20px;
+        padding: 10px 31px;
+        margin-bottom: 31px;
+        align-items: center;
+        img{
+            width: 110px;
+            height: 110px;
+            display: block;
+            margin-right: 16px;
+        }
+    }
+
+    .tips{
+        font-size: 34px;
+        margin-bottom: 51px;
+        &::before{
+            content: '';
+            width: 10px;
+            height: 50px;
+            display: inline-block;
+            background-color: #E3B377;
+            margin-right: 20px;
+            position: relative;
+            top: 10px;
+        }
+    }
+
+    .disclaimers-box{
+        width: 94vw;
+        padding: 32px;
+    }
+
+    .rich-content{
+        line-height: 1.7;
+        font-size: 34px;
+        :deep(img){
+            width: 100% !important;
+        }
+    }
+
+    .no-auth-wrap{
+      min-height: 200px;
+      padding: 0 34px 50px 34px;
+      background: linear-gradient(360deg, #FFFFFF 60%, rgba(255, 255, 255, 0) 88%);
+    //   position: relative;
+    //   top: -150px;
+      position: fixed;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      z-index: 99;
+      text-align: center;
+      font-size: 32px;
+      color: #E3B377;
+      .apply-box{
+        padding-top: 250px;
+      }
+      .btn{
+        width: 100%;
+        margin-left: auto;
+        margin-right: auto;
+        line-height: 80px;
+        background-color: #E6B77D;
+        border-radius: 4px;
+        color: #fff;
+        margin-top: 100px;
+        display: block;
+      }
+    }
+
+    .back-top-img{
+        position: fixed;
+        z-index: 99;
+        width: 76px;
+        height: 76px;
+        right: 34px;
+        bottom: 150px;
+    }
+
+    .chapter-list-wrap{
+        .top-box{
+            height: 418px;
+            background-color: rgba($color: #000000, $alpha: 0.7);
+            background-size: cover;
+            color: #fff;
+            position: relative;
+            .title{
+                text-align: center;
+                font-size: 34px;
+                font-weight: 600;
+                padding-top: 78px;
+            }
+            .sub-title{
+                font-size: 32px;
+                text-align: center;
+                width: 70%;
+                margin-left: auto;
+                margin-right: auto;
+            }
+            .top-bot{
+                position: absolute;
+                bottom: 70px;
+                left: 34px;
+                right: 34px;
+                justify-content: space-between;
+                align-items: flex-end;
+                .time-box{
+                    align-items: center;
+                    font-size: 24px;
+                    .day{
+                        font-size: 32px;
+                        border-right: 1px solid #fff;
+                        padding-right: 15px;
+                        margin-right: 15px;
+                    }
+                }
+                
+            }
+        }
+        .list-box{
+            margin-top: -50px;
+            border-top-left-radius: 40px;
+            border-top-right-radius: 40px;
+            min-height: 100px;
+            background-color: #fff;
+            position: relative;
+            z-index: 2;
+            .item{
+                padding: 50px 34px;
+                border-bottom: 1px solid #E5E5E5;
+                .img{
+                    width: 112px;
+                    height: 112px;
+                    // background-color: #f5f5f5;
+                    flex-shrink: 0;
+                    margin-right: 20px;
+                }
+                .con{
+                    flex: 1;
+                    .title{
+                        font-size: 32px;
+                        color: #57768D;
+                        font-weight: bold;
+                        margin-bottom: 10px;
+                        .tag{
+                            font-size: 20px;
+                            color: #fff;
+                            font-weight: normal;
+                            display: inline-block;
+                            background-color: #1E88E5;
+                            line-height: 37px;
+                            padding: 0 6px;
+                            border-radius: 4px;
+                            margin-left: 10px;
+                        }
+                    }
+                    .sub-title{
+                        color: #999;
+                    }
+                    .update-time{
+                        float: right;
+                        color: #D4D4D4;
+                        font-size: 20px;
+                    }
+                }
+            }
+        }
+        .no-auth-box{
+            text-align: center;
+            font-size: 32px;
+            color: #E3B377;
+            img{
+                width: 100%;
+                margin-bottom: 50px;
+            }
+            .btn{
+                width: 90%;
+                margin-left: auto;
+                margin-right: auto;
+                line-height: 80px;
+                background-color: #E6B77D;
+                border-radius: 4px;
+                color: #fff;
+                margin-top: 100px;
+                display: block;
+            }
+        }
+    }
+}
+</style>

+ 68 - 0
src/views/hzyb/report/components/AudioBox.vue

@@ -0,0 +1,68 @@
+<script setup>
+import {reactive, ref} from 'vue'
+import { Slider } from 'vant';
+import { useStore } from "vuex";
+
+const store=useStore()
+
+const props = defineProps({
+  audioData: Object,
+});
+
+const formatVoiceTime = (e) => {
+  let minus = parseInt(e / 60);
+  let sec = parseInt(e % 60);
+  return `${minus > 9 ? minus : "0" + minus}分${sec > 9 ? sec : "0" + sec}秒`;
+};
+
+const audioIconPlay=new URL('../../../../assets/hzyb/report/audio-play.png', import.meta.url).href
+const audioIconPause=new URL('../../../../assets/hzyb/report/audio-pause.png', import.meta.url).href
+
+
+const handleClickAudio=()=>{
+    if(store.state.hzyb.audioData.url==props.audioData.video_url){
+      if(store.state.hzyb.audioData.paused){
+        store.state.hzyb.audioData.INS.play()
+      }else{
+        store.state.hzyb.audioData.INS.pause()
+      }
+    }else{
+        store.commit('hzyb/addAudio',props.audioData)
+    }
+}
+
+
+</script>
+
+<template>
+  <div class="flex audio-wrap">
+    <img style="opacity: 0.3" src="@/assets/hzyb/report/audio-pause.png" mode="aspectFill" v-if="!audioData.auth_ok" />
+    <img :src="$store.state.hzyb.audioData.url==audioData.video_url&&!$store.state.hzyb.audioData.paused?audioIconPlay:audioIconPause" @click="handleClickAudio" v-else />
+    <div style="flex:1;overflow:hidden">
+      <div class="van-multi-ellipsis--l2">{{ audioData.video_name }}</div>
+      <div style="color: #999999">{{ formatVoiceTime(audioData.video_play_seconds) }}</div>
+    </div>
+  </div>
+</template>
+
+<style lang="scss" scoped>
+.flex{
+    display: flex;
+}
+.audio-wrap {
+  height: 160px;
+  background: #faf7ee;
+  border-radius: 16px;
+  margin-top: 20px;
+  padding: 10px 31px;
+  margin-bottom: 31px;
+  align-items: center;
+  img {
+    width: 110px;
+    height: 110px;
+    display: block;
+    margin-right: 16px;
+    flex-shrink: 0;
+  }
+}
+</style>