|
@@ -0,0 +1,480 @@
|
|
|
+<script setup name="ReportEdit">
|
|
|
+import {ref,onMounted,onUnmounted} from 'vue'
|
|
|
+import {useInitFroalaEditor} from '@/hooks/useFroalaEditor'
|
|
|
+import EditReportBaseInfo from './components/EditReportBaseInfo.vue'
|
|
|
+import ReportInsertContent from './components/reportInsert/Index.vue'
|
|
|
+import apiReport from '@/api/report'
|
|
|
+import apiChart from '@/api/chart'
|
|
|
+import moment from 'moment'
|
|
|
+import { showToast } from 'vant'
|
|
|
+import { useRoute, useRouter } from 'vue-router'
|
|
|
+
|
|
|
+const router=useRouter()
|
|
|
+const route=useRoute()
|
|
|
+
|
|
|
+
|
|
|
+const {FroalaEditorIns,initFroalaEditor,frolaEditorContentChange}=useInitFroalaEditor()
|
|
|
+
|
|
|
+let autoSaveTimer=null
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ const el=document.getElementById('editor')
|
|
|
+ initFroalaEditor('#editor',{height:el.offsetHeight-150})
|
|
|
+ getReportDetail()
|
|
|
+ autoSaveTimer=setInterval(() => {
|
|
|
+ autoSaveReportContent()
|
|
|
+ }, 6000);
|
|
|
+})
|
|
|
+onUnmounted(()=>{
|
|
|
+ clearInterval(autoSaveTimer)
|
|
|
+})
|
|
|
+
|
|
|
+// 自动保存报告
|
|
|
+async function autoSaveReportContent(){
|
|
|
+ const res=await apiReport.reportContentSave({
|
|
|
+ ReportId:Number(route.query.id),
|
|
|
+ Content:$('.fr-element').html(),
|
|
|
+ NoChange:frolaEditorContentChange.value?0:1
|
|
|
+ })
|
|
|
+ frolaEditorContentChange.value=false
|
|
|
+}
|
|
|
+
|
|
|
+// 获取报告详情
|
|
|
+const reportData=ref(null)
|
|
|
+async function getReportDetail(){
|
|
|
+ const res=await apiReport.getReportDetail({
|
|
|
+ ReportId:Number(route.query.id)
|
|
|
+ })
|
|
|
+ if(res.Ret===200){
|
|
|
+ reportData.value=res.Data
|
|
|
+ reportBaseInfoData.addType=res.Data.AddType
|
|
|
+ reportBaseInfoData.classifyName=[
|
|
|
+ {
|
|
|
+ id:res.Data.ClassifyIdFirst,
|
|
|
+ text:res.Data.ClassifyNameFirst,
|
|
|
+ HasTeleconference:0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id:res.Data.ClassifyIdSecond,
|
|
|
+ text:res.Data.ClassifyNameSecond,
|
|
|
+ HasTeleconference:0
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ reportBaseInfoData.author=res.Data.Author ? res.Data.Author.split(',') : ['FICC团队']
|
|
|
+ reportBaseInfoData.frequency=[res.Data.Frequency]
|
|
|
+ reportBaseInfoData.createtime=moment(res.Data.CreateTime).format('YYYY-MM-DD')
|
|
|
+ reportBaseInfoData.title=res.Data.Title
|
|
|
+ reportBaseInfoData.abstract=res.Data.Abstract
|
|
|
+
|
|
|
+ FroalaEditorIns.value.html.set(res.Data.Content);
|
|
|
+
|
|
|
+ // 查找选中的分类是否有电话会
|
|
|
+ const classifyRes=await apiReport.getClassifyList({
|
|
|
+ CurrentIndex:1,
|
|
|
+ PageSize:1000,
|
|
|
+ KeyWord:'',
|
|
|
+ HideDayWeek:1
|
|
|
+ })
|
|
|
+ if(classifyRes.Ret===200){
|
|
|
+ const arr=classifyRes.Data.List||[]
|
|
|
+ arr.forEach(item=>{
|
|
|
+ if(item.Id==reportBaseInfoData.classifyName[0].id){
|
|
|
+ reportBaseInfoData.classifyName[0].HasTeleconference=item.HasTeleconference
|
|
|
+ }
|
|
|
+ item.Child&&item.Child.forEach(_item=>{
|
|
|
+ if(_item.Id==reportBaseInfoData.classifyName[1].id){
|
|
|
+ reportBaseInfoData.classifyName[1].HasTeleconference=_item.HasTeleconference
|
|
|
+ }
|
|
|
+ })
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 报告基本内容
|
|
|
+const showReportBaseInfo=ref(false)
|
|
|
+let reportBaseInfoData={
|
|
|
+ addType:1,
|
|
|
+ classifyName:[],
|
|
|
+ author:['FICC团队'],
|
|
|
+ frequency: ['日度'],
|
|
|
+ createtime:moment().format('YYYY-MM-DD'),
|
|
|
+ title:'',
|
|
|
+ abstract:''
|
|
|
+}
|
|
|
+async function handleReportBaseInfoChange(e){
|
|
|
+ reportBaseInfoData=e
|
|
|
+
|
|
|
+ //继承报告 覆盖一次
|
|
|
+ if(e.addType===2&&e.classifyName.length===2){
|
|
|
+ const res=await apiReport.reportDetailByClassifyId({
|
|
|
+ ClassifyIdFirst:e.classifyName[0].id,
|
|
|
+ ClassifyIdSecond:e.classifyName[1].id
|
|
|
+ })
|
|
|
+ if(res.Ret===200){
|
|
|
+ if(res.Data===null){
|
|
|
+ showToast('此分类暂无报告')
|
|
|
+ }else{
|
|
|
+ reportBaseInfoData.author=res.Data.Author ? res.Data.Author.split(',') : ['FICC团队']
|
|
|
+ reportBaseInfoData.frequency=[res.Data.Frequency]
|
|
|
+ reportBaseInfoData.createtime=moment().format('YYYY-MM-DD')
|
|
|
+ reportBaseInfoData.title=res.Data.Title
|
|
|
+ reportBaseInfoData.abstract=res.Data.Abstract
|
|
|
+ FroalaEditorIns.value.html.set(res.Data.Content);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ showReportBaseInfo.value=false
|
|
|
+}
|
|
|
+
|
|
|
+// 报告插入数据弹窗
|
|
|
+const showReportInsertPop=ref(false)
|
|
|
+/**
|
|
|
+ * list:[UniqueCode] 图表code
|
|
|
+ * type:iframe/img 插入的为iframe或者图片
|
|
|
+ * chartType: chart-图表,sheet-表格
|
|
|
+ */
|
|
|
+function handleInsert({list,type,chartType}){
|
|
|
+ if(type==='iframe'){
|
|
|
+ let link;
|
|
|
+ if(chartType==='chart'){
|
|
|
+ link=import.meta.env.MODE==='production'?'https://chartlib.hzinsights.com/chartshow':'https://charttest.hzinsights.com/chartshow'
|
|
|
+ list.forEach(item => {
|
|
|
+ FroalaEditorIns.value.html.insert(`<p style='text-align:left; margin-top:10px;'>
|
|
|
+ <iframe src='${link}?code=${item}&fromPage=' width='100%' height='350' style='border-width:0px; min-height:350px;'></iframe>
|
|
|
+ </p>`,false)
|
|
|
+ });
|
|
|
+ }else if(chartType==='sheet'){
|
|
|
+ link=import.meta.env.MODE==='production'?'https://chartlib.hzinsights.com/sheetshow':'https://charttest.hzinsights.com/sheetshow'
|
|
|
+ list.forEach(item => {
|
|
|
+ FroalaEditorIns.value.html.insert(`<p style='text-align:left; margin-top:10px;'>
|
|
|
+ <iframe src='${link}?code=${item}' class='iframe${item}' width='100%' style='border-width:0px;'></iframe>
|
|
|
+ </p>`,false)
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }else if(type==='img'){
|
|
|
+ list.forEach(item=>{
|
|
|
+ FroalaEditorIns.value.html.insert(`<img style='width:100%' src='${item}' />`,false)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ showReportInsertPop.value=false
|
|
|
+}
|
|
|
+
|
|
|
+// 更新sheet表格高度
|
|
|
+function reInitSheetIframe(e){
|
|
|
+ const { height,code } = e.data;
|
|
|
+ let iframeDom = document.getElementsByClassName(`iframe${code}`)
|
|
|
+ Array.prototype.forEach.call(iframeDom, function (ele) {
|
|
|
+ ele.height = `${height+45}px`;
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(()=>{
|
|
|
+ window.addEventListener('message',reInitSheetIframe)
|
|
|
+})
|
|
|
+onUnmounted(()=>{
|
|
|
+ window.removeEventListener('message',reInitSheetIframe)
|
|
|
+})
|
|
|
+
|
|
|
+// 刷新所有图表
|
|
|
+async function handleRefreshAllChart(){
|
|
|
+ let code_arr = [];
|
|
|
+ $('iframe').each((k,i) => {
|
|
|
+ try {
|
|
|
+ let href = $(i).attr('src');
|
|
|
+ code_arr.push(href.slice(href.indexOf('code=') + 5));
|
|
|
+ } catch (err) {
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if(!code_arr.length) return showToast('请插入图表');
|
|
|
+ const res=await apiChart.refreshChartMultiple({ChartInfoCode:code_arr})
|
|
|
+ if(res.Ret===200){
|
|
|
+ $('iframe').each((k,i) => {
|
|
|
+ $(i).attr('src',$(i).attr('src'))
|
|
|
+ });
|
|
|
+ showToast('刷新成功')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 发布报告-fb;保存-cg;预览-yl
|
|
|
+const showPublishPop=ref(false)
|
|
|
+async function handleReportOpt(type){
|
|
|
+ if(reportBaseInfoData.classifyName.length===0){
|
|
|
+ showToast('请选择报告分类')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(!reportBaseInfoData.title){
|
|
|
+ showToast('请填写报告标题')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ const params={
|
|
|
+ ReportId:Number(route.query.id),
|
|
|
+ AddType: reportBaseInfoData.addType,
|
|
|
+ ClassifyIdFirst: reportBaseInfoData.classifyName[0].id,
|
|
|
+ ClassifyNameFirst: reportBaseInfoData.classifyName[0].text,
|
|
|
+ ClassifyIdSecond: reportBaseInfoData.classifyName[1].id,
|
|
|
+ ClassifyNameSecond: reportBaseInfoData.classifyName[1].text,
|
|
|
+ Title: reportBaseInfoData.title,
|
|
|
+ Abstract: reportBaseInfoData.abstract,
|
|
|
+ Author:reportBaseInfoData.author.join(','),
|
|
|
+ Frequency: reportBaseInfoData.frequency[0],
|
|
|
+ Content: $('.fr-element').html(),
|
|
|
+ CreateTime: reportBaseInfoData.createtime,
|
|
|
+ ReportVersion: 2,
|
|
|
+ State:1
|
|
|
+ }
|
|
|
+ console.log(params);
|
|
|
+ cachedViewsStore.removeCaches('ReportList')
|
|
|
+ if(type==='cg'){
|
|
|
+ // 存草稿
|
|
|
+ const res=await apiReport.reportEdit(params)
|
|
|
+ if(res.Ret===200){
|
|
|
+ showToast('保存成功')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(type==='fb'){
|
|
|
+ // 发布
|
|
|
+ const hasTel=reportBaseInfoData.classifyName[1].HasTeleconference
|
|
|
+ //有电话会的不提示推送客群
|
|
|
+ if(hasTel==1){
|
|
|
+ const res=await apiReport.reportEdit(params)
|
|
|
+ if(res.Ret===200){
|
|
|
+ reportPublish(res.Data.ReportId)
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ // 显示发布提示弹窗,提示推送客群
|
|
|
+ showPublishPop.value=true
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 点击发布提示弹窗中的操作按钮
|
|
|
+async function handleConfirmPublish(e){
|
|
|
+ const params={
|
|
|
+ ReportId:Number(route.query.id),
|
|
|
+ AddType: reportBaseInfoData.addType,
|
|
|
+ ClassifyIdFirst: reportBaseInfoData.classifyName[0].id,
|
|
|
+ ClassifyNameFirst: reportBaseInfoData.classifyName[0].text,
|
|
|
+ ClassifyIdSecond: reportBaseInfoData.classifyName[1].id,
|
|
|
+ ClassifyNameSecond: reportBaseInfoData.classifyName[1].text,
|
|
|
+ Title: reportBaseInfoData.title,
|
|
|
+ Abstract: reportBaseInfoData.abstract,
|
|
|
+ Author:reportBaseInfoData.author.join(','),
|
|
|
+ Frequency: reportBaseInfoData.frequency[0],
|
|
|
+ Content: $('.fr-element').html(),
|
|
|
+ CreateTime: reportBaseInfoData.createtime,
|
|
|
+ ReportVersion: 2,
|
|
|
+ State:1
|
|
|
+ }
|
|
|
+ const saveRes=await apiReport.reportEdit(params)
|
|
|
+ if(e===1){//仅发布
|
|
|
+ reportPublish(saveRes.Data.ReportId)
|
|
|
+ }else if(e===2){
|
|
|
+ if(reportData.value.MsgIsSend===1) return
|
|
|
+ const pubRes=await apiReport.reportPublish({ReportIds:saveRes.Data.ReportId.toString()})
|
|
|
+ if(pubRes.Ret!==200) return
|
|
|
+ const msgRes=await apiReport.reportMessageSend({ReportId:saveRes.Data.ReportId})
|
|
|
+ if(msgRes.Ret!==200) return
|
|
|
+ router.back()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function reportPublish(id){
|
|
|
+ const res=await apiReport.reportPublish({ReportIds:id.toString()})
|
|
|
+ if(res.Ret===200){
|
|
|
+ console.log('back');
|
|
|
+ router.back()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+</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>
|
|
|
+ <!-- 底部操作 -->
|
|
|
+ <div class="bot-action-box">
|
|
|
+ <div class="left-box">
|
|
|
+ <div class="item" @click="handleRefreshAllChart">
|
|
|
+ <img src="@/assets/imgs/report/icon_refresh.png" alt="">
|
|
|
+ <span>刷新</span>
|
|
|
+ </div>
|
|
|
+ <div class="item" @click="handleReportOpt('yl')">
|
|
|
+ <img src="@/assets/imgs/report/icon_preview.png" alt="">
|
|
|
+ <span>预览</span>
|
|
|
+ </div>
|
|
|
+ <div class="item" @click="handleReportOpt('cg')">
|
|
|
+ <img src="@/assets/imgs/report/icon_save2.png" alt="">
|
|
|
+ <span>保存</span>
|
|
|
+ </div>
|
|
|
+ <div class="item" @click="handleReportOpt('fb')">
|
|
|
+ <img src="@/assets/imgs/report/icon_publish3.png" alt="">
|
|
|
+ <span>发布</span>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="right-btn" @click="showReportInsertPop=true">
|
|
|
+ <svg width="28" height="28" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
|
+ <path d="M12.0499 15.9499V27.5H15.9499V15.9499H27.5V12.0499H15.9499V0.5H12.0499V12.0499H0.5V15.9499H12.0499Z" fill="white"/>
|
|
|
+ </svg>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 报告基础信息 -->
|
|
|
+ <van-popup
|
|
|
+ v-model:show="showReportBaseInfo"
|
|
|
+ position="bottom"
|
|
|
+ :style="{ height: '100%' }"
|
|
|
+ >
|
|
|
+ <EditReportBaseInfo v-if="showReportBaseInfo" :defaultData="reportBaseInfoData" @close="showReportBaseInfo=false" @confirm="handleReportBaseInfoChange"/>
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+ <!-- 报告插入数据模块 -->
|
|
|
+ <van-popup
|
|
|
+ v-model:show="showReportInsertPop"
|
|
|
+ position="bottom"
|
|
|
+ round
|
|
|
+ >
|
|
|
+ <report-insert-content v-if="showReportInsertPop" @insert="handleInsert"/>
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+ <!-- 发布提示 -->
|
|
|
+ <van-popup
|
|
|
+ v-model:show="showPublishPop"
|
|
|
+ >
|
|
|
+ <div class="publish-report-pop-box">
|
|
|
+ <div class="title">发布提示</div>
|
|
|
+ <p class="tips">是否发布报告,且推送模板消息和客户群?</p>
|
|
|
+ <div class="btns">
|
|
|
+ <div :class="['btn blue',reportData.MsgIsSend===1?'disabled':'']" @click="handleConfirmPublish(2)">发布&推送</div>
|
|
|
+ <div class="btn" @click="handleConfirmPublish(1)">仅发布</div>
|
|
|
+ <div class="btn" @click="showPublishPop=false">取消发布</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-popup>
|
|
|
+</template>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.publish-report-pop-box{
|
|
|
+ padding: 48px;
|
|
|
+ .title{
|
|
|
+ font-size: 36px;
|
|
|
+ text-align: center;
|
|
|
+ margin-bottom: 32px;
|
|
|
+ }
|
|
|
+ .tips{
|
|
|
+ color: $font-grey;
|
|
|
+ margin-bottom: 48px;
|
|
|
+ }
|
|
|
+ .btns{
|
|
|
+ .btn{
|
|
|
+ line-height: 96px;
|
|
|
+ border-radius: 12px;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 32px;
|
|
|
+ font-weight: 600;
|
|
|
+ margin-bottom: 24px;
|
|
|
+ background-color: #F2F3FF;
|
|
|
+ color: $theme-color;
|
|
|
+ }
|
|
|
+ .blue{
|
|
|
+ background-color: $theme-color;
|
|
|
+ color: #fff;
|
|
|
+ }
|
|
|
+ .disabled{
|
|
|
+ background-color: #a8b0fc;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@media screen and (min-width:$media-width){
|
|
|
+ .publish-report-pop-box{
|
|
|
+ padding: 24px;
|
|
|
+ .title{
|
|
|
+ font-size: 18px;
|
|
|
+ margin-bottom: 16px;
|
|
|
+ }
|
|
|
+ .tips{
|
|
|
+ margin-bottom: 24px;
|
|
|
+ }
|
|
|
+ .btns{
|
|
|
+ .btn{
|
|
|
+ line-height: 48px;
|
|
|
+ border-radius: 12px;
|
|
|
+ font-size: 16px;
|
|
|
+ margin-bottom: 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.add-report-page{
|
|
|
+ height: 100vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.van-cell{
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+.main-wrap{
|
|
|
+ flex: 1;
|
|
|
+ width: calc(100% - 32PX);
|
|
|
+ margin: 0 auto;
|
|
|
+ margin-top: 30px;
|
|
|
+ .editor-box{
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ }
|
|
|
+}
|
|
|
+.bot-action-box{
|
|
|
+ padding: 20px 16PX;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ .left-box{
|
|
|
+ flex: 1;
|
|
|
+ background: #FFFFFF;
|
|
|
+ box-shadow: 0px 12px 60px 10px rgba(0, 0, 0, 0.05), 0px 32px 48px 4px rgba(0, 0, 0, 0.04), 0px 16px 20px -10px rgba(0, 0, 0, 0.08);
|
|
|
+ border-radius: 100px;
|
|
|
+ height: 112px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ margin-right: 20px;
|
|
|
+ padding: 0 20px;
|
|
|
+ .item{
|
|
|
+ flex: 1;
|
|
|
+ text-align: center;
|
|
|
+ font-size: 20px;
|
|
|
+ img{
|
|
|
+ width: 40px;
|
|
|
+ height: 40px;
|
|
|
+ display: block;
|
|
|
+ margin: 5px auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .right-btn{
|
|
|
+ flex-shrink: 0;
|
|
|
+ position: relative;
|
|
|
+ width: 96px;
|
|
|
+ height: 96px;
|
|
|
+ background-color: $theme-color;
|
|
|
+ border-radius: 50%;
|
|
|
+ box-shadow: 0px 6px 28px 4px rgba(0, 0, 0, 0.05), 0px 16px 20px 2px rgba(0, 0, 0, 0.06), 0px 10px 10px -6px rgba(0, 0, 0, 0.1);
|
|
|
+ svg{
|
|
|
+ width: 27px;
|
|
|
+ height: 27px;
|
|
|
+ position: absolute;
|
|
|
+ top: 50%;
|
|
|
+ left: 50%;
|
|
|
+ transform: translate(-50%,-50%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|