|
@@ -0,0 +1,509 @@
|
|
|
+<script setup name="ReportEnAdd">
|
|
|
+import {ref,onMounted,onUnmounted, nextTick} from 'vue'
|
|
|
+import EditReportBaseInfo from './components/EditReportBaseInfo.vue'
|
|
|
+import ReportInsertContent from '../report/components/reportInsert/Index.vue'
|
|
|
+import apiReportEn from '@/api/reportEn'
|
|
|
+import apiChart from '@/api/chart'
|
|
|
+import moment from 'moment'
|
|
|
+import { showToast } from 'vant'
|
|
|
+import { useRoute, useRouter } from 'vue-router'
|
|
|
+import {useInitFroalaEditor} from '@/hooks/useFroalaEditor'
|
|
|
+import {useCachedViewsStore} from '@/store/modules/cachedViews'
|
|
|
+
|
|
|
+const cachedViewsStore=useCachedViewsStore()
|
|
|
+const router=useRouter()
|
|
|
+const route=useRoute()
|
|
|
+
|
|
|
+const {lastFocusPosition,frolaEditorContentChange,imgUploadFlag,initFroalaEditor}=useInitFroalaEditor()
|
|
|
+
|
|
|
+let reportContentIns=null//报告内容编辑器实例
|
|
|
+let overviewContentIns=null//overview内容编辑器实例
|
|
|
+
|
|
|
+let autoSaveTimer=null//自动保存定时器
|
|
|
+
|
|
|
+onMounted(async () => {
|
|
|
+ const el=document.getElementById('editor')
|
|
|
+ reportContentIns=initFroalaEditor('#editor',{height:el.offsetHeight-150})
|
|
|
+ if(route.query.id>0){
|
|
|
+ //编辑时
|
|
|
+ getReportDetail()
|
|
|
+ autoSaveTimer=setInterval(() => {
|
|
|
+ autoSaveReportContent()
|
|
|
+ }, 6000);
|
|
|
+ }
|
|
|
+})
|
|
|
+onUnmounted(()=>{
|
|
|
+ clearInterval(autoSaveTimer)
|
|
|
+})
|
|
|
+
|
|
|
+// 自动保存报告
|
|
|
+async function autoSaveReportContent(){
|
|
|
+ if(!imgUploadFlag.value)return
|
|
|
+ //如果富文本中有未上传完成的图片,去除这个dom
|
|
|
+ $('#editor .fr-element').find('img.fr-uploading').length&&$('#editor .fr-element').find('img.fr-uploading').remove()
|
|
|
+ const res=await apiReportEn.reportContentSave({
|
|
|
+ ReportId:Number(route.query.id),
|
|
|
+ Content:$('#editor .fr-element').html(),
|
|
|
+ NoChange:frolaEditorContentChange.value?0:1
|
|
|
+ })
|
|
|
+ frolaEditorContentChange.value=false
|
|
|
+}
|
|
|
+
|
|
|
+// 获取报告详情
|
|
|
+const reportData=ref(null)
|
|
|
+async function getReportDetail(){
|
|
|
+ const res=await apiReportEn.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
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id:res.Data.ClassifyIdSecond,
|
|
|
+ text:res.Data.ClassifyNameSecond
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ reportBaseInfoData.author=res.Data.Author ? res.Data.Author.split(',') : ['Horizon Insights FICC Team']
|
|
|
+ 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
|
|
|
+
|
|
|
+ reportContentIns.html.set(res.Data.Content);
|
|
|
+ temOverviewData.value=res.Data.Overview
|
|
|
+
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 报告基本内容
|
|
|
+const showReportBaseInfo=ref(false)
|
|
|
+let reportBaseInfoData={
|
|
|
+ addType:1,
|
|
|
+ classifyName:[],
|
|
|
+ author:['Horizon Insights FICC Team'],
|
|
|
+ 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 apiReportEn.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
|
|
|
+ reportContentIns.html.set(res.Data.Content);
|
|
|
+ temOverviewData.value=res.Data.Overview
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ showReportBaseInfo.value=false
|
|
|
+}
|
|
|
+
|
|
|
+// overview
|
|
|
+const showEditOverview=ref(false)
|
|
|
+const temOverviewData=ref('')
|
|
|
+function handleShowOverview(){
|
|
|
+ showEditOverview.value=true
|
|
|
+ nextTick(()=>{
|
|
|
+ const el=document.getElementById('editor-overview')
|
|
|
+ overviewContentIns=initFroalaEditor('#editor-overview',{height:el.offsetHeight-150})
|
|
|
+ if(temOverviewData.value){
|
|
|
+ setTimeout(() => {
|
|
|
+ overviewContentIns.html.set(temOverviewData.value)
|
|
|
+ }, 100);
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+function handleSaveOverview(){
|
|
|
+ temOverviewData.value=$('#editor-overview .fr-element').html()
|
|
|
+ showEditOverview.value=false
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 报告插入数据弹窗
|
|
|
+const showReportInsertPop=ref(false)
|
|
|
+/**
|
|
|
+ * list:[UniqueCode] 图表code
|
|
|
+ * type:iframe/img 插入的为iframe或者图片
|
|
|
+ * chartType: chart-图表,sheet-表格
|
|
|
+ */
|
|
|
+function handleInsert({list,type,chartType}){
|
|
|
+ reportContentIns.events.focus()
|
|
|
+ if(lastFocusPosition.value){
|
|
|
+ reportContentIns.selection.get().removeAllRanges()
|
|
|
+ reportContentIns.selection.get().addRange(lastFocusPosition.value)
|
|
|
+ }
|
|
|
+ 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 => {
|
|
|
+ reportContentIns.html.insert(`<p style='text-align:left; margin-top:10px;'>
|
|
|
+ <iframe src='${link}?code=${item}&fromPage=en' width='100%' height='350' style='border-width:0px; min-height:350px;'></iframe>
|
|
|
+ </p>`)
|
|
|
+ });
|
|
|
+ }else if(chartType==='sheet'){
|
|
|
+ link=import.meta.env.MODE==='production'?'https://chartlib.hzinsights.com/sheetshow':'https://charttest.hzinsights.com/sheetshow'
|
|
|
+ list.forEach(item => {
|
|
|
+ reportContentIns.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>`)
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }else if(type==='img'){
|
|
|
+ list.forEach(item=>{
|
|
|
+ reportContentIns.html.insert(`<img style='width:100%' src='${item}' />`)
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ 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('刷新成功')
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+// 报告操作
|
|
|
+async function handleReportOpt(e){
|
|
|
+ //如果富文本中有未上传完成的图片,去除这个dom
|
|
|
+ $('#editor .fr-element').find('img.fr-uploading').length&&$('#editor .fr-element').find('img.fr-uploading').remove()
|
|
|
+ const params={
|
|
|
+ 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:$('#editor .fr-element').html(),
|
|
|
+ CreateTime:moment(reportBaseInfoData.createtime).format('YYYY.MM.DD'),
|
|
|
+ State: 1,
|
|
|
+ ReportVersion: 2,
|
|
|
+ Overview:temOverviewData.value
|
|
|
+ }
|
|
|
+
|
|
|
+ if(reportBaseInfoData.classifyName.length!=2){
|
|
|
+ showToast('请选择分类')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(!reportBaseInfoData.title){
|
|
|
+ showToast('请输入标题')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(!params.Overview){
|
|
|
+ showToast('请输入overview')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(!params.Content){
|
|
|
+ showToast('请输入content')
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if(!params.Abstract){
|
|
|
+ showToast('请输入摘要')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if(e==='yl'){
|
|
|
+ sessionStorage.setItem('reportEnPreData',JSON.stringify(params))
|
|
|
+ const routerEl=router.resolve({
|
|
|
+ path:'/reportEn/detail',
|
|
|
+ query:{
|
|
|
+ id:-1
|
|
|
+ }
|
|
|
+ })
|
|
|
+ window.open(routerEl.href,'_blank')
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ const res=route.query.id
|
|
|
+ ?await apiReportEn.reportEdit({ReportId:Number(route.query.id),...params})
|
|
|
+ :await apiReportEn.reportAdd(params)
|
|
|
+ if(res.Ret!==200) return
|
|
|
+ cachedViewsStore.removeCaches('ReportEnList')
|
|
|
+ if(e==='cg'){
|
|
|
+ showToast('保存成功')
|
|
|
+ setTimeout(() => {
|
|
|
+ router.replace({
|
|
|
+ path:'/reportEn/edit',
|
|
|
+ query:{
|
|
|
+ id:res.Data.ReportId
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }, 1000);
|
|
|
+ }
|
|
|
+ if(e==='fb'){
|
|
|
+ reportPublish(res.Data.ReportId)
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+// 发布报告
|
|
|
+function reportPublish(id){
|
|
|
+ apiReportEn.reportPublish({ReportIds:id.toString()}).then(res=>{
|
|
|
+ if(res.Ret===200){
|
|
|
+ showToast('发布成功')
|
|
|
+ setTimeout(() => {
|
|
|
+ router.back()
|
|
|
+ }, 1500);
|
|
|
+ }
|
|
|
+ })
|
|
|
+}
|
|
|
+
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div class="reporten-add-page">
|
|
|
+ <van-cell title="基础信息" is-link @click="showReportBaseInfo=true"/>
|
|
|
+ <van-cell title="Overview" is-link @click="handleShowOverview"/>
|
|
|
+ <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>
|
|
|
+
|
|
|
+ <!-- 报告overview -->
|
|
|
+ <van-popup
|
|
|
+ v-model:show="showEditOverview"
|
|
|
+ position="bottom"
|
|
|
+ :style="{ height: '100%' }"
|
|
|
+ >
|
|
|
+ <div class="overview-edit-wrap">
|
|
|
+ <h3>Overview</h3>
|
|
|
+ <div id="editor-overview"></div>
|
|
|
+ <div class="bot-btns">
|
|
|
+ <van-button class="bot-btn" type="primary" @click="handleSaveOverview">保存</van-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+ <!-- 报告插入数据模块 -->
|
|
|
+ <van-popup
|
|
|
+ v-model:show="showReportInsertPop"
|
|
|
+ position="bottom"
|
|
|
+ round
|
|
|
+ >
|
|
|
+ <report-insert-content v-if="showReportInsertPop" @insert="handleInsert"/>
|
|
|
+ </van-popup>
|
|
|
+
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.reporten-add-page{
|
|
|
+ height: 100dvh;
|
|
|
+ min-height: 95vh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+@media screen and (min-width:$media-width){
|
|
|
+ .reporten-add-page{
|
|
|
+ height: calc(100dvh - 60px);
|
|
|
+ min-height: calc(95vh - 60px);
|
|
|
+ }
|
|
|
+}
|
|
|
+.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%;
|
|
|
+ }
|
|
|
+}
|
|
|
+@media screen and (min-width:$media-width){
|
|
|
+ .main-wrap{
|
|
|
+ margin-top: 15px;
|
|
|
+ }
|
|
|
+}
|
|
|
+.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%);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+@media screen and (min-width:$media-width){
|
|
|
+ .bot-action-box{
|
|
|
+ margin: 0 auto;
|
|
|
+ width: 600px;
|
|
|
+ padding: 10px 16px;
|
|
|
+ .left-box{
|
|
|
+ border-radius: 50px;
|
|
|
+ height: 56px;
|
|
|
+ margin-right: 10px;
|
|
|
+ padding: 0 10px;
|
|
|
+ .item{
|
|
|
+ font-size: 12px;
|
|
|
+ img{
|
|
|
+ width: 20px;
|
|
|
+ height: 20px;
|
|
|
+ margin: 3px auto;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .right-btn{
|
|
|
+ width: 48px;
|
|
|
+ height: 48px;
|
|
|
+ svg{
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.overview-edit-wrap{
|
|
|
+ overflow: hidden;
|
|
|
+ padding: $page-padding;
|
|
|
+ height: 100%;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ #editor-overview{
|
|
|
+ flex: 1;
|
|
|
+ }
|
|
|
+ .bot-btns{
|
|
|
+ text-align: center;
|
|
|
+ padding-top: $page-padding;
|
|
|
+ .bot-btn{
|
|
|
+ width: 90%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+@media screen and (min-width:$media-width){
|
|
|
+ .overview-edit-wrap{
|
|
|
+ padding: $page-padding;
|
|
|
+ .bot-btns{
|
|
|
+ padding-top: $page-padding;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+</style>
|