فهرست منبع

Merge branch 'ETA2.5.4'

cldu 4 هفته پیش
والد
کامیت
60c1b15712

+ 29 - 0
src/CustomElement/EtaDisclaime.ce.vue

@@ -0,0 +1,29 @@
+<script setup>
+import { ref } from 'vue';
+import { getDisclaimer } from './api/getData.js';
+
+const props = defineProps({
+    type:'zh',  // zh  en
+})
+const disclaimer = ref('');
+
+async function getDis(){
+    const res = await getDisclaimer();
+    if(res.Ret != 200) return;
+    disclaimer.value = props.type == 'en' ? res.Data.DisclaimerEn : res.Data.Disclaimer
+}
+
+getDis();
+
+</script>
+
+<template>
+   <div style="font-size: 14px;">
+      <div style="margin-bottom: 4px;">{{ props.type == 'en' ? 'Disclaimers' : '免责声明' }}:</div>
+      <div v-html="disclaimer"></div>
+   </div>
+</template>
+
+<style lang='less' scoped>
+
+</style>

+ 8 - 0
src/CustomElement/api/getData.js

@@ -25,4 +25,12 @@ export const forumChartInfoByCode=params=>{
 */
 export const infoByCode=params=>{
     return post('/excel/detail',params)
+}
+
+/**
+ * 通过免责声明
+ * @param UniqueCode 
+*/
+export const getDisclaimer=params=>{
+  return post('/common/disclaimer',params)
 }

+ 3 - 0
src/CustomElement/index.js

@@ -1,11 +1,14 @@
 import { defineCustomElement } from 'vue';
 import EtaChartComp from './EtaChart.ce.vue';
 import EtaTableComp from './EtaTable.ce.vue'
+import EtaDisclaimeComp from './EtaDisclaime.ce.vue';
 
 const EtaChart = defineCustomElement(EtaChartComp);
 const EtaTable = defineCustomElement(EtaTableComp);
+const EtaDisclaime = defineCustomElement(EtaDisclaimeComp);
 
 export function registerEtaComp() {
   customElements.define('eta-chart', EtaChart)
   customElements.define('eta-table', EtaTable)
+  customElements.define('eta-disclaime', EtaDisclaime)
 }

+ 8 - 0
src/router/report.js

@@ -127,4 +127,12 @@ export const reportRoutes=[
             title: "详情页",
         },
     },
+    {
+        path:"/free_report/preview",
+        name:"FreeReportPreview",
+        component: () => import("@/views/report/freeReport/freeReportPreview.vue"),
+        meta: { 
+            title: "详情页",
+        },
+    },
 ]

+ 1 - 2
src/views/externalReport/List.vue

