Browse Source

Merge branch 'master' into iframe_dev

bding 1 year ago
parent
commit
050418c94f

+ 1 - 0
package.json

@@ -20,6 +20,7 @@
     "normalize.css": "^8.0.1",
     "vant": "^3.3.4",
     "vue": "^3.2.16",
+    "vue-pdf-embed": "^1.1.6",
     "vue-router": "^4.0.12",
     "vuex": "^4.0.2"
   },

+ 6 - 1
src/api/ssbg/http.js

@@ -35,7 +35,12 @@ _axios.interceptors.request.use(
 _axios.interceptors.response.use(
   function (response) {
     // Do something with response data
-    
+    if(response.data.code===403){
+      wx.miniProgram.reLaunch({
+        url:"/pages/login/login"
+      })
+      return
+    }
     return response.data;
   },
   function (error) {

BIN
src/assets/hzyb/chart/calendar-new-1.png


BIN
src/assets/hzyb/chart/more.png


BIN
src/assets/hzyb/chart/search-new-1.png


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

@@ -61,6 +61,11 @@ export const hzybRoutes=[
                 name:"hzybChapterDetail",
                 component: () => import("@/views/hzyb/report/ChapterDetail.vue"),
             },
+            {
+                path:"previewpdf",
+                name:"hzybPreviewPDF",
+                component:() => import("@/views/hzyb/report/PreviewPDF.vue")
+            }
         ]
     }
 ]

+ 191 - 55
src/views/hzyb/chart/Detail.vue

@@ -3,7 +3,7 @@ import chartBox from './component/chartBox.vue'
 import noAuth from './component/noAuth.vue'
 import sharePoster from '../components/SharePoster.vue'
 import collectBox from './component/collectBox.vue'
-import { Popup, Toast,Picker,Icon } from 'vant';
+import { Popup, Toast,Picker,Icon,Tab,Tabs,ActionSheet} from 'vant';
 import {ref,onMounted, reactive, watch,computed,nextTick} from 'vue'
 import {useRoute, useRouter,onBeforeRouteUpdate} from 'vue-router'
 import moment from 'moment'
@@ -90,9 +90,32 @@ getUserInfo()
 let showDate=ref(false)
 let startDate=ref('')
 let endDate=ref('')
-let columns=ref([])
+// 开始-结束时间picker相关信息
+const pickerInfo=reactive({
+    tabIndex:'1'
+})
+// picker使用数据
+const dateRange=[]
+const DateConfirm=(data,dateType)=>{
+    if(dateType=='start'){
+        if(resData.value.ChartInfo.ChartType===2){
+            dateRange[0]=data[0]
+        }else{
+            dateRange[0]=data[0]+'-'+data[1]
+        }
+    }else{
+        if(resData.value.ChartInfo.ChartType===2){
+            dateRange[1]=data[0]
+        }else{
+            dateRange[1]=data[0]+'-'+data[1]
+        }
+    }
+}
+
+let columnsStart=ref([])
+let columnsEnd=ref([])
 // type 1:年-月 2:年
