فهرست منبع

智能章节报告设置版图;报告发布提交hooks统一

Karsa 8 ماه پیش
والد
کامیت
11fdaeb7db

BIN
src/assets/imgs/report/icon_set.png


+ 10 - 0
src/router/report.js

@@ -71,6 +71,16 @@ export const reportRoutes=[
             hasBackTop:true
         },
     },
+    {
+        path:"/report/chapter/preview",
+        name:"ReportChapterDetail",
+        component: () => import("@/views/report/chapter/Preview.vue"),
+        meta: { 
+            title: "中文研报",
+            keepAlive:false,
+            hasBackTop:true
+        },
+    },
     {
         path:"/report/search",
         name:"ReportSearch",

+ 5 - 141
src/views/report/EditReport.vue

@@ -13,7 +13,6 @@ import {useCachedViewsStore} from '@/store/modules/cachedViews'
 import {usePublicSettingStore} from '@/store/modules/publicSetting'
 import {reportManageBtn,useAuthBtn} from '@/hooks/useAuthBtn'
 import {useReportApprove} from '@/hooks/useReportApprove'
-import {Base64} from 'js-base64'
 import AddReportBaseInfoV2 from './components/AddReportBaseInfoV2.vue'
 import { useReportHandles } from './hooks/useReport'
 
@@ -27,11 +26,10 @@ const {checkAuthBtn} = useAuthBtn()
 const {lastFocusPosition,initFroalaEditor,imgUploadFlag,frolaEditorContentChange}=useInitFroalaEditor()
 let reportContentEditorIns=null//报告内容编辑器实例
 
-const { handleRefresh,handleSubmitReport } = useReportHandles()
+
+const { handleRefresh,handlePublishReportHook,handleDSPublish,showDSFBTime } = useReportHandles()
 
 let autoSaveTimer=null
-// 水印
-const waterMarkStr=ref('')
 
 onMounted(() => {
     const el=document.getElementById('editor')
@@ -41,7 +39,6 @@ onMounted(() => {
     autoSaveTimer=setInterval(() => {
         autoSaveReportContent()
     }, 6000);
-    getSystemInfoFun()
 })
 onUnmounted(()=>{
     clearInterval(autoSaveTimer)
@@ -241,152 +238,19 @@ async function handlePublishReport(tp) {
     const saveRes = await autoSaveReportContent('auto');
     if(!saveRes) return
 
-    if(tp==='dsfb'){
-        showDSFBTime.value=true
-		return
-    }else if(tp==='submit'){
-        handleSubmitReport({id:Number(route.query.id)})
-        return
-    }
-
-    let sendMsg = reportData.value.MsgIsSend;
-    if(sendMsg===1){
-        reportPublish({sendMsg: false})
-    }else {
-        const isPost = checkAuthBtn(reportManageBtn.reportManage_sendMsg)
-
-        showDialog({
-            title: '发布提示',
-            showCancelButton: true,
-            message: isPost?'发布后,是否推送模板消息?':'是否立即发布报告?',
-            confirmButtonText: isPost?'推送':'发布',
-            cancelButtonText: isPost?'不推送':'取消',      
-        }).then(() => {
-            reportPublish({sendMsg: isPost?true:false})
-        })
-        .catch(() => {
-            if(isPost) reportPublish({sendMsg: false});
-        });
-
-    }
-}
-
-
-function generatePdfLinks(){
-    let code = reportData.value.ReportCode
-
-    return `${publicSettingStore.publicSetting.ReportViewUrl}/reportshare_pdf?code=${code}&flag=${waterMarkStr.value}`
+    handlePublishReportHook(tp,reportData.value)
 }
 
-async function reportPublish({sendMsg}){
-    const res=await apiReport.reportPublish({ReportIds:String(route.query.id),ReportUrl:generatePdfLinks()})
-    if(res.Ret===200){
-        sendMsg && apiReport.reportMessageSend({ReportId: Number(route.query.id)})
-
-        showToast('发布成功')
-        console.log('back');
-        setTimeout(() => {
-            router.back()
-        },1000)
-    }
-}
 
 // 定时发布报告选择时间
-const showDSFBTime=ref(false)
 function onConfirmDSFBTime(time){
-    console.log(time);
-    if(reportData.value.MsgIsSend===1){//已经推送过了
-        apiReport.reportPublishTimeSet({
-            ReportId:reportData.value.Id,
-            PrePublishTime:time,
-            PreMsgSend:0,
-            ReportUrl:generatePdfLinks()
-        }).then(res=>{
-            if(res.Ret===200){
-                showToast('定时发布成功!')
-                setTimeout(() => {
-                    router.back()
-                }, 1000);
-            }
-        })
-        return
-    }
-    const isAuthPushMsg=checkAuthBtn(reportManageBtn.reportManage_sendMsg)
-    showDialog({
-        title: '提示',
-        message:isAuthPushMsg?'是否发布定时报告,并推送模板消息?':'是否发布定时报告',
-        confirmButtonText:isAuthPushMsg?'推送':'确定',
-        cancelButtonText:isAuthPushMsg?'不推送':'取消',
-        showCancelButton:true
-    }).then(()=>{
-        if(!isAuthPushMsg){
-            apiReport.reportPublishTimeSet({
-                ReportId:reportData.value.Id,
-                PrePublishTime:time,
-                PreMsgSend:0,
-                ReportUrl:generatePdfLinks()
-            }).then(res=>{
-                if(res.Ret===200){
-                    showToast('定时发布成功!')
-                    setTimeout(() => {
-                        router.back()
-                    }, 1000);
-                }
-            })
-            return
-        }
-        //推送
-        apiReport.reportPublishTimeSet({
-            ReportId:reportData.value.Id,
-            PrePublishTime:time,
-            PreMsgSend:1,
-            ReportUrl:generatePdfLinks()
-        }).then(res=>{
-            if(res.Ret===200){
-                showToast('定时发布成功!')
-                setTimeout(() => {
-                    router.back()
-                }, 1000);
-            }
-        })
-    }).catch(()=>{
-        if(!isAuthPushMsg) return
-        //不推送
-        apiReport.reportPublishTimeSet({
-            ReportId:reportData.value.Id,
-            PrePublishTime:time,
-            PreMsgSend:0,
-            ReportUrl:generatePdfLinks()
-        }).then(res=>{
-            if(res.Ret===200){
-                showToast('定时发布成功!')
-                setTimeout(() => {
-                    router.back()
-                }, 1000);
-            }
-        })
-    })
-}
-
-const getSystemInfoFun=()=>{
-    getSystemInfo().then(res=>{
-        if(res.Ret===200){
-          const systemUserInfo=res.Data
-          // 设置水印文案
-          let waterMarkString=''
-          if(systemUserInfo){
-            waterMarkString=`${systemUserInfo.RealName}${systemUserInfo.Mobile?systemUserInfo.Mobile:systemUserInfo.Email}`
-            waterMarkString=encodeURIComponent(waterMarkString)
-            waterMarkStr.value=Base64.encode(waterMarkString)
-          }
-        }
-    })
+    // console.log(time);
+    handleDSPublish(time,reportData.value)
 }
 </script>
 
 <template>
     <div class="add-report-page">
-        <!-- <van-cell title="基础信息" is-link @click="showReportBaseInfo=true"/> -->
         <div class="main-wrap">
             <div class="editor-box" id="editor"></div>
         </div>

+ 244 - 151
src/views/report/chapter/List.vue

@@ -1,6 +1,7 @@
 <script setup name="reportChapterList">
 import {computed, nextTick, reactive, ref} from 'vue'
 import { useRoute, useRouter } from "vue-router";
+import { V3ColorPicker } from "v3-color-picker-teleport"
 import apiReport from '@/api/report'
 import { apiGetWXQRCodeImg,getSystemInfo } from '@/api/common'
 import moment from 'moment';
@@ -12,13 +13,17 @@ import {usePublicSettingStore} from '@/store/modules/publicSetting'
 import EditBaseInfo from './components/EidtBaseInfo.vue'
 import ReportPublishTimeSet from '../components/ReportPublishTimeSet.vue'
 import html2canvas from "html2canvas";
-import {transfImgTobase64} from '@/hooks/common'
+import {transfImgTobase64,isWeiXin} from '@/hooks/common'
 import draggable from 'vuedraggable'
 import {reportManageBtn,useAuthBtn} from '@/hooks/useAuthBtn'
 import {useReportApprove} from '@/hooks/useReportApprove'
 import AddReportBaseInfoV2 from '../components/AddReportBaseInfoV2.vue'
 import EditChapterBaseInfo from './components/EditChapterBaseInfo.vue'
+import ReportLayoutImg from '../smartReport/components/ReportLayoutImg.vue'
 import { useReportHandles } from '../hooks/useReport'
+import AudioBox from '../components/AudioBox.vue'
+import {useUploadFileToOSS} from '@/hooks/useUploadFileToOSS'
+import MD5 from 'js-md5'
 
 const cachedViewsStore=useCachedViewsStore()
 const publicSettingStore = usePublicSettingStore()
@@ -128,25 +133,6 @@ async function getChapterList(){
 }
 
 
-// 水印
-const waterMarkStr=ref('')
-function getSystemInfoFun(){
-    getSystemInfo().then(res=>{
-        if(res.Ret===200){
-          const systemUserInfo=res.Data
-          // 设置水印文案
-          let waterMarkString=''
-          if(systemUserInfo){
-            waterMarkString=`${systemUserInfo.RealName}${systemUserInfo.Mobile?systemUserInfo.Mobile:systemUserInfo.Email}`
-            waterMarkString=encodeURIComponent(waterMarkString)
-            waterMarkStr.value=Base64.encode(waterMarkString)
-          }
-        }
-    })
-}
-getSystemInfoFun()
-
-
 /* 章节操作弹窗 */
 const showItemOpt = ref(false)
 const activeItem = ref(null)
@@ -169,7 +155,7 @@ function handleChapterBaseInfoSave() {
 }
 
 
-const { handleSubmitReport } = useReportHandles()
+const { handlePublishReportHook,handleDSPublish,showDSFBTime } = useReportHandles()
 /* 发布报告 */
 async function  handlePublishReportCheck(tp) {
     //校验章节是否都已发布
@@ -188,130 +174,14 @@ async function  handlePublishReportCheck(tp) {
 async function handlePublishReport(tp) {
     cachedViewsStore.removeCaches('ReportList')
 
-    if(tp==='dsfb'){
-        showDSFBTime.value=true
-		return
-    }else if(tp==='submit'){
-        handleSubmitReport({id:Number(route.query.id)})
-        return
-    }
-
-    let sendMsg = reportInfo.value.MsgIsSend;
-    if(sendMsg===1){
-        reportPublish({sendMsg: false})
-    }else {
-        const isPost = checkAuthBtn(reportManageBtn.reportManage_sendMsg)
-
-        showDialog({
-            title: '发布提示',
-            showCancelButton: true,
-            message: isPost?'发布后,是否推送模板消息?':'是否立即发布报告?',
-            confirmButtonText: isPost?'推送':'发布',
-            cancelButtonText: isPost?'不推送':'取消',      
-        }).then(() => {
-            reportPublish({sendMsg: isPost?true:false})
-        })
-        .catch(() => {
-            if(isPost) reportPublish({sendMsg: false});
-        });
-
-    }
-}
-
-async function reportPublish({sendMsg}){
-    const res=await apiReport.reportPublish({ReportIds:String(route.query.id),ReportUrl:generatePdfLinks()})
-    if(res.Ret===200){
-        sendMsg && apiReport.reportMessageSend({ReportId: Number(route.query.id)})
-
-        showToast('发布成功')
-        console.log('back');
-        setTimeout(() => {
-            router.back()
-        },1000)
-    }
-}
-function generatePdfLinks(){
-    let code = reportInfo.value.ReportCode
-
-    return `${publicSettingStore.publicSetting.ReportViewUrl}/reportshare_pdf?code=${code}&flag=${waterMarkStr.value}`
+    handlePublishReportHook(tp,reportInfo.value)
 }
 
 
 // 定时发布报告选择时间
-const showDSFBTime=ref(false)
 function onConfirmDSFBTime(time){
 
-    if(reportInfo.value.MsgIsSend===1){//已经推送过了
-        apiReport.reportPublishTimeSet({
-            ReportId:reportInfo.value.Id,
-            PrePublishTime:time,
-            PreMsgSend:0,
-            ReportUrl:generatePdfLinks()
-        }).then(res=>{
-            if(res.Ret===200){
-                showToast('定时发布成功!')
-                setTimeout(() => {
-                    router.back()
-                }, 1000);
-            }
-        })
-        return
-    }
-    const isAuthPushMsg=checkAuthBtn(reportManageBtn.reportManage_sendMsg)
-    showDialog({
-        title: '提示',
-        message:isAuthPushMsg?'是否发布定时报告,并推送模板消息?':'是否发布定时报告',
-        confirmButtonText:isAuthPushMsg?'推送':'确定',
-        cancelButtonText:isAuthPushMsg?'不推送':'取消',
-        showCancelButton:true
-    }).then(()=>{
-        if(!isAuthPushMsg){
-            apiReport.reportPublishTimeSet({
-                ReportId:reportInfo.value.Id,
-                PrePublishTime:time,
-                PreMsgSend:0,
-                ReportUrl:generatePdfLinks()
-            }).then(res=>{
-                if(res.Ret===200){
-                    showToast('定时发布成功!')
-                    setTimeout(() => {
-                        router.back()
-                    }, 1000);
-                }
-            })
-            return
-        }
-        //推送
-        apiReport.reportPublishTimeSet({
-            ReportId:reportInfo.value.Id,
-            PrePublishTime:time,
-            PreMsgSend:1,
-            ReportUrl:generatePdfLinks()
-        }).then(res=>{
-            if(res.Ret===200){
-                showToast('定时发布成功!')
-                setTimeout(() => {
-                    router.back()
-                }, 1000);
-            }
-        })
-    }).catch(()=>{
-        if(!isAuthPushMsg) return
-        //不推送
-        apiReport.reportPublishTimeSet({
-            ReportId:reportInfo.value.Id,
-            PrePublishTime:time,
-            PreMsgSend:0,
-            ReportUrl:generatePdfLinks()
-        }).then(res=>{
-            if(res.Ret===200){
-                showToast('定时发布成功!')
-                setTimeout(() => {
-                    router.back()
-                }, 1000);
-            }
-        })
-    })
+    handleDSPublish(time,reportInfo.value)
 }
 
 /* 预览报告 */
@@ -347,8 +217,71 @@ function handleDelChapter(item) {
 }
 
 /* 上传章节音频 */
-function handleUploadChapterAudio(item) {
-    showItemOpt.value = false
+// 上传音频
+const showUploadAudio=ref(false)
+const temAudioData=reactive({
+    time:0,
+    size:0,
+    url:'',
+})
+function handleShowUploadAudio(){
+    temAudioData.time=activeItem.value.audioDuration
+    temAudioData.size=activeItem.value.audioSize
+    temAudioData.url=activeItem.value.audioUrl
+    showUploadAudio.value=true
+}
+// 获取音频时长
+function handleGetAudioDuration(file){
+    return new Promise((resolve,reject)=>{
+        if(isWeiXin()){
+            console.log('微信?');
+            resolve(0)
+        }
+
+        const fileUrl=URL.createObjectURL(file)
+        const audioEl=new Audio(fileUrl)
+        audioEl.addEventListener('loadedmetadata',(e)=>{
+            console.log('e.path',e.path)
+            console.log('e.composedPath',e.composedPath())
+            console.log('获取音频时长',e.composedPath()[0].duration);
+            console.log(audioEl.duration);
+            const t=e.composedPath()[0].duration
+            resolve(t)
+        })
+    })
+}
+function handleAudioUploadBeforeRead(e){
+    const allowedTypes = ['audio/mpeg', 'audio/mp4','audio/aac','audio/x-m4a','audio/wav']
+    //由于部分安卓机的部分浏览器无法获取到文件类型,无法判断故先去除判断
+    // if(!allowedTypes.includes(e.type)){
+    //     showToast('上传失败,上传音频格式不正确')
+    //     return false
+    // }
+    return true
+}
+async function handleAudioUploadAfterRead(e){
+    // console.log(e);
+    const duration=await handleGetAudioDuration(e.file)
+
+    temAudioData.time=duration||0
+    temAudioData.size=e.file.size/1024/1024 //单位MB
+    temAudioData.name=e.file.name
+    console.log('音频数据temAudioData',temAudioData);
+    // 生成文件名
+    const t=new Date().getTime().toString()
+    const temName=`static/yb/audio/${import.meta.env.MODE}/${MD5(t)}.${e.file.type.split('/')[1]}`
+    console.log(temName);
+    temAudioData.url=await useUploadFileToOSS(e.file,temName)
+}
+function handleUpdateAudio(){
+    activeItem.value.audioUrl=temAudioData.url
+    activeItem.value.audioDuration=temAudioData.time
+    activeItem.value.audioSize=temAudioData.size
+    showUploadAudio.value=false
+}
+//更新下音频时长
+function handleUpdateAudioTime(e){
+    temAudioData.time=e
 }
 
 //章节拖动
@@ -447,12 +380,13 @@ async function goChapterDetail(item){
             path:reportInfo.value.ReportLayout===1 ? '/report/edit' : "/smart_report/edit",
             query:{
                 id:reportInfo.value.Id,
+                chapterId: item.ReportChapterId,
                 coopType: reportInfo.value.CollaborateType
             }
         })
     }else {
         router.push({
-            path:'/report/chapter/detail',
+            path:'/report/chapter/preview',
             query:{
                 id:item.ReportChapterId
             }
@@ -498,14 +432,69 @@ async function handleShowPoster(item){
     })
 }
 
+
+
+//显示版图设置弹窗
+const showLayoutSetPop = ref(false)
+const showLayoutImgPop = ref(false)
+const layoutState = reactive({
+    defaultType: 1,
+    bgColor: '',
+    headImg:'',//版头图片
+    endImg: '',//版尾图片
+    headImgId: 0,//版头Id
+    endImgId: 0,//版尾Id
+})
+function handleShowLayoutSet() {
+    layoutState.defaultType = 1
+    layoutState.bgColor = reportInfo.value.CanvasColor
+    layoutState.headImg = reportInfo.value.HeadImg
+    layoutState.endImg = reportInfo.value.EndImg
+    layoutState.headImgId = reportInfo.value.HeadResourceId
+    layoutState.endImgId = reportInfo.value.EndResourceId
+
+    showLayoutSetPop.value = true
+}
+//设置版图图片
+function  handleConfirmSetLayoutImg(e) {
+		if(e.type===1){
+				layoutState.headImg=e.data.ImgUrl
+				layoutState.headImgId = e.data.ResourceId
+		}else{
+				layoutState.endImg=e.data.ImgUrl
+				layoutState.endImgId = e.data.ResourceId
+		}
+		showLayoutImgPop.value = false
+}
+async function handleConfirmSetLayout() {
+    const res = await apiReport.setReportLayoutImg({
+    ReportId: reportInfo.value.Id,
+    HeadImg: layoutState.headImg,
+    EndImg: layoutState.endImg,
+    HeadResourceId: layoutState.headImgId,
+    EndResourceId: layoutState.endImgId,
+    CanvasColor: layoutState.bgColor,
+    })
+
+    if(res.Ret !== 200) return 
+    
+    showToast('设置成功')
+
+    reportInfo.value.CanvasColor = layoutState.bgColor
+    reportInfo.value.HeadImg = layoutState.headImg
+    reportInfo.value.EndImg = layoutState.endImg
+    reportInfo.value.HeadResourceId = layoutState.headImgId
+    reportInfo.value.EndResourceId = layoutState.endImgId
+
+    showLayoutSetPop.value = false
+}
+
 </script>
 
 <template>
     <div class="report-chapterlist-page" v-if="reportInfo">
-        <!-- <van-cell title="基础信息" is-link @click="showBaseInfoPop=true"/> -->
         <div class="chapter-list-wrap">
             
-            <!-- <ul class="chapter-list"> -->
             <draggable 
                 class="chapter-list"
                 :list="chapterList" 
@@ -547,8 +536,7 @@ async function handleShowPoster(item){
                         </div>
                     </li>
                 </template>
-            </draggable>      
-            <!-- </ul> -->
+            </draggable>
 
             <van-button
                 v-if="checkAuthBtn(reportManageBtn.reportMange_chapter_add)"
@@ -560,7 +548,11 @@ async function handleShowPoster(item){
 
         <div class="bot-action-box">
             <div class="action-box">
-                <div class="item" @click="showBaseInfoPop=true">
+                <div class="item" @click="handleShowLayoutSet" v-if="reportInfo.ReportLayout===2&&isCreator">
+                    <img src="@/assets/imgs/report/icon_set.png" alt="">
+                    <span>版图设置</span>
+                </div>
+                <div class="item" @click="showBaseInfoPop=true" v-if="isCreator">
                     <img src="@/assets/imgs/report/icon_info.png" alt="">
                     <span>基础信息</span>
                 </div>
@@ -689,12 +681,69 @@ async function handleShowPoster(item){
             <div class="item" @click="handleChapterInfo(activeItem)" v-if="isCreator">基础信息</div>
             <div class="item" @click="handleDelChapter(activeItem)" v-if="isCreator">删除</div>
             <div class="item" @click="handleShowTrendTag(activeItem)" v-permission="reportManageBtn.reportMange_chapter_editTag">添加标签</div>
-            <div class="item" @click="handleUploadChapterAudio(activeItem)">上传录音</div>
+            <div class="item" @click="handleShowUploadAudio()">上传录音</div>
         </div>
     </van-action-sheet>
 
+    <!-- 版图设置 -->
+    <van-popup
+        v-model:show="showLayoutSetPop"
+        position="bottom"
+        :style="{height:'70%'}"
+    >
+        <div class="top-box">
+            <span style="color:#666666" @click="showLayoutSetPop=false">取消</span>
+            <span class="title">版图设置</span>
+            <span style="color:#0052D9" @click="handleConfirmSetLayout">确定</span>
+        </div>
+        <van-cell-group>
+            <van-cell
+                title="版头设置"
+                is-link
+                @click="layoutState.defaultType=1;showLayoutImgPop=true"
+            />
+            <div class="show-wrapper" v-if="layoutState.headImg">
+                <img :src="layoutState.headImg" width="100" height="100">
+            </div>
+        </van-cell-group>
+        <van-cell-group>
+            <van-cell
+                title="版尾设置"
+                is-link
+                @click="layoutState.defaultType=2;showLayoutImgPop=true;"
+        
+            />
+            <div class="show-wrapper" v-if="layoutState.endImg">
+                <img :src="layoutState.endImg" width="100" height="100">
+            </div>
+        </van-cell-group>
+        <van-cell-group>
+            <div class="show-wrapper">
+                <span style="margin-right: 20px">背景色</span>
+                <V3ColorPicker v-model:value="layoutState.bgColor" :zIndex="9999"/>
+            </div>
+        </van-cell-group>
+    </van-popup>
+    
+    <!-- 版图图片设置 -->
+    <van-popup
+        v-model:show="showLayoutImgPop"
+        position="bottom"
+    >
+        <ReportLayoutImg 
+            v-if="showLayoutImgPop"
+            :defaultVal="layoutState.defaultType"
+            @close="showLayoutImgPop=false" 
+            @confirm="handleConfirmSetLayoutImg"
+        />
+    </van-popup>
+
     <!-- 定时发布选择时间 -->
-    <ReportPublishTimeSet v-model="showDSFBTime" :prePublishTime="reportInfo?.PrePublishTime" @confirm="onConfirmDSFBTime" />
+    <ReportPublishTimeSet 
+        v-model="showDSFBTime" 
+        :prePublishTime="reportInfo?.PrePublishTime" 
+        @confirm="onConfirmDSFBTime"
+    />
 
     <!-- 海报dom模块 -->
         <div v-if="chapterItemPosterInfo" class="select-text-disabled chapter-poster-box" id="chapter-poster-box">
@@ -893,14 +942,56 @@ async function handleShowPoster(item){
         background: #eee;
     }
     .item{
-        padding: 10px 0;
+        padding: 20px 0;
         text-align: center;
         line-height: 48px;
         font-size: 32px;
         border-top: 1px solid $border-color;
     }
 }
+.upload-audio-wrap{
+    height: 100%;
+    position: relative;
+    overflow: hidden;
+    padding: $page-padding;
+    p{
+        color: rgba(0, 0, 0, 0.6);
+        padding-bottom: 32px;
+        border-bottom: 1px solid $border-color;
+        margin-bottom: 32px;
+        word-wrap: break-word;
+    }
+    .bot-btns{
+        // width: 100%;
+        position: absolute;
+        bottom: 0;
+        padding: 20px 0;
+        text-align: center;
+        .bot-btn{
+            width: 315px;
+            margin: 0 10px;
+        }
+    }
+}
 
+.top-box{
+    padding:32px;
+    display: flex;
+    justify-content: space-between;
+    border-bottom: 1px solid #DCDFE6;
+    .close{
+        color:#666666;
+    }
+    .title{
+        font-size: 36px;
+    }
+    .add-btn{
+        color:$theme-color;
+    }
+}
+.show-wrapper {
+    padding: 20px;
+}
 @media screen and (min-width:$media-width){
     .report-chapterlist-page{
         padding-bottom: 80px;
@@ -981,7 +1072,9 @@ async function handleShowPoster(item){
 
     .report-item-action-box{
         .item{
-            font-size: 12px;
+            font-size: 14px;
+            line-height: 20px;
+            padding: 20px 0;
         }
     }
 }

+ 123 - 4
src/views/report/chapter/Preview.vue

@@ -1,10 +1,129 @@
-<script setup>
-import { ref } from 'vue'
+<script setup name="ReportPreview">
+import { ref,computed, nextTick, reactive,toRefs } from 'vue'
+import { useRoute, useRouter } from "vue-router";
+import apiReport from '@/api/report'
+import AudioBox from '../components/AudioBox.vue'
+import {showToast} from 'vant'
+import {reportManageBtn,useAuthBtn} from '@/hooks/useAuthBtn'
 
+
+const {checkAuthBtn} = useAuthBtn()
+
+const route=useRoute()
+const router=useRouter()
+
+
+// 获取报告详情
+let reportInfo=ref(null)
+async function getChapterDetail(){
+    const res=await apiReport.getChapterDetail({ReportChapterId:Number(route.query.id)})
+    if(res.Ret===200){
+        reportInfo.value=res.Data
+        document.title=res.Data.Title
+    }
+}
+getChapterDetail()
 </script>
 <template>
-  <div></div>
+    <div class="report-detail-page" v-if="reportInfo">
+        <h1 class="report-title">{{reportInfo.Title}}</h1>
+        <div class="auth-box">
+            <span>{{reportInfo.Author}}</span>
+            <span v-if="[2,6].includes(reportInfo.PublishState)">{{reportInfo.PublishTime}}</span>
+        </div>
+        <!-- 音频 -->
+        <!-- <AudioBox :url="reportInfo.VideoUrl" v-if="reportInfo.VideoUrl"/> -->
+        <div class="report-abstract" v-if="reportInfo.Abstract">摘要:{{reportInfo.Abstract}}</div>
+        
+        <div class="report-html-wrap" v-html="reportInfo.Content"></div>
+
+    </div>
 </template>
-<style scoped lang="scss">
 
+<style lang="scss" scoped>
+  .report-drag-item-wrap{
+        padding: 6px;
+        margin-bottom: 3px;
+    }
+.report-detail-page{
+    padding: 30px 34px;
+    margin-bottom: 112px;
+    .report-title{
+        margin: 30px 0;
+        font-weight: 600;
+        font-size: 42px;
+        line-height: 56px;
+    }
+    .auth-box{
+        display: flex;
+        justify-content: space-between;
+        font-size: $font-grey;
+        font-size: 36px;
+        padding-bottom: 40px;
+        border-bottom: 1px solid $border-color;
+        margin-bottom: 40px;
+    }
+    .report-abstract{
+        font-size: 34px;
+        line-height: 54px;
+        margin: 40px 0;
+    }
+    .audio-box{
+        margin: 40px 0;
+    }
+
+  
+}
+.top-stage-box{
+    .stage{
+        display: inline-block;
+        background-color: #F2F3FF;
+        border-radius: 8px;
+        height: 72px;
+        line-height: 72px;
+        padding: 0 20px;
+        font-size: 28px;
+    }
+    .edit-icon{
+        float: right;
+        width: 70px;
+        height: 70px;
+    }
+}
+
+@media screen and (min-width:$media-width){
+    .report-detail-page{
+        max-width: 800px;
+        margin: 0 auto 110px;
+        padding: 30px;
+        .report-title{
+            margin: 15px 0;
+            font-size: 21px;
+            line-height: 28px;
+        }
+        .auth-box{
+            font-size: 18px;
+            padding-bottom: 20px;
+            margin-bottom: 20px;
+        }
+        .report-abstract{
+            font-size: 17px;
+            line-height: 27px;
+            margin: 20px 0;
+        }
+    }
+    .top-stage-box{
+        .stage{
+            border-radius: 4px;
+            height: 36px;
+            line-height: 36px;
+            padding: 0 10px;
+            font-size: 14px;
+        }
+        .edit-icon{
+            width: 35px;
+            height: 35px;
+        }
+    }
+}
 </style>

+ 2 - 1
src/views/report/components/AddReportBaseInfoV2.vue

@@ -84,6 +84,7 @@ getReportauthor()
 const showClassify=ref(false)
 // 分类筛选
 function handleShowClassify() {
+  if(props.id) return
   // temReportTitleVal.value=reportBaseInfo.title
   showClassify.value=true
 }
@@ -312,7 +313,7 @@ async function handleSave() {
         required
         title="报告分类"
         :label="classifyNameLabel"
-        is-link
+        :is-link="id?false:true"
         @click="handleShowClassify"
       />
     </van-cell-group>

+ 0 - 10
src/views/report/components/ReportOptsBottom.vue

@@ -1,10 +0,0 @@
-<script setup>
-import { ref } from 'vue'
-
-</script>
-<template>
-  <div></div>
-</template>
-<style scoped lang="scss">
-
-</style>

+ 177 - 2
src/views/report/hooks/useReport.js

@@ -1,11 +1,37 @@
 import { ref } from 'vue'
 import { router } from '@/router'
+import {Base64} from 'js-base64'
 import apiReport from '@/api/report'
+import {getSystemInfo} from '@/api/common'
 import { showToast,showDialog } from 'vant'
 import _ from 'lodash'
+import {reportManageBtn,useAuthBtn} from '@/hooks/useAuthBtn'
+import {usePublicSettingStore} from '@/store/modules/publicSetting'
 
+const publicSettingStore = usePublicSettingStore()
+const { checkAuthBtn } = useAuthBtn()
 
+
+/* 报告操作 */
 export function useReportHandles() {
+	
+	// 水印
+	const waterMarkStr=ref('')
+	function getSystemInfoFun() {
+			getSystemInfo().then(res=>{
+					if(res.Ret===200){
+						const systemUserInfo=res.Data
+						// 设置水印文案
+						let waterMarkString=''
+						if(systemUserInfo){
+							waterMarkString=`${systemUserInfo.RealName}${systemUserInfo.Mobile?systemUserInfo.Mobile:systemUserInfo.Email}`
+							waterMarkString=encodeURIComponent(waterMarkString)
+							waterMarkStr.value=Base64.encode(waterMarkString)
+						}
+					}
+			})
+	}
+	getSystemInfoFun()
 
 
   // 刷新所有图表和表格
@@ -81,7 +107,8 @@ export function useReportHandles() {
 
   },1000)
 
-  /* 提交报告 */
+
+  /* 提交报告进入审批流 */
   function handleSubmitReport({id}) {
     showDialog({
         title: '提示',
@@ -98,13 +125,161 @@ export function useReportHandles() {
     }).catch(()=>{})
   }
 
+
+	const isPost = checkAuthBtn(reportManageBtn.reportManage_sendMsg)
+	//发布 定时 提交
+	async function handlePublishReportHook(tp,reportInfo) {
+
+		if(tp==='dsfb'){
+				showDSFBTime.value=true
+		return
+		}else if(tp==='submit'){
+				handleSubmitReport({id:Number(reportInfo.Id)})
+				return
+		}
+
+		let sendMsg = reportInfo.MsgIsSend;
+		if(sendMsg===1){
+				reportPublish({
+						sendMsg: false,
+						reportInfo
+				})
+		}else {
+
+				showDialog({
+						title: '发布提示',
+						showCancelButton: true,
+						message: isPost?'发布后,是否推送模板消息?':'是否立即发布报告?',
+						confirmButtonText: isPost?'推送':'发布',
+						cancelButtonText: isPost?'不推送':'取消',      
+				}).then(() => {
+						reportPublish({
+								sendMsg: isPost?true:false,
+								reportInfo
+						})
+				})
+				.catch(() => {
+						if(isPost) reportPublish({
+								sendMsg: false,
+								reportInfo
+						});
+				});
+
+		}
+	}
+
+	/* 发布报告 */
+	async function reportPublish({sendMsg,reportInfo}){
+			const res=await apiReport.reportPublish({ReportIds:String(reportInfo.Id),ReportUrl:generatePdfLinks(reportInfo)})
+			if(res.Ret===200){
+					sendMsg && apiReport.reportMessageSend({ReportId: Number(reportInfo.Id)})
+
+					showToast('发布成功')
+					setTimeout(() => {
+							router.back()
+					},1000)
+			}
+	}
+
+
+	//定时发布
+	const showDSFBTime = ref(false)
+	function handleDSPublish(time,reportInfo) {
+		if(reportInfo.MsgIsSend===1){//已经推送过了
+			apiReport.reportPublishTimeSet({
+					ReportId:reportInfo.Id,
+					PrePublishTime:time,
+					PreMsgSend:0,
+					ReportUrl:generatePdfLinks(reportInfo)
+			}).then(res=>{
+					if(res.Ret===200){
+							showToast('定时发布成功!')
+							setTimeout(() => {
+									router.back()
+							}, 1000);
+					}
+			})
+			return
+		}
+
+		showDialog({
+				title: '提示',
+				message:isPost?'是否发布定时报告,并推送模板消息?':'是否发布定时报告',
+				confirmButtonText:isPost?'推送':'确定',
+				cancelButtonText:isPost?'不推送':'取消',
+				showCancelButton:true
+		}).then(()=>{
+				if(!isPost){
+						apiReport.reportPublishTimeSet({
+								ReportId:reportInfo.Id,
+								PrePublishTime:time,
+								PreMsgSend:0,
+								ReportUrl:generatePdfLinks()
+						}).then(res=>{
+								if(res.Ret===200){
+										showToast('定时发布成功!')
+										setTimeout(() => {
+												router.back()
+										}, 1000);
+								}
+						})
+						return
+				}
+				//推送
+				apiReport.reportPublishTimeSet({
+						ReportId:reportInfo.Id,
+						PrePublishTime:time,
+						PreMsgSend:1,
+						ReportUrl:generatePdfLinks()
+				}).then(res=>{
+						if(res.Ret===200){
+								showToast('定时发布成功!')
+								setTimeout(() => {
+										router.back()
+								}, 1000);
+						}
+				})
+		}).catch(()=>{
+				if(!isPost) return
+				//不推送
+				apiReport.reportPublishTimeSet({
+						ReportId:reportInfo.Id,
+						PrePublishTime:time,
+						PreMsgSend:0,
+						ReportUrl:generatePdfLinks()
+				}).then(res=>{
+						if(res.Ret===200){
+								showToast('定时发布成功!')
+								setTimeout(() => {
+										router.back()
+								}, 1000);
+						}
+				})
+		})
+	}
+
+	function generatePdfLinks(reportInfo){
+			let code = reportInfo.ReportCode
+
+			return `${publicSettingStore.publicSetting.ReportViewUrl}/reportshare_pdf?code=${code}&flag=${waterMarkStr.value}`
+	}
+  
+
   return {
     handleRefresh,
-    handleSubmitReport
+		handleDSPublish,
+		showDSFBTime,
+		handlePublishReportHook
   }
 }
 
 
+/* 章节报告操作 */
+export function useChapterRepoprtHandles() {
+
+}
+
+
 /* 获取地址栏参数值 */
 function getUrlParams(str=window.location.href,key) {
   let obj = {};

+ 59 - 33
src/views/report/smartReport/EditReport.vue

@@ -2,18 +2,15 @@
 import { nextTick, reactive, ref,toRefs, watch,onMounted,onUnmounted } from 'vue'
 import { V3ColorPicker } from "v3-color-picker-teleport"
 import ReportInsertContent from '../components/reportInsert/Index.vue'
-// import ReportPublishTimeSet from './components/ReportPublishTimeSet.vue'
+import ReportPublishTimeSet from '../components/ReportPublishTimeSet.vue'
 import apiReport from '@/api/report'
 import _ from 'lodash'
-import {getSystemInfo} from '@/api/common'
 import moment from 'moment'
 import { showToast,showDialog } from 'vant'
 import { useRoute, useRouter } from 'vue-router'
 import {useCachedViewsStore} from '@/store/modules/cachedViews'
-import {usePublicSettingStore} from '@/store/modules/publicSetting'
 import {reportManageBtn,useAuthBtn} from '@/hooks/useAuthBtn'
 import {useReportApprove} from '@/hooks/useReportApprove'
-import {Base64} from 'js-base64'
 import AddReportBaseInfoV2 from '../components/AddReportBaseInfoV2.vue'
 import { useReportHandles } from '../hooks/useReport'
 import draggable from 'vuedraggable'
@@ -27,12 +24,25 @@ import ReportLayoutImg from './components/ReportLayoutImg.vue'
 
 
 const cachedViewsStore=useCachedViewsStore()
-const publicSettingStore = usePublicSettingStore()
 const {isApprove,hasApproveFlow,getEtaConfig,checkClassifyNameArr} = useReportApprove()
 const router=useRouter()
 const route=useRoute()
 const {checkAuthBtn} = useAuthBtn()
 
+
+let autoSaveTimer=null
+onMounted(() => {
+    getEtaConfig()
+    getReportDetail()
+    // autoSaveTimer=setInterval(() => {
+    //     autoSaveReportContent()
+    // }, 6000);
+})
+onUnmounted(()=>{
+    // clearInterval(autoSaveTimer)
+})
+
+
 // 获取报告详情
 const reportInfo=ref(null)
 const reportCoopType = ref(Number(route.query.coopType))
@@ -117,7 +127,6 @@ async function getReportDetail(){
 
     }
 }
-getReportDetail()
 
 
 watch(
@@ -589,8 +598,9 @@ function handleConfirmBgColor() {
 		showBgPop.value = false
 }
 
+
 /* 报告流程操作 */
-const { handleRefresh,handleSubmitReport } = useReportHandles()
+const { handleRefresh,handlePublishReportHook,handleDSPublish,showDSFBTime } = useReportHandles()
 // 报告基本信息
 const showReportBaseInfo=ref(false)
 let reportBaseInfoData={
@@ -670,13 +680,22 @@ function autoSaveReportContent(type="auto") {
     })
 }
 
-
+//发布,定时发布,提交
 async function handlePublishReport(tp) {
+		cachedViewsStore.removeCaches('ReportList')
 	 	if(document.getElementById('report-html-content')) { 
 				// 存一次草稿
 				const saveRes=await autoSaveReportContent("auto")
 				if(!saveRes) return
 		}
+
+		handlePublishReportHook(tp,reportInfo.value)
+}
+
+// 定时发布报告选择时间
+function onConfirmDSFBTime(time){
+    // console.log(time);
+    handleDSPublish(time,reportData.value)
 }
 
 
@@ -694,9 +713,9 @@ const {
 </script>
 <template>
   <div class="add-report-page">
-    <div class="main-wrap">
+    <div class="main-wrap" :style="{backgroundColor:bgColor}">
 
-      <div class="report-content-box" id="report-content-box" :style="{backgroundColor:bgColor}">
+      <div class="report-content-box" id="report-content-box" >
 
 					<div class="add-comp-wrapper">
 						<van-popover v-model:show="showPopover" @select="handleOpenComPop">
@@ -863,29 +882,29 @@ const {
   </div>
 
   <!-- 报告插入数据模块 -->
-    <van-popup
-        v-model:show="showReportInsertPop"
-        position="bottom"
-        round
-    >
-				<!-- 文字插入 -->
-				<TextEditor 
-					v-if="showInsertCompType===1"
-					:defaultVal="temTextVal"
-					@close="showReportInsertPop=false;temTextVal=''"
-					@confirm="handleInsertText"
-				/>
-
-        <!-- 图片 -->
-				<ImgEditor
-					v-else-if="showInsertCompType===2"
-					:defaultVal="temImgVal"
-					@close="showReportInsertPop=false;temImgVal=''"
-					@confirm="handleInsertImg"
-				/>
-        <!-- 图表资源 -->
-        <ReportInsertContent v-if="showInsertCompType===3" @insert="handleChartInsert"/>
-    </van-popup>
+	<van-popup
+			v-model:show="showReportInsertPop"
+			position="bottom"
+			round
+	>
+			<!-- 文字插入 -->
+			<TextEditor 
+				v-if="showInsertCompType===1"
+				:defaultVal="temTextVal"
+				@close="showReportInsertPop=false;temTextVal=''"
+				@confirm="handleInsertText"
+			/>
+
+			<!-- 图片 -->
+			<ImgEditor
+				v-else-if="showInsertCompType===2"
+				:defaultVal="temImgVal"
+				@close="showReportInsertPop=false;temImgVal=''"
+				@confirm="handleInsertImg"
+			/>
+			<!-- 图表资源 -->
+			<ReportInsertContent v-if="showInsertCompType===3" @insert="handleChartInsert"/>
+	</van-popup>
 
   <!-- 报告基础信息 -->
   <van-popup
@@ -901,6 +920,13 @@ const {
       />
   </van-popup>
 
+	 <!-- 定时发布选择时间 -->
+  <ReportPublishTimeSet 
+		v-model="showDSFBTime" 
+		:prePublishTime="reportInfo?.PrePublishTime" 
+		@confirm="onConfirmDSFBTime"
+	/>
+
 	<!-- 更多操作 背景色 版图 -->
 	<van-action-sheet 
 			teleport="body"

+ 2 - 2
src/views/report/smartReport/components/ReportLayoutImg.vue

@@ -17,7 +17,7 @@ const imgTypeOpts = [
 
 const list = ref([])
 const filterState = reactive({
-    type: 1,
+    type: props.defaultVal?props.defaultVal:1,
     page:1,
     pageSize:20,
     finished:false,
@@ -76,7 +76,7 @@ function handleConfirm() {
     <div class="top-box">
         <span style="color:#666666" @click="handleCancle">取消</span>
         <van-dropdown-menu>
-          <van-dropdown-item v-model="filterState.type" :options="imgTypeOpts" @change="initList"/>
+          <van-dropdown-item v-model="filterState.type" :options="imgTypeOpts" @change="initList" :disabled="defaultVal?true:false"/>
         </van-dropdown-menu>
         <span style="color:#0052D9" @click="handleConfirm">确定</span>
     </div>