@@ -261,10 +261,9 @@ async function handleChangeReportClassifyCollect(item) {
 
 // 跳转详情
 function goDetail(item){
-    console.log(item);
     if(isRise.value) { //普通报告预览
         router.push({
-            path:"/report/preview",
+            path:item.ReportLayout == 3 ? "/free_report/preview" : "/report/preview",
             query:{
                 id:item.Id
             }

+ 23 - 5
src/views/report/List.vue

@@ -178,7 +178,7 @@ async function handleReportPublish(item){
     activeReportData.value=item
 
     //如果走审批流 直接发布
-    if(isApprove.value){
+    if(isApprove.value || item.ReportLayout == 3){ //自由布局暂时取消推送
         confirmPublish(item)
         return
     }
@@ -445,7 +445,7 @@ function goDetail(item){
     //若没有预览权限,则不跳转
     if(!checkAuthBtn(reportManageBtn.reportManage_reportView)) return 
     router.push({
-        path:"/report/preview",
+        path:item.ReportLayout == 3 ? "/free_report/preview" : "/report/preview",
         query:{
             id:item.Id
         }
@@ -585,6 +585,24 @@ const getSystemInfoFun=()=>{
     })
 }
 
+const handleDownloadPdf = () => {
+    if(activeItem.value && activeItem.value.ReportLayout == 3) {
+        downloadPdfImg(activeItem.value,1)
+    } else {
+        showDownloadPdfImg.value=true;
+        downloadPdfImgType.value='pdf'
+    }
+}
+
+const handleDownloadImg = () => {
+    if(activeItem.value && activeItem.value.ReportLayout == 3) {
+        downloadPdfImg(activeItem.value,2)
+    } else {
+        showDownloadPdfImg.value=true;
+        downloadPdfImgType.value='img'
+    }
+}
+
 onMounted(async ()=>{
     getEtaConfig()
     getSystemInfoFun()
@@ -770,7 +788,7 @@ onMounted(async ()=>{
             -->
             <!-- 未发布,待提交 -->
             <template v-if="[1,3].includes(activeItem.State)">
-                <div class="item" @click="handleReportEdit(activeItem)" v-permission="reportManageBtn.reportManage_reportEdit">编辑</div>
+                <div class="item" @click="handleReportEdit(activeItem)" v-if="checkAuthBtn(reportManageBtn.reportManage_reportEdit)&&activeItem.ReportLayout!=3">编辑</div>
                 <div class="item" v-if="checkAuthBtn(reportManageBtn.reportManage_publish)&&activeItem.State===1"
                     @click="handleReportPublish(activeItem)">发布</div>
                 <div class="item" v-if="checkAuthBtn(reportManageBtn.reportManage_publish)&&activeItem.State===3"
@@ -784,9 +802,9 @@ onMounted(async ()=>{
                 <div class="item" v-if="checkAuthBtn(reportManageBtn.reportManage_cancelPublish)&&activeItem.State===6&&activeItem.HasAuth"
                     @click="handleReportCancel(activeItem)">撤销</div>
                 <div class="item" v-if="checkAuthBtn(reportManageBtn.reportManage_exportPdf) && activeItem.DetailPdfUrl"
-                    @click="showDownloadPdfImg=true;downloadPdfImgType='pdf'">下载pdf</div>
+                    @click="handleDownloadPdf">下载pdf</div>
                 <div class="item" v-if="checkAuthBtn(reportManageBtn.reportManage_exportImg) && activeItem.DetailImgUrl"
-                    @click="showDownloadPdfImg=true;downloadPdfImgType='img'">下载长图</div>
+                    @click="handleDownloadImg">下载长图</div>
                 <div class="item" @click="handldReportMsgSend(activeItem)" v-if="activeItem.MsgIsSend==0&&checkAuthBtn(reportManageBtn.reportManage_sendMsg)&&activeItem.HasAuth">推送消息</div>
             </template>
             <!-- 待审批,已驳回 -->

+ 1 - 1
src/views/report/Search.vue

@@ -63,7 +63,7 @@ function handleSearch(){
 
 function goDetail(item){
     router.push({
-        path:"/report/preview",
+        path:item.ReportLayout == 3 ? "/free_report/preview" : "/report/preview",
         query:{
             id:item.Id
         }

+ 334 - 0
src/views/report/freeReport/freeReportPreview.vue

@@ -0,0 +1,334 @@
+<script setup>
+import { ref , reactive , nextTick , computed , onMounted , onUnmounted } from 'vue'
+import apiReport from '@/api/report'
+import { useRoute, useRouter } from "vue-router";
+import {getSystemInfo,shareGenerate} from '@/api/common'
+import {reportManageBtn,useAuthBtn} from '@/hooks/useAuthBtn'
+import {usePublicSettingStore} from '@/store/modules/publicSetting'
+import vueQr from 'vue-qr/src/packages/vue-qr.vue'
+import {showToast} from 'vant'
+import { copyText } from 'vue3-clipboard'
+
+const route = useRoute();
+const {checkAuthBtn} = useAuthBtn()
+const publicSettingStore = usePublicSettingStore()
+
+const scaleContainer = ref(null);
+const reportId = ref(route.query.id || '');
+const reportInfo = ref({});
+const pageList = ref([]);
+const bgColor = ref('');
+const scaleStyle = ref({ transform: 'scale(1)', transformOrigin: 'top left', width: '1202px' })
+const contentHeight=ref(1000);
+const showImgPop = ref(false);
+const waterMarkStr = ref('')
+let shareUrls=ref(null);
+const pageConfig = ref({
+    pageEditObject:{
+        header:{
+            html:'',
+            noFirstPageShow:false,//首页不显示
+            noAllPageShow:true,//所有页不显示
+        },
+        footer:{
+            html:'',
+            noFirstPageShow:false,//首页不显示
+            noAllPageShow:true,//所有页不显示
+        },
+        page:{
+            align:'center',// 位置
+            noFirstPageShow:false,//首页不显示
+            noAllPageShow:true,//所有页不显示
+        },
+    },
+});
+const layoutBaseInfo = reactive(
+    {
+        研报标题:'',
+        研报作者:'',
+        创建时间:''
+    }
+)
+
+async function getReportDetail(){
+    const res=await apiReport.getReportDetail({ReportId:Number(reportId.value)})
+    if(res.Ret != 200) return;
+    reportInfo.value = res.Data;
+    bgColor.value = reportInfo.value.CanvasColor;
+    layoutBaseInfo['研报标题'] = reportInfo.value.Title
+    layoutBaseInfo['研报作者'] = reportInfo.value.Author
+    layoutBaseInfo['创建时间'] = (reportInfo.value.PublishTime||reportInfo.value.PrePublishTime)
+    pageConfig.value = reportInfo.value.FreeLayoutConfig ? JSON.parse(reportInfo.value.FreeLayoutConfig) || {} : {}
+    pageList.value = reportInfo.value.FreeLayoutContentPages || [];
+    handleSize();
+};
+async function handleSize(){
+    await nextTick();
+    const baseWidth = 1202;
+    const clientWidth = document.documentElement.clientWidth
+    const scale = clientWidth / baseWidth
+
+    const contentEl = scaleContainer.value
+    if (!contentEl) return
+
+    const rawHeight = contentEl.scrollHeight
+
+    scaleStyle.value = {
+        transform: `scale(${scale})`,
+        transformOrigin: 'top left',
+        width: `${baseWidth}px`,
+    }
+    contentHeight.value = rawHeight * scale;
+};
+function showHeaderWrap(item){
+    let result = false;
+    if(pageConfig.value && pageConfig.value.pageEditObject){
+        const pageEditObject = pageConfig.value.pageEditObject;
+        result = !(pageEditObject.header.noAllPageShow || (pageEditObject.header.noFirstPageShow && item.Page <= 1))
+    }
+    return result
+};
+function showFooterMessage(item){
+    let result = false;
+    if(pageConfig.value && pageConfig.value.pageEditObject){
+        const pageEditObject = pageConfig.value.pageEditObject;
+        result = !(pageEditObject.footer.noAllPageShow || (pageEditObject.footer.noFirstPageShow && item.Page <= 1))
+    }
+    return result
+};
+function showFooterPage(item){
+    let result = false;
+    if(pageConfig.value && pageConfig.value.pageEditObject){
+        const pageEditObject = pageConfig.value.pageEditObject;
+        result = !(pageEditObject.page.noAllPageShow || (pageEditObject.page.noFirstPageShow && item.Page <= 1))
+    }
+    return result
+};
+function showFooterWrap(item){
+    const reuslt = !showFooterPage(item) && !showFooterMessage(item) ? false : true;
+    return reuslt
+};
+
+function getPageNumberPosition(data){
+    if(!data) return;
+    if(data == 'left') return `left:0;`;
+    if(data == 'right') return `right:0;`;
+    if(data == 'center') return `left:50%;transform:translateX(-50%);`;
+};
+
+function handleCopyLink(type) {
+    let str=''
+    let url=''
+    const baseUrl= publicSettingStore.publicSetting.ReportViewUrl;
+    if(reportInfo.value.ReportCode){
+        str= `${baseUrl}/reportshare_free_report?code=${reportInfo.value.ReportCode}& ${reportInfo.value.Title}`
+        const params={
+            "Url":str,
+            "ReportId":reportInfo.value.Id
+        } 
+        shareGenerate(params).then(res=>{
+            if(res.Ret===200){
+                if(location.port=='5173'){
+                    url='http://8.136.199.33:8611'
+                }else{
+                    url=location.origin
+                }
+                shareUrls.value=url+'/v1/share/'+res.Data.UrlToken
+
+                if(type==='urcode') {
+                    showImgPop.value=true 
+                }else {
+                    copyText(shareUrls.value,undefined,(error,event)=>{
+                        if(error){
+                            showToast('复制链接失败')
+
+                            throw new Error('复制数据失败'+JSON.stringify(error))
+                        }else{
+                            showToast('复制链接成功')
+                        }
+                    })
+                }
+            }
+        })
+    }
+};
+const shareCodeUrls = computed(() => {
+    let index = shareUrls.value.indexOf(' ');
+    return shareUrls.value.substring(0,index)
+})
+getReportDetail();
+
+const getIframeMessage = (e) => {
+    if(e.data && e.data.height){
+        const { height, code,uid } = e.data;
+        let iframeDom = document.getElementsByClassName(`iframe${uid||code}`);
+        if(iframeDom && iframeDom.length) iframeDom = Array.from(iframeDom);
+        iframeDom && iframeDom.length && iframeDom.forEach((ele) => {
+            ele.height = `${height+2}px`;
+        });
+    }
+};
+const handleHtmlStr = (data) => {
+    const htmlString = data.replace(
+        /class="([^"]*\breport-html-wrap\b[^"]*)"/,
+        (match, p1) => {
+            return `class="${p1.replace('report-html-wrap', 'report-html-wrap-free')}"`;
+        }
+    );
+   return htmlString
+}
+onMounted(() => {
+    window.addEventListener('message',getIframeMessage);
+})
+onUnmounted(() => {
+    window.removeEventListener('message',getIframeMessage)
+})
+</script>
+
+<template>
+    <div class="free-report-scale-outer" :style="{ height: contentHeight + 'px',fontSize:'14px', }">
+        <div class="free-report-detail" ref="scaleContainer" :style="scaleStyle">
+            <div id="reportdtl" class="main-box" style="width: 1202px;">
+                <div v-for="(item,index) in pageList" :key="index + 1" class="report-content-box" :style="{backgroundColor:bgColor,height:'1697px'}">
+                    <!-- 版头 -->
+                    <div class="border-wrap" style="min-height: 30px;max-height: 100px;" v-if="showHeaderWrap(item)">
+                        <div class="page-header-wrap" style="min-height: 30px;max-height: 100px;" v-html="pageConfig.pageEditObject.header.html"></div>
+                    </div>
+                    <div v-html="handleHtmlStr(item.Content)" class="content-wrap"></div>
+                    <div class="border-wrap" style="min-height: 30px;max-height: 100px;" v-if="showFooterWrap(item)">
+                        <div
+                            v-if="showFooterPage(item)"
+                            :style="`position:absolute;bottom:6px;${getPageNumberPosition(pageConfig.pageEditObject.page.align)}`"
+                        >{{ pageConfig.pageEditObject.page.noFirstPageShow ? item.Page - 1 : item.Page }}</div>
+                        <div
+                            v-if="showFooterMessage(item)" 
+                            class="page-header-wrap" 
+                            style="min-height: 30px;max-height: 100px;"
+                            v-html="pageConfig.pageEditObject.footer.html"></div>
+                        </div>
+                </div>
+            </div>
+        </div>
+    </div>
+    <div class="empty-bottom"></div>
+    <van-popup 
+        v-model:show="showImgPop" 
+        round
+    >
+        <vue-qr :text="shareCodeUrls" colorDark="#333" colorLight="#fff" :dotScale="1"></vue-qr>
+    </van-popup>
+    <div class="fix-bot-action-box" v-if="reportInfo&&reportInfo.ClassifyEnabled">
+        <div class="item" @click="handleCopyLink" v-permission="reportManageBtn.reportManage_reportView_copyWechat">
+            <img class="icon" src="@/assets/imgs/report/icon_copy.png" alt="">
+            <div>复制链接</div>
+        </div>
+        <div class="item" @click="handleCopyLink('urcode')" v-permission="reportManageBtn.reportManage_reportView_wechartShare">
+            <img class="icon" src="@/assets/imgs/report/icon_wx_black.png" alt="">
+            <div>微信分享</div>
+        </div>
+    </div>
+</template>
+
+<style lang="scss">
+p[data-f-id="pbf"] {
+  display: none;
+}
+div{
+      box-sizing: border-box;
+  }
+  .free-report-scale-outer{
+    position: relative;
+    overflow: hidden;
+    line-height: normal;
+    font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB,
+       Microsoft YaHei, SimSun, sans-serif;
+  }
+  .free-report-detail{
+    position: absolute;
+    top: 0;
+    left: 0;
+    .main-box{
+        margin: 0 auto;
+        padding: 0;
+        overflow: hidden;
+        position: relative;
+        .report-content-box{
+            margin-bottom: 20px;
+            width:100%;
+            background: #FFF;
+            box-sizing: border-box;
+            overflow: hidden;
+            display: flex;
+            flex-direction: column;
+            position: relative;
+            border: 1px solid #C0C4CC;
+            .content-wrap{
+              flex: 1;
+              display: flex;
+              flex-direction: column;
+              position: relative;
+            }
+            .report-html-wrap-free{
+                height: 100%;
+                position: relative;
+                overflow: hidden;
+                &::after{
+                  content: '';
+                  display: block;
+                }
+            }
+        }
+        .version-wrap{
+          width: 100%;
+          height: 100;
+          overflow: hidden;
+          position: relative;
+          .head-layout-item{
+              position: absolute;
+              overflow: hidden;
+              box-sizing: border-box;
+          }
+      }
+        .border-wrap{
+            position: relative;
+            .page-header-wrap,.page-footer-wrap{
+                overflow: hidden;
+            }
+        }
+    }
+  }
+  .fix-bot-action-box{
+    position: fixed;
+    left: 0;
+    bottom: 0;
+    right: 0;
+    z-index: 99;
+    background-color: #fff;
+    border-top: 1px solid $border-color;
+    height: 112px;
+    display: flex;
+    align-items: center;
+    .item{
+        height: 100%;
+        flex: 1;
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        align-items: center;
+        font-size: 20px;
+        .icon{
+            width: 40px;
+            height: 40px;
+            margin-bottom: 5px;
+        }
+    }
+}
+.empty-bottom{
+    margin-bottom: 114px;
+}
+@media screen and (max-width:1200px){
+  #reportdtl{
+    width: 100%;
+  }
+}
+</style>