-const makeTimeData=(type)=>{
+const makeTimeData=(type,dateType)=>{
     let curYear=new Date().getFullYear()
     let yearArr=[]
     let monthArr=[]
@@ -102,45 +125,46 @@ const makeTimeData=(type)=>{
     for (let i = 1; i < 13; i++) {
         monthArr.push(i<10?'0'+i:i.toString())
     }
+    const date = dateType=='start'?startDate:endDate
     if(type==1){
-        let index1=yearArr.indexOf(startDate.value.split('-')[0])
-        let index2=monthArr.indexOf(startDate.value.split('-')[1])
-        let index3=yearArr.indexOf(endDate.value.split('-')[0])
-        let index4=monthArr.indexOf(endDate.value.split('-')[1])
+        let index1=yearArr.indexOf(date.value.split('-')[0])
+        let index2=monthArr.indexOf(date.value.split('-')[1])
         return [
             {values:yearArr,defaultIndex: index1>-1?index1:yearArr.length-1},
-            {values:monthArr,defaultIndex: index2>-1?index2:monthArr.length-1},
-            {values:yearArr,defaultIndex: index3>-1?index3:yearArr.length-1},
-            {values:monthArr,defaultIndex: index4>-1?index4:monthArr.length-1}
+            {values:monthArr,defaultIndex: index2>-1?index2:monthArr.length-1}
         ]
     }else{
-        let index1=yearArr.indexOf(startDate.value)
-        let index2=yearArr.indexOf(endDate.value)
+        let index1=yearArr.indexOf(date)
         return [
-            {values:yearArr,defaultIndex: index1>-1?index1:yearArr.length-1},
-            {values:yearArr,defaultIndex: index2>-1?index2:yearArr.length-1}
+            {values:yearArr,defaultIndex: index1>-1?index1:yearArr.length-1}
         ]
     }
 }
 const handleShowDate=()=>{
     // if(columns.value.length===0){
         if( sameOptionType.value.includes(resData.value.ChartInfo.ChartType)){//曲线图
-            columns.value=makeTimeData(1)
+            columnsStart.value=makeTimeData(1,'start')
+            columnsEnd.value=makeTimeData(1,'end')
         }else if(resData.value.ChartInfo.ChartType===2){//季节性图表
-            columns.value=makeTimeData(2)
+            columnsStart.value=makeTimeData(2,'start')
+            columnsEnd.value=makeTimeData(2,'end')
         }
     // }
     showDate.value=true
 }
+const startPicker=ref(null)
+const endPicker=ref(null)
+
 // 确定选择时间
-const handleConfirmDate=(e)=>{
+const handleConfirmDate=()=>{
+    startPicker.value.confirm()
+    endPicker.value.confirm()
+    
     let start='',end=''
-    if(sameOptionType.value.includes(resData.value.ChartInfo.ChartType)){
-        start=e[0]+'-'+e[1]
-        end=e[2]+'-'+e[3]
-    }else if(resData.value.ChartInfo.ChartType===2){
-        start=e[0]
-        end=e[1]
+    if(sameOptionType.value.includes(resData.value.ChartInfo.ChartType)
+    || resData.value.ChartInfo.ChartType===2){
+        start=dateRange[0]
+        end=dateRange[1]
     }
     if(new Date(end)>=new Date(start)){
         startDate.value=start
@@ -153,6 +177,20 @@ const handleConfirmDate=(e)=>{
     }
 }
 
+const actionSheetShow=ref(false)
+const actions=computed(()=>{
+    return canSave.value&&![3,4,6,7,8,9].includes(chartSource)?[{ name: '刷新' },{ name: '保存' },{ name: '生成海报' }]:
+                            [{ name: '刷新' },{ name: '生成海报' }]
+})
+const onActionSelect=(action,index)=>{
+    if(action.name=='刷新'){
+        handleRefreshChart()
+    }else if(action.name=='保存'){
+        handleSaveChart()
+    }else if(action.name=='生成海报'){
+        $('.share-poster-wrap div')[0].click()
+    }
+}
 // 选择年份时间段
 let dateTypeList=ref([
     {
@@ -2129,7 +2167,22 @@ const posterParams=computed(()=>{
 
 /* 折叠source */
 const sourceColl = ref(false)
-
+const sourceIconShow=ref(null)
+let timer = null
+let count = 0
+onMounted(()=>{
+    timer=setInterval(()=>{
+        count++
+        if($('.source-item')[0]){
+            // 就为了判断是否显示折叠icon
+            sourceIconShow.value = $('.source-item')[0].offsetHeight>=$('.source-box')[0].offsetHeight
+            clearInterval(timer)
+        }else if(count>=30){
+            // 预防
+            clearInterval(timer)
+        }
+    },100)
+})
 
 // 获取我的图库中切换上一张下一张的数据
 let myChartPageChangeList=ref([])
@@ -2182,13 +2235,14 @@ const myChartPageChange=(type)=>{
     <div class="chart-detail" v-if="!loading&&!noauth&&!nodata">
         <div class="chart-title">{{resData.ChartInfo.ChartName}}</div>
         <div class="top-box" v-if="$route.query.source!=='ybxcx_my_chart'">
-            <div class="flex calendar-box" style="float:left" @click="handleShowDate" v-if="![7,10].includes(resData.ChartInfo.ChartType) &&resData.ChartInfo.Source===1">
-                <img src="../../../assets/hzyb/chart/calendar.png" alt="">
+            <div class="flex calendar-box" :style="{'color':startDate?'#1F243A':'#999999'}"
+            @click="handleShowDate" v-if="![7,10].includes(resData.ChartInfo.ChartType) &&resData.ChartInfo.Source===1">
+                <img src="../../../assets/hzyb/chart/calendar-new-1.png" alt="">
                 <span class="date">{{startDate||'开始日期'}}</span>
-                <span style="margin:0 5px"></span>
+                <span style="margin:0 5px">-</span>
                 <span class="date">{{endDate||'结束日期'}}</span>
             </div>
-            <img class="icon" src="../../../assets/hzyb/chart/search.png" alt="" @click="handleGoSearch">
+            <img class="icon search-icon" src="../../../assets/hzyb/chart/search-new-1.png" alt="" @click="handleGoSearch">
             <share-poster 
                 :isSlot="true"
                 :shareData="{
@@ -2198,10 +2252,13 @@ const myChartPageChange=(type)=>{
                     data:posterParams
                 }"
             >
-                <img class="icon" src="@/assets/hzyb/share-poster-chart-icon.png" alt="">
+                <!-- <img class="icon" src="@/assets/hzyb/share-poster-chart-icon.png" alt=""> -->
             </share-poster>
-            <img class="icon" src="../../../assets/hzyb/chart/save.png" alt="" @click="handleSaveChart" v-if="canSave&&![3,4,6,7,8,9].includes(chartSource)">
-            <img class="icon" src="../../../assets/hzyb/chart/refresh.png" alt="" @click="handleRefreshChart">
+            <!-- <img class="icon" src="../../../assets/hzyb/chart/save.png" alt="" @click="handleSaveChart" v-if="canSave&&![3,4,6,7,8,9].includes(chartSource)">
+            <img class="icon" src="../../../assets/hzyb/chart/refresh.png" alt="" @click="handleRefreshChart"> -->
+            <img class="icon" src="../../../assets/hzyb/chart/more.png" alt="" @click="actionSheetShow=true">
+            <ActionSheet v-model:show="actionSheetShow" cancel-text="确定" :actions="actions" 
+            @select="onActionSelect" close-on-click-action />
         </div>
         
         <collectBox 
@@ -2213,8 +2270,9 @@ const myChartPageChange=(type)=>{
         <chartBox :options='chartData' v-if="!loading"></chartBox>
 
         <div :class="['source-box',{'un-coll-sty':sourceColl,'coll-sty': !sourceColl}]" v-if="$route.query.source=='ybxcx_my_chart'">
-            来源:{{resData&&resData.ChartInfo.ChartSource}}
-            <Icon :name="sourceColl?'arrow-up':'arrow-down'" class="slide-icon" @click="sourceColl=!sourceColl"/>
+            <span class="source-item">来源:{{resData&&resData.ChartInfo.ChartSource}}</span>
+            <Icon :name="sourceColl?'arrow-up':'arrow-down'" class="slide-icon" v-if="sourceIconShow"
+            @click="sourceColl=!sourceColl"/>
         </div>
 
         <template v-if="$route.query.source!=='ybxcx_my_chart'">
@@ -2227,8 +2285,9 @@ const myChartPageChange=(type)=>{
             <span style="color:#E3B377;flex:1;text-align:right" @click="showLimit=true" v-if="![3,4,6,7,8,9].includes(resData.ChartInfo.Source)">上下限设置</span>
         </div>
         <div :class="['source-box',{'un-coll-sty':sourceColl,'coll-sty': !sourceColl}]">
-            来源:{{resData&&resData.ChartInfo.ChartSource}}
-            <Icon :name="sourceColl?'arrow-up':'arrow-down'" class="slide-icon" @click="sourceColl=!sourceColl"/>
+            <span class="source-item">来源:{{resData&&resData.ChartInfo.ChartSource}}</span>
+            <Icon :name="sourceColl?'arrow-up':'arrow-down'" class="slide-icon" v-if="sourceIconShow"
+            @click="sourceColl=!sourceColl"/>
         </div>
 
         <!-- 日期类型 -->
@@ -2242,9 +2301,10 @@ const myChartPageChange=(type)=>{
         </div>
 
         <!-- 最新值 -->
-        <div class="latest-value-wrap" v-if="resData&&resData.ChartInfo.Source===1">
-            <p style="margin-bottom:10px">最新数值</p>
-            <ul class="list" v-if="sameOptionType.includes(resData.ChartInfo.ChartType)">
+        <div class="latest-value-wrap" v-if="resData&&resData.ChartInfo.Source===1" 
+        :class="{'marginTopZone': sameOptionType.includes(resData.ChartInfo.ChartType)}">
+            <!-- <p style="margin-bottom:10px">最新数值</p> -->
+            <ul class="list same-option-type-list" v-if="sameOptionType.includes(resData.ChartInfo.ChartType)">
                 <li v-for="item in chartData.series" :key="item.name">
                     <p style="color:#333">{{moment(item.LatestDate).format('YYYY-MM-DD')}}</p>
                     <p :style="{color:item.color,flex:1}">{{item.name.length>20?item.name.replace(/<br>/g,''):item.name}}</p>
@@ -2295,17 +2355,37 @@ const myChartPageChange=(type)=>{
         </div>
 
         <!-- 日期选择 -->
+        <!-- 属于同个弹窗多个picker选择多个值,vant4.0以上有 现成组件替换
+            这个项目涉及到多个项目,升级vant4.0的兼容处理难于调试
+            这里暂时使用多个组件自定义,后续有更新至vant4.0,可以进行修改 -->
         <Popup
             v-model:show="showDate"
             position="bottom"
             round
         >   
-            <Picker 
-                title="" 
-                :columns="columns" 
-                @cancel="showDate=false" 
-                @confirm="handleConfirmDate" 
-            />
+            <div class="custom-popup-top">
+                <div class="popup-top-item popup-top-cancel">
+                    <span @click="showDate=false">取消</span>
+                </div>
+                <div class="popup-top-item popup-top-title">
+                    {{ pickerInfo.tabIndex==1?'选择起始时间':'选择结束时间' }}
+                </div>
+                <div class="popup-top-item popup-top-confirm">
+                    <span @click="handleConfirmDate">确认</span>
+                </div>
+            </div>
+            <Tabs color="#E3B377" v-model:active="pickerInfo.tabIndex"
+            line-width="16px" border swipeable title-active-color="#E3B377"
+            title-inactive-color="#333333">
+                <Tab title="开始时间" name="1">
+                    <Picker ref="startPicker" @confirm="e=> DateConfirm(e,'start')" 
+                        :columns="columnsStart" :show-toolbar="false"/>
+                </Tab>
+                <Tab title="结束时间" name="2">
+                    <Picker ref="endPicker" @confirm="e=> DateConfirm(e,'end')" 
+                        :columns="columnsEnd" :show-toolbar="false"/>
+                </Tab>
+            </Tabs>
         </Popup>
 
         <!-- 上下限设置 -->
@@ -2419,33 +2499,42 @@ const myChartPageChange=(type)=>{
         }
     }
     .top-box{
-        padding: 20px 34px 40px 34px;
-        height: 40px;
+        padding: 0 34px 0 34px;
+        // height: 40px;
+        display: flex;
+        align-items: center;
         .calendar-box{
             align-items: center;
+            background-color:#F6F6F6 ;
+            padding: 11px 30px;
+            border-radius: 99px;
+            width: 466px;
             img{
-                width: 40px;
-                height: 40px;
+                width: 48px;
+                height: 48px;
                 margin-right: 18px;
             }
             .date{
                 width: 128px;
                 height: 40px;
-                background: #F6F6F6;
-                border: 1px solid #E5E5E5;
+                // background: #F6F6F6;
+                // border: 1px solid #E5E5E5;
                 border-radius: 4px;
                 text-align: center;
                 line-height: 44px;
                 font-size: 24px;
-                color: #1F243A;
+                // color: #1F243A;
             }
         }
         .icon{
-            float: right;
-            width: 40px;
-            height: 40px;
+            // float: right;
+            width: 70px;
+            height: 70px;
             margin-left: 30px;
         }
+        .search-icon{
+            margin-left: 40px;
+        }
     }
     .select-date-box-head{
         padding: 40px 34px;
@@ -2577,8 +2666,17 @@ const myChartPageChange=(type)=>{
                 border-right: none !important;
             }
         }
+        .same-option-type-list{
+            li{
+                &:first-child{
+                    border-top: none;
+                }
+            }
+        }
+    }
+    .marginTopZone{
+        margin-top: 0;
     }
-
     .set-limit-box{
         min-height: 450px;
         padding-top: 5px;
@@ -2628,5 +2726,43 @@ const myChartPageChange=(type)=>{
         }
 
     }
+    .custom-popup-top{
+        height: 88px;
+        width: 100%;
+        display: flex;
+        align-items: center;
+        justify-content: space-between;
+        flex-wrap: nowrap;
+        .popup-top-item{
+            height: 100%;
+            padding: 0 32px;
+            display: flex;
+            align-items: center;
+        }
+        .popup-top-cancel{
+            font-weight: 400;
+            font-size: 32px;
+            color: #666666;
+        }
+        .popup-top-title{
+            font-weight: 600;
+            font-size: 36px;
+            color: #333333;
+        }
+        .popup-top-confirm{
+            font-weight: 400;
+            font-size: 32px;
+            color: #E3B377;
+        }
+    }
+}
+::v-deep(.van-tab) {
+    flex: none;
+    padding: 0 32px;
 }
+::v-deep(.van-action-sheet__item) {
+    border-bottom: solid 1px #E7E7E7;
+}
+
+
 </style>

+ 121 - 0
src/views/hzyb/report/PreviewPDF.vue

@@ -0,0 +1,121 @@
+<script setup>
+import { useRoute } from 'vue-router';
+import { ref,onMounted } from "vue";
+import VuePdfEmbed from "vue-pdf-embed";
+import {Toast,Dialog} from 'vant';
+import {apiUserInfo} from '@/api/hzyb/user'
+const route = useRoute();
+localStorage.setItem('hzyb-token',route.query.token)
+document.title='PDF报告'
+const pdfSrc = ref('')
+let LOADING = null
+let showHint = ref(false)
+let hasRight = ref(true)
+let userInfo = ref({})
+let hintText = ref('')
+
+
+const loadingFailed = ()=>{
+    LOADING.clear()
+    Toast("加载PDF失败!")
+    showHint.value = true
+}
+const loadedPDF = ()=>{
+    LOADING.clear()
+    showHint.value = false
+    hintText.value = ''
+}
+
+const checkRight = async()=>{
+    const res = await apiUserInfo({Authorization: localStorage.getItem('hzyb-token')})
+    if(res.code!==200) return 
+    userInfo.value = res.data
+    if(['试用','正式','永续'].includes(res.data.status)){
+        hasRight.value = true
+        LOADING = Toast.loading({
+            message: "正在加载PDF",
+            duration: 0,
+            forbidClick: true,
+        });
+        pdfSrc.value = route.query.pdfSrc ||''
+        if(!pdfSrc.value.length){
+            hintText.value = '获取PDF失败'
+        }
+    }else{
+        LOADING&&LOADING.clear()
+        hasRight.value = false
+    }
+}
+
+const handleGoApply = ()=>{
+    if(userInfo.value.is_bind===0){
+        Dialog.confirm({
+            title:'温馨提示',
+            message:'为了优化您的用户体验,\n 请登录后查看更多信息!',
+            confirmButtonText:'去登录',
+            confirmButtonColor:'#E6B77D',
+            cancelButtonColor:'#666'
+        }).then(res=>{
+            wx.miniProgram.reLaunch({url:'/pages/login'})
+        })
+        return
+    }
+    wx.miniProgram.redirectTo({
+        url:"/pages-applyPermission/applyPermission?source=4&from_page=PDF报告"
+    })
+}
+
+onMounted(()=>{
+    checkRight()
+})
+</script>
+
+<template>
+    <div class="preview-pdf-wrap">
+        <!-- 无权限 -->
+        <div class="no-auth-box" v-if="!hasRight">
+            <img class="img" src="https://hzstatic.hzinsights.com/static/icon/hzyb/activity_no_auth.png" mode="widthFix" />
+            <div class="apply-box">
+                <div>您暂无权限查看报告,若想查看请申请开通</div>
+                <div class="btn" @click="handleGoApply">立即申请</div>
+            </div>
+        </div>
+        <template v-else-if="pdfSrc.length">
+            <vue-pdf-embed :source="pdfSrc" @loading-failed="loadingFailed" @loaded="loadedPDF"/>
+            <p v-if="showHint" class="hint">加载pdf失败</p>
+        </template>
+        <template v-else>
+            <p class="hint">{{hintText}}</p>
+        </template>
+    </div>
+</template>
+
+<style lang="scss" scoped>
+.preview-pdf-wrap{
+    .hint{
+        margin-top:100px;
+        text-align:center;
+        color:#999;
+    }
+    .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>