Browse Source

v2研报页面布局

Karsa 1 year ago
parent
commit
af4860066f
37 changed files with 7132 additions and 159 deletions
  1. 11 0
      src/routes/modules/oldRoutes.js
  2. 111 78
      src/views/report_manage/reportV2/components/reportBaseInfoDia.vue
  3. 112 0
      src/views/report_manage/reportV2/components/reportEditHeader.vue
  4. 71 24
      src/views/report_manage/reportV2/components/reportPreview.vue
  5. 6 10
      src/views/report_manage/reportV2/list.vue
  6. 85 0
      src/views/report_manage/reportV2/normalReport/components/ETAChart.vue
  7. 141 0
      src/views/report_manage/reportV2/normalReport/components/ETAPriceChart.vue
  8. 134 0
      src/views/report_manage/reportV2/normalReport/components/ETASandBox.vue
  9. 119 0
      src/views/report_manage/reportV2/normalReport/components/ETASheet.vue
  10. 119 0
      src/views/report_manage/reportV2/normalReport/components/ImportETAChart.vue
  11. 134 0
      src/views/report_manage/reportV2/normalReport/components/SemanticAnalysis.vue
  12. 222 0
      src/views/report_manage/reportV2/normalReport/components/StatisticAnalysis.vue
  13. 160 0
      src/views/report_manage/reportV2/normalReport/components/importMyChart.vue
  14. 80 0
      src/views/report_manage/reportV2/normalReport/components/insertContent.vue
  15. 618 0
      src/views/report_manage/reportV2/normalReport/editReport.vue
  16. 178 0
      src/views/report_manage/reportV2/normalReport/mixins/messagePush.js
  17. 594 0
      src/views/report_manage/reportV2/normalReport/mixins/reportMixin.js
  18. 0 23
      src/views/report_manage/reportV2/normalReportEditor.vue
  19. 316 0
      src/views/report_manage/reportV2/smartReport/components/BaseInfo.vue
  20. 20 0
      src/views/report_manage/reportV2/smartReport/components/ChartComp.vue
  21. 106 0
      src/views/report_manage/reportV2/smartReport/components/ETAChart.vue
  22. 180 0
      src/views/report_manage/reportV2/smartReport/components/ETAPriceChart.vue
  23. 172 0
      src/views/report_manage/reportV2/smartReport/components/ETASandBox.vue
  24. 172 0
      src/views/report_manage/reportV2/smartReport/components/ETASheet.vue
  25. 16 0
      src/views/report_manage/reportV2/smartReport/components/ImgComp.vue
  26. 141 0
      src/views/report_manage/reportV2/smartReport/components/ImgEdit.vue
  27. 209 0
      src/views/report_manage/reportV2/smartReport/components/ImgSource.vue
  28. 166 0
      src/views/report_manage/reportV2/smartReport/components/ImportETAChart.vue
  29. 171 0
      src/views/report_manage/reportV2/smartReport/components/ImportMyETAChart.vue
  30. 172 0
      src/views/report_manage/reportV2/smartReport/components/SemanticAnalysis.vue
  31. 41 0
      src/views/report_manage/reportV2/smartReport/components/SheetComp.vue
  32. 258 0
      src/views/report_manage/reportV2/smartReport/components/StatisticAnalysis.vue
  33. 20 0
      src/views/report_manage/reportV2/smartReport/components/TextComp.vue
  34. 168 0
      src/views/report_manage/reportV2/smartReport/components/TextEdit.vue
  35. 1571 0
      src/views/report_manage/reportV2/smartReport/editReport.vue
  36. 338 0
      src/views/report_manage/reportV2/smartReport/reportDetail.vue
  37. 0 24
      src/views/report_manage/reportV2/smartReportEditor.vue

+ 11 - 0
src/routes/modules/oldRoutes.js

@@ -65,6 +65,17 @@ export default [
     component: () => import("@/views/smartReport/reportDetail.vue"),
   },
 
+  {
+    path: '/reportEditV2',
+    name:'编辑研报',
+    component: () => import("@/views/report_manage/reportV2/normalReport/editReport.vue")
+  },
+  {
+    path: '/smpartReportEditV2',
+    name:'编辑研报',
+    component: () => import("@/views/report_manage/reportV2/smartReport/editReport.vue")
+  },
+
   // 主页
   {
     path: "/",

+ 111 - 78
src/views/report_manage/reportV2/components/reportBaseInfoDia.vue

@@ -15,6 +15,7 @@
       :rules="rules"
       ref="baseinfoForm"
       class="baseinfo-form-wrap"
+      label-width="120px"
     >
       <el-form-item prop="type" label="新增方式">
         <el-radio-group
@@ -35,8 +36,10 @@
         <el-input
           :placeholder="$t('ReportManage.ReportList.input_title_please')"
           v-model="formData.title"
-          style="width: 340px"
+          style="width: 350px"
         ></el-input>
+        
+        <el-button type="text" v-if="formData.type===2">选择继承报告</el-button>
       </el-form-item>
 
       <el-form-item prop="classify" label="报告分类">
@@ -46,17 +49,23 @@
           v-model="formData.classify"
           :placeholder="$t('ReportManage.ReportList.please_select_category')"
           size="medium"
-          style="width: 340px"
+          style="width: 350px"
           @change="handleUpdateBaseInfo"
         />
       </el-form-item>
+
+      <el-form-item prop="relationVariety" label="关联品种" v-if="formData.relationVariety.length">
+        <div>
+          <el-tag v-for="item in formData.relationVariety" :key="item"></el-tag>
+        </div>
+      </el-form-item>
       
       <el-form-item prop="abstract" label="报告摘要">
         <el-input
           type="textarea"
           :placeholder="$t('ReportManage.ReportList.please_input_abstract')"
           v-model="formData.abstract"
-          style="width: 340px"
+          style="width: 350px"
         ></el-input>
       </el-form-item>
 
@@ -66,7 +75,7 @@
           multiple
           :placeholder="$t('ReportManage.ReportList.please_select_author')"
           size="medium"
-          style="width: 340px"
+          style="width: 350px"
         >
           <el-option
             v-for="(item, i) in authorlist"
@@ -77,12 +86,12 @@
         </el-select>
       </el-form-item>
 
-      <el-form-item prop="frequency">
+      <el-form-item prop="frequency" label="频度">
         <el-select
           v-model="formData.frequency"
           :placeholder="$t('ReportManage.ReportList.please_select_frequency')"
           size="medium"
-          style="width: 340px"
+          style="width: 350px"
         >
           <el-option 
             v-for="item in reportFrequencyOption" 
@@ -101,42 +110,53 @@
           :placeholder="$t('ReportManage.ReportList.please_select_date')"
           size="medium"
           :clearable="false"
-          style="width: 340px"
+          style="width: 350px"
         ></el-date-picker>
       </el-form-item>
 
-      <el-form-item prop="time" label="协作方式">
-        <el-date-picker
-          v-model="formData.time"
-          type="date"
-          value-format="yyyy-MM-dd"
-          :placeholder="$t('ReportManage.ReportList.please_select_date')"
-          size="medium"
-          :clearable="false"
-          style="width: 340px"
-        ></el-date-picker>
+      <el-form-item prop="cooperationType" label="协作方式">
+        <el-radio-group
+          v-model="formData.cooperationType"
+          :disabled="id"
+          @change="handleUpdateBaseInfo"
+        >
+          <el-radio :label="1">个人</el-radio>
+          <el-radio :label="2">多人协作</el-radio>
+        </el-radio-group>
+
+        <el-button 
+          type="text" 
+          v-if="formData.cooperationType===2"
+          style="margin-left: 20px"
+        >选择协作人</el-button>
       </el-form-item>
-      <el-form-item prop="time" label="报告布局">
-        <el-date-picker
-          v-model="formData.time"
-          type="date"
-          value-format="yyyy-MM-dd"
-          :placeholder="$t('ReportManage.ReportList.please_select_date')"
-          size="medium"
-          :clearable="false"
-          style="width: 340px"
-        ></el-date-picker>
+      <el-form-item prop="reportLayout" label="报告布局">
+        <el-radio-group
+          v-model="formData.reportLayout"
+          :disabled="id"
+          @change="handleUpdateBaseInfo"
+        >
+          <el-radio :label="1">常规布局</el-radio>
+          <el-radio :label="2">智能布局</el-radio>
+        </el-radio-group>
       </el-form-item>
-      <el-form-item prop="time" label="公开发布">
-        <el-date-picker
-          v-model="formData.time"
-          type="date"
-          value-format="yyyy-MM-dd"
-          :placeholder="$t('ReportManage.ReportList.please_select_date')"
-          size="medium"
-          :clearable="false"
-          style="width: 340px"
-        ></el-date-picker>
+      <el-form-item prop="isPublcPublish">
+        <template slot="label">
+          <span>公开发布</span>
+          <el-tooltip class="item" effect="dark" placement="top">
+            <div slot="content" v-html="publishTip"></div>
+            <i class="el-icon-info"/>
+          </el-tooltip>
+        </template>
+
+        <el-radio-group
+          v-model="formData.isPublcPublish"
+          :disabled="id"
+          @change="handleUpdateBaseInfo"
+        >
+          <el-radio :label="true">是</el-radio>
+          <el-radio :label="false">否</el-radio>
+        </el-radio-group>
       </el-form-item>
 
     </el-form>
@@ -176,37 +196,29 @@ export default {
   },
   watch: {
     show(n) {
-      if (!n) {
-        this.formData.type = 1;
-        this.formData.classify = [];
-        this.formData.title = "";
-        this.formData.abstract = "";
-        this.formData.author = ["投研团队"];
-        this.formData.frequency = "日度";
-        this.formData.time = this.$moment().format("YYYY-MM-DD");
-      } else {
-        if (this.id) {
-          apiSmartReport
-            .reportDetail({
-              SmartReportId: Number(this.id),
-            })
-            .then((res) => {
-              if (res.Ret === 200) {
-                this.formData.type = res.Data.AddType;
-                this.formData.classify = [
-                  res.Data.ClassifyIdFirst,
-                  res.Data.ClassifyIdSecond,
-                ];
-                this.formData.title = res.Data.Title;
-                this.formData.abstract = res.Data.Abstract;
-                this.formData.author = res.Data.Author
-                  ? res.Data.Author.split(",")
-                  : [];
-                this.formData.frequency = res.Data.Frequency;
-                this.formData.time = res.Data.CreateTime;
-              }
-            });
-        }
+      if (!n) return
+
+      if (this.id) {
+        apiSmartReport
+          .reportDetail({
+            SmartReportId: Number(this.id),
+          })
+          .then((res) => {
+            if (res.Ret === 200) {
+              this.formData.type = res.Data.AddType;
+              this.formData.classify = [
+                res.Data.ClassifyIdFirst,
+                res.Data.ClassifyIdSecond,
+              ];
+              this.formData.title = res.Data.Title;
+              this.formData.abstract = res.Data.Abstract;
+              this.formData.author = res.Data.Author
+                ? res.Data.Author.split(",")
+                : [];
+              this.formData.frequency = res.Data.Frequency;
+              this.formData.time = res.Data.CreateTime;
+            }
+          });
       }
     },
   },
@@ -216,14 +228,27 @@ export default {
       formData: {
         type: 1,
         classify: [],
+        relationVariety: [],
         title: "",
         abstract: "",
         author: ["投研团队"],
         frequency: "日度",
         time: this.$moment().format("YYYY-MM-DD") || "",
+        cooperationType: 1,//协作方式
+        reportLayout: 1,//报告布局
+        isPublcPublish: true
       },
+      publishTip: `若选择是,则发布后所有人可见;<br>
+        若选择否,则发布后,仅创建人和审批人可见;`,
+
       classifyArr: [],
       authorlist: [],
+
+      //协作人弹窗
+      isChooseCooperaUser: false,
+
+      //继承报告弹窗
+      isSelectReport:false
     };
   },
   computed: {
@@ -232,27 +257,21 @@ export default {
         type: [
           {
             required: true,
-            message: this.$t(
-              "ReportManage.ReportList.please_report_type_select"
-            ),
+            message: this.$t("ReportManage.ReportList.please_report_type_select"),
             trigger: "change",
           },
         ],
         classify: [
           {
             required: true,
-            message: this.$t(
-              "ReportManage.ReportList.please_report_type_select"
-            ),
+            message: this.$t("ReportManage.ReportList.please_report_type_select"),
             trigger: "change",
           },
         ],
         title: [
           {
             required: true,
-            message: this.$t(
-              "ReportManage.ReportList.please_report_title_input"
-            ),
+            message: this.$t("ReportManage.ReportList.please_report_title_input"),
             trigger: "blur",
           },
         ],
@@ -261,6 +280,20 @@ export default {
   },
   methods: {
     handleClose() {
+      this.formData = {
+        type: 1,
+        classify: [],
+        relationVariety: [],
+        title: "",
+        abstract: "",
+        author: ["投研团队"],
+        frequency: "日度",
+        time: this.$moment().format("YYYY-MM-DD") || "",
+        cooperationType: 1,//协作方式
+        reportLayout: 1,//报告布局
+        isPublcPublish: true
+      }
+
       this.$emit("showChange", false);
     },
 
@@ -305,6 +338,7 @@ export default {
           apiSmartReport.reportAdd(params).then((res) => {
             if (res.Ret === 200) {
               this.handleClose();
+              
               let { href } = this.$router.resolve({
                 path: "/smartReportEdit",
                 query: { id: res.Data.SmartReportId },
@@ -422,7 +456,6 @@ export default {
     width: 100%;
   }
   .el-form-item {
-    width: 340px;
     margin-left: auto;
     margin-right: auto;
   }

+ 112 - 0
src/views/report_manage/reportV2/components/reportEditHeader.vue

@@ -0,0 +1,112 @@
+<template>
+  <div class="top-action-wrap">
+      <div class="title">{{reportInfo&&reportInfo.Title}}</div>
+      <ul class="action-list">
+          <li class="action-item" @click="$emit('handleClearContent')">
+              <img src="~@/assets/img/smartReport/icon01.png" alt="">
+              <span>一键清空内容</span>
+          </li>
+          <li class="action-item" @click="$emit('openBaseInfo')">
+              <img src="~@/assets/img/smartReport/icon01.png" alt="">
+              <span>{{$t('ReportManage.ReportList.information_title')}}</span>
+          </li>
+          <li class="action-item" @click="$emit('handleRefreshAllChart')">
+              <img src="~@/assets/img/smartReport/icon02.png" alt="">
+              <span>一键刷新</span>
+          </li>
+          <li class="action-item" @click="$emit('handlePreviewReport')">
+              <img src="~@/assets/img/smartReport/icon03.png" alt="">
+              <span>{{$t('ReportManage.ReportList.preview_btn')}}</span>
+          </li>
+          <li class="action-item" @click="$emit('handleSaveContent')">
+              <img src="~@/assets/img/smartReport/icon01.png" alt="">
+              <span>{{$t('ReportManage.ReportList.save_draft_btn')}}</span>
+          </li>
+          <template v-if="!isApprove||!hasApproveFlow">
+              <li class="action-item" :class="{'disabled':checkLoading}"
+                  @click="$emit('handlePublishOpt','dsfb')">
+                  <img src="~@/assets/img/smartReport/icon01.png" alt="">
+                  <span>{{$t('ReportManage.ReportList.scheduled_publish_btn')}}</span>
+              </li>
+              <li class="action-item" :class="{'disabled':checkLoading}"
+                  @click="$emit('handlePublishOpt','fb')">
+                  <img src="~@/assets/img/smartReport/icon01.png" alt="">
+                  <span>{{$t('ReportManage.ReportList.publish_btn')}}</span>
+              </li>
+          </template>
+          <template v-if="isApprove&&hasApproveFlow">
+              <li class="action-item" :class="{'disabled':checkLoading}"
+                  @click="$emit('handlePublishOpt','submit')">
+                  <img src="~@/assets/img/smartReport/icon01.png" alt="">
+                  <span>{{$t('ReportManage.ReportList.submission_btn')}}</span>
+              </li>
+          </template>
+          
+      </ul>
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    reportInfo: {
+        type: Object
+    }
+  },
+  data() {
+    return {
+      
+    }
+  },
+  mounted(){
+
+  },
+  methods:{
+
+  },
+}
+</script>
+<style scoped lang='scss'>
+.top-action-wrap{
+    position: sticky;
+    top: 0px;
+    background-color: #fff;
+    box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.10);
+    height: 60px;
+    display: flex;
+    justify-content: space-between;
+    align-content: center;
+    padding: 0 24px;
+    .title{
+        line-height: 60px;
+        font-size: 16px;
+    }
+    .action-list{
+        display: flex;
+        align-items: center;
+        .action-item{
+            height: 36px;
+            display: flex;
+            align-items: center;
+            border-right: 1px solid #C8CDD9;
+            padding: 0 30px;
+            font-size: 16px;
+            cursor: pointer;
+            img{
+                width: 16px;
+                height: 16px;
+                margin-right: 4px;
+                position: relative;
+                top: 2px;
+            }
+            &:last-child{
+                border-right: none;
+            }
+            &.disabled{
+                pointer-events: none;
+                cursor: not-allowed;
+                color:#999;
+            }
+        }
+    }
+}
+</style>

+ 71 - 24
src/views/report_manage/reportV2/components/reportPreview.vue

@@ -38,20 +38,25 @@
           <div id="resetcss" style="overflow:hidden;" v-html="reportInfo.Content"></div>
         </block>
       </div>
+    </div>
 
+    <ul class="fixed-handles">
+        <li v-permission="permissionBtn.reportManageBtn.reportManage_reportView_copyWechat" :data-clipboard-text='linkUrl' @click="copyHandle" class="copy">
+            <el-button type="text">复制链接</el-button>
+        </li>
+        <li v-permission="permissionBtn.reportManageBtn.reportManage_reportView_wechartShare" @mouseenter="isShowCode=true" @mouseleave="isShowCode=false" style="position:relative">
+            <el-button type="text">微信分享</el-button>
 
-      <div v-if="linkUrl" style="width:100px;height30px;position:absolute;right:-100px;top:100px;cursor:pointer;">
-        <div v-permission="permissionBtn.reportManageBtn.reportManage_reportView_copyWechat"
-                  style="display:flex;alignItems:center;color:#333;" :data-clipboard-text='linkUrl' @click="copyHandle" class="copy">
-          <img src="@/assets/img/icons/cop.png" alt="" style="width:30px;height:30px;marginRight:10px;">复制链接
-        </div>
-        <div v-permission="permissionBtn.reportManageBtn.reportManage_reportView_wechartShare"
-                  style="display:flex;alignItems:center;color:#333;marginTop:20px;"  @mouseenter="isShowCode=true" @mouseleave="isShowCode=false">
-          <img src="@/assets/img/icons/wechat.png" alt="" style="width:30px;height:30px;marginRight:10px;">微信分享
-        </div>
-        <vue-qr :text="linkUrl" :margin="0" colorDark="#333" colorLight="#fff" :dotScale="1" :size="100" style="position:absolute;right:0;top:100px;" v-if="isShowCode"></vue-qr>
-      </div>
-    </div>
+          <vue-qr :text="linkUrl" :margin="0" colorDark="#333" colorLight="#fff" :dotScale="1" :size="100" style="position:absolute;left:-20px;top:-120px;" v-if="isShowCode"></vue-qr>
+        </li>
+        <li>
+            <el-button type="text" @click="$emit('itemclick',{type:'下载Pdf',data: reportIdInfo})">下载PDF</el-button>
+        </li>
+        <li>
+            <el-button type="text" @click="$emit('itemclick',{type:'下载长图',data: reportIdInfo})">下载长图</el-button>
+        </li>
+
+    </ul>
 
   </el-drawer>
 </template>
@@ -64,15 +69,15 @@ export default {
     show: {
       type: Boolean
     },
-    reportId: {
-      type:Number
+    reportIdInfo: {
+      type: Object
     }
   },
   computed: {
     linkUrl(){
       let str=''
       const baseUrl= localStorage.getItem('dynamicOutLinks') ? JSON.parse(localStorage.getItem('dynamicOutLinks')).ReportViewUrl : '';
-      if(this.$route.query.code){
+      if(this.reportIdInfo.ReportCode){
         // 设置水印文案
         let waterMarkStr=''
         if(this.systemUserInfo){
@@ -81,12 +86,8 @@ export default {
           waterMarkStr=encodeURIComponent(waterMarkStr)
           waterMarkStr=base64.encode(waterMarkStr)
         }
-        
-        if(this.$route.query.fromPage == 'en'){
-          str=`${baseUrl}/reportshare_crm_report_en?code=${this.$route.query.code}&flag=${waterMarkStr}`
-        }else{
-          str=`${baseUrl}/reportshare_crm_report?code=${this.$route.query.code}&flag=${waterMarkStr}`
-        }
+
+        str=`${baseUrl}/reportshare_crm_report?code=${this.reportIdInfo.ReportCode}&flag=${waterMarkStr}`
       }
       
       return str
@@ -103,11 +104,19 @@ export default {
     return {
       reportInfo:{},
     
+      handlesOpt: [
+        { key:'copyLink',label:'复制链接' },
+        { key:'wxShare',label:'微信分享' },
+        { key:'downPdf',label:'下载PDF' },
+        { key:'downPic',label:'下载长图' },
+      ],
       loading: false,
+
+      isShowCode: false
     }
   },
   mounted(){
-
+    this.getSystemUserInfo()
   },
   methods:{
     handleClose() {
@@ -118,13 +127,37 @@ export default {
     async getReportDetail() {
 
       this.loading = true;
-      const res = await reportdetail({ReportId:parseInt(this.reportId)})
+      const res = await reportdetail({ReportId:parseInt(this.reportIdInfo.Id)})
 			if( res.Ret!==200 ) return 
 
       this.reportInfo=res.Data;
       
       this.loading = false;
       this.isShow=true;
+    },
+
+    getSystemUserInfo(){
+      departInterence.systemUserInfo().then(res=>{
+        if(res.Ret===200){
+          this.systemUserInfo=res.Data
+        }
+      })
+    },
+
+    /* 复制链接 */
+    copyHandle() {
+      var clipboard = new this.Clipboard('.copy')
+      clipboard.on('success', e => {
+        this.$message.success('复制链接成功')
+        e.clearSelection() // 释放内存
+        clipboard.destroy()
+      })
+      // // 浏览器不支持
+      clipboard.on('error', e => {
+        this.$message.warning('浏览器暂不支持')
+        // 释放内存
+        clipboard.destroy()
+      })
     }
   },
 }
@@ -151,7 +184,7 @@ export default {
   color: #333;
 }
 
-	#reportdtl{ background:#fff;  max-width:1200px; margin:10px auto;position:relative;
+	#reportdtl{ background:#fff;  max-width:1200px; margin:10px auto 70px;position:relative;
 		img{ display:'block'; width:'100%'; margin:'0 auto'; }
 		header{ padding:10px 30px; box-sizing:border-box; font-size:28px; font-weight:500; color:#333; background:#fff; }
 		#abstract{ padding:10px 30px 0; box-sizing:border-box; font-size:22px; line-height:36px;
@@ -220,4 +253,18 @@ export default {
 			}
 		}
 	}
+
+
+  .fixed-handles {
+    width: 100%;
+    height: 60px;
+    padding: 0 15px;
+    position: fixed;
+    bottom: 0;
+    background: #fff;
+    border-top: 1px solid #ccc;
+    display: flex;
+    align-items: center;
+    gap: 40px;
+  }
 </style>

+ 6 - 10
src/views/report_manage/reportV2/list.vue

@@ -312,7 +312,8 @@
     <!-- 报告预览弹窗 -->
     <reportPreview
       :show.sync="isShowPreview"
-      :reportId="previewReportId"
+      :reportIdInfo="previewReportInfo"
+      @itemclick="itemclickHandle"
     />
 
 
@@ -621,7 +622,7 @@ export default {
       publishReportCode:'',
 
       isShowPreview: false,//预览报告弹窗
-      previewReportId: 0,
+      previewReportInfo: {},
     }
   },
   mounted(){
@@ -766,15 +767,9 @@ export default {
       //如果没有预览权限,就不跳转
       if(!this.permissionBtn.checkPermissionBtn(this.permissionBtn.reportManageBtn.reportManage_reportView)) return
 
-      this.previewReportId = item.Id
+      this.previewReportInfo = item;
       this.isShowPreview = true
 
-      // sessionStorage.setItem("reportdtl", JSON.stringify(item));
-      // let { href } = this.$router.resolve({
-      //   name: "预览报告",
-      //   query: { id: item.Id, code: item.ReportCode },
-      // });
-      // window.open(href, "_blank");
     },
 
 
@@ -923,7 +918,8 @@ export default {
       sessionStorage.setItem("PageIndex", this.PageIndex);
 
       this.$router.push({
-        path: item.ReportVersion === 2 ? "/editreportNew" : "/editreport",
+        // path: item.ReportVersion === 2 ? "/editreportNew" : "/editreport",
+        path: '/reportEditV2',
         query: {
           id: item.Id,
         },

+ 85 - 0
src/views/report_manage/reportV2/normalReport/components/ETAChart.vue

@@ -0,0 +1,85 @@
+<template>
+    <div class="eta-chart-wrap">
+        <div class="top-box">
+            <div class="left-card">
+                <span :class="['item',activeType==='ETA图库'?'active':'']" @click="activeTypeChange('ETA图库')">{{$t('ReportManage.ReportList.chart_inventory_radio')}}</span>
+                <span :class="['item',activeType==='MyETA'?'active':'']" @click="activeTypeChange('MyETA')">{{$t('MyEtaPage.tab_my')}}</span>
+            </div>
+            <el-input
+                class="search-box"
+                :placeholder="$t('ReportManage.ReportList.chart_name')"
+                v-model="keyword"
+                size="medium"
+                prefix-icon="el-icon-search"
+                v-if="activeType==='ETA图库'"
+                @input="handleETAChartSearch"
+            />
+        </div>
+        <ImportETAChart ref="ETAChartWrap" v-if="activeType==='ETA图库'" @insertHtml="item =>{$emit('insertHtml',item)}"/>
+        <ImportMyETAChart @handleImportMyChart="handleImportMyChart" v-if="activeType==='MyETA'"/>
+    </div>
+</template>
+
+<script>
+import ImportETAChart from './ImportETAChart.vue';
+import ImportMyETAChart from './importMyChart.vue';
+export default {
+    name:"ETAChartWrap",
+    components:{ImportETAChart,ImportMyETAChart},
+    data() {
+        return {
+            keyword:'',
+            activeType:'ETA图库',
+        }
+    },
+    methods: {
+        activeTypeChange(e){
+            if(this.activeType===e) return
+            this.activeType=e
+        },
+
+        handleETAChartSearch(){
+            this.$refs.ETAChartWrap.handleSearch(this.keyword)
+        },
+
+        handleImportMyChart(list){
+            this.$emit('handleImportMyChart',list)
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.eta-chart-wrap{
+    .top-box{
+        .left-card{
+            width: fit-content;
+            margin-bottom: 15px;
+            border-radius: 4px;
+            border: 1px solid var(--unnamed, #DCDFE6);
+            background: var(--gary-gy-3-disabled, #EBEFF6);
+            display: flex;
+            align-items: center;
+            padding: 6px;
+            .item{
+                cursor: pointer;
+                display: block;
+                width: 110px;
+                height: 30px;
+                line-height: 30px;
+                text-align: center;
+                border-radius: 4px;
+                font-size: 18px;
+                color: #666;
+                &.active{
+                    background: #FFF;
+                    color: #002D78;
+                }
+            }
+        }
+    }
+}
+</style>

+ 141 - 0
src/views/report_manage/reportV2/normalReport/components/ETAPriceChart.vue

@@ -0,0 +1,141 @@
+<template>
+    <div class="statistic-analysis-wrap">
+        <div class="top-box">
+            <div class="right">
+                <el-input
+                    class="search-box"
+					placeholder="图表名称"
+					v-model="keyword"
+					size="medium"
+					prefix-icon="el-icon-search"
+                    @input="handleSearch"
+				/>
+            </div>
+        </div>
+        <div class="main-box">
+            <el-checkbox
+                class="onlyshowme-box"
+                v-model="isShowMe" 
+                @change="handleIsShowMeChange"
+            >{{$t('ReportManage.ReportList.just_mine_radio')}}</el-checkbox>
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+                <div class="chart-item" v-for="item in list" :key="item.UniqueCode">
+                    <div class="title">{{item.ChartName}}</div>
+                    <img
+                        :src="item.ChartImage"
+                        @click="$emit('insertHtml',item)"
+                    />
+                </div>
+                <tableNoData :text="$t('ReportManage.ReportList.no_chart_table_available')" size="mini" v-if="list.length===0&&finished"/>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import futuresInterface from "@/api/modules/futuresBaseApi";
+export default {
+    data() {
+        return {
+            
+            keyword:'',
+            isShowMe:false,
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+            loading:false
+        }
+    },
+    created(){
+        this.getChartList()
+    },
+    methods: {
+
+        handleIsShowMeChange(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getChartList()
+        },
+
+        handleSearch(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getChartList()
+        },
+
+        /* 搜索图表分页 */
+        async getChartList(word) {
+            let params = {
+                Keyword: this.keyword || "",
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+                IsShowMe: this.isShowMe,
+            };
+            this.loading=true
+            let res = await futuresInterface.searchChart(params);
+            this.loading=false
+            if (res.Ret !== 200) return;
+            const arr = res.Data.List || [];
+            this.list =
+                this.page === 1
+                ? arr
+                : [...this.list, ...arr];
+            this.finished =  res.Data.Paging.IsEnd;
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getChartList()
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .right{
+            .search-box{
+                width: 330px;
+            }
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            flex: 1;
+            overflow-y: auto;
+
+        }
+    }
+}
+.chart-item {
+    width: 100%;
+    margin: 20px 0;
+    padding: 20px;
+    border: 1px solid #eaeaea;
+    border-radius: 10px;
+    font-size: 16px;
+    text-align: center;
+    img {
+        width: 100%;
+    }
+}
+</style>

+ 134 - 0
src/views/report_manage/reportV2/normalReport/components/ETASandBox.vue

@@ -0,0 +1,134 @@
+<template>
+    <div class="statistic-analysis-wrap">
+        <div class="top-box">
+            <div class="right">
+                <el-input
+                    class="search-box"
+					:placeholder="$t('ReportManage.ReportList.no_reports_msg')"
+					v-model="keyword"
+					size="medium"
+					prefix-icon="el-icon-search"
+                    @input="handleSearch"
+				/>
+            </div>
+        </div>
+        <div class="main-box">
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+               
+                <div class="chart-item" v-for="item in list" :key="item.SandboxId">
+                    <div class="title">{{item.Name}}</div>
+                    <img
+                        :src="item.PicUrl"
+                        @click="$emit('insertHtml',item)"
+                    />
+                </div>
+                <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-if="list.length===0&&finished"/>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import {sandInterface} from "@/api/api.js";
+export default {
+    data() {
+        return {
+            
+            keyword:'',
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+            loading:false
+        }
+    },
+    created(){
+        this.getSandBoxList()
+    },
+    methods: {
+        handleIsShowMeChange(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getSandBoxList()
+        },
+
+        handleSearch(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getSandBoxList()
+        },
+
+        /* 搜索图表分页 */
+        async getSandBoxList(word) {
+            let params = {
+                Keyword: this.keyword || "",
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+            };
+            this.loading=true
+            let res = await sandInterface.sandlistByQuote(params);
+            this.loading=false
+            if (res.Ret !== 200) return;
+            const arr = res.Data.List || [];
+            this.list =
+                this.page === 1
+                ? arr
+                : [...this.list, ...arr];
+            this.finished =  res.Data.Paging.IsEnd;
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getSandBoxList()
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .right{
+            .search-box{
+                width: 330px;
+            }
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            flex: 1;
+            overflow-y: auto;
+
+        }
+    }
+}
+.chart-item {
+    width: 100%;
+    margin: 20px 0;
+    padding: 20px;
+    border: 1px solid #eaeaea;
+    border-radius: 10px;
+    font-size: 16px;
+    text-align: center;
+    img {
+        width: 100%;
+    }
+}
+</style>

+ 119 - 0
src/views/report_manage/reportV2/normalReport/components/ETASheet.vue

@@ -0,0 +1,119 @@
+<template>
+    <div class="eta-sheet-wrap">
+        <div class="top-box">
+            <el-input
+                class="search-box"
+				:placeholder="$t('ReportManage.ReportList.table_name_tabs')"
+				v-model="keyword"
+				size="medium"
+				prefix-icon="el-icon-search"
+                @input="handleSearch"
+			/>
+        </div>
+        <div class="main-box">
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+            <div class="sheet-item" v-for="item in list" :key="item.ExcelInfoId">
+                <div class="title">{{item.ExcelName}}</div>
+                <div class="img" :style="`backgroundImage:url(${ !item.HaveOperaAuth?$icons.lock_big:item.ExcelImage })`" @click="$emit('insertHtml',item)"></div>
+                <img
+                    :src="!item.HaveOperaAuth?$icons.lock_big:item.ExcelImage"
+                    @click="$emit('insertHtml',item)"
+                />
+            </div>
+            <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-if="list.length===0"/>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import * as sheetInterface from "@/api/modules/sheetApi.js";
+export default {
+    data() {
+        return {
+            keyword:'',
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+            loading:false
+        }
+    },
+    created(){
+        this.getSheetList()
+    },
+    methods: {
+        handleSearch(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getSheetList()
+        },
+        getSheetList() {
+            this.loading=true
+            sheetInterface.sheetList({
+                Keyword: this.keyword,
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+            }).then((res) => {
+                this.loading=false
+                if (res.Ret !== 200) return;
+                const arr = res.Data.List || [];
+                this.list =
+                    this.page === 1
+                    ? arr
+                    : [...this.list, ...arr];
+                this.finished =  res.Data.Paging.IsEnd;
+            });
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getSheetList()
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.eta-sheet-wrap{
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        .search-box{
+            width: 330px;
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            flex: 1;
+            overflow-y: auto;
+
+        }
+        .sheet-item{
+            width: 100%;
+            margin: 20px 0;
+            padding: 20px;
+            border: 1px solid #eaeaea;
+            border-radius: 10px;
+            font-size: 16px;
+            text-align: center;
+            img {
+                width: 100%;
+            }
+        }
+    }
+}
+</style>

+ 119 - 0
src/views/report_manage/reportV2/normalReport/components/ImportETAChart.vue

@@ -0,0 +1,119 @@
+<template>
+    <div class="main-box">
+            <el-checkbox
+                class="onlyshowme-box"
+                v-model="isShowMe" 
+                @change="handleIsShowMeChange"
+            >{{$t('ReportManage.ReportList.just_mine_radio')}}</el-checkbox>
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+ 
+                <div class="chart-item" v-for="item in list" :key="item.UniqueCode">
+                    <div class="title">{{item.ChartName}}</div>
+                    <img
+                        :src="!item.HaveOperaAuth?$icons.lock_big:item.ChartImage"
+                        @click="$emit('insertHtml',item)"
+                    />
+                </div>
+                <tableNoData :text="$t('ReportManage.ReportList.no_chart_table_available')" size="mini" v-if="list.length===0&&finished"/>
+            </div>
+        </div>
+</template>
+
+<script>
+import { dataBaseInterface } from "@/api/api.js";
+export default {
+    data() {
+        return {
+            isShowMe:false,
+            page:1,
+            pageSize:20,
+            list:[],
+            finished:false,
+            keyword:'',
+            loading:false
+        }
+    },
+    computed: {
+        //语言版本
+        currentLang() {
+            return this.$store.state.lang
+        }
+    },
+    created() {
+        this.getETAChartList()
+    },
+    methods: {
+
+        async getETAChartList(){
+            this.loading=true
+            const res=await dataBaseInterface.chartSearchByEs({
+                Keyword: this.keyword || "",
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+                IsShowMe: this.isShowMe,
+            })
+            this.loading=false
+            if(res.Ret===200){
+                const arr=res.Data.List || []
+                this.list=[...this.list,...arr]
+                this.finished=res.Data.Paging.IsEnd
+            }
+        },
+
+        handleIsShowMeChange(){
+            this.page=1
+            this.finished=false
+            this.list=[]
+            this.getETAChartList()
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getETAChartList()
+        },
+
+        handleSearch(key){
+            this.page=1
+            this.finished=false
+            this.list=[]
+            this.keyword=key
+            this.getETAChartList()
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+
+.main-box{
+    margin-top: 30px;
+    height: calc(100vh - 300px);
+    border-radius: 4px;
+    border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+    background: #FFF;
+    padding: 20px;
+    display: flex;
+    flex-direction: column;
+    .list-wrap{
+        flex: 1;
+        overflow-y: auto;
+
+    }
+}
+.chart-item {
+    width: 100%;
+    margin: 20px 0;
+    padding: 20px;
+    border: 1px solid #eaeaea;
+    border-radius: 10px;
+    font-size: 16px;
+    text-align: center;
+    img {
+        width: 100%;
+    }
+}
+</style>

+ 134 - 0
src/views/report_manage/reportV2/normalReport/components/SemanticAnalysis.vue

@@ -0,0 +1,134 @@
+<template>
+    <div class="statistic-analysis-wrap">
+        <div class="top-box">
+            <div class="right">
+                <el-input
+                    class="search-box"
+					:placeholder="$t('ReportManage.ReportList.keyword_search')"
+					v-model="keyword"
+					size="medium"
+					prefix-icon="el-icon-search"
+                    @input="handleSearch"
+				/>
+            </div>
+        </div>
+        <div class="main-box">
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+                    <div class="chart-item" v-for="item in list" :key="item.SaCompareId">
+                        <div class="title">{{item.Title}}</div>
+                        <img
+                            :src="item.ResultImg"
+                            @click="$emit('insertHtml',{...item,PicUrl:item.ResultImg})"
+                        />
+                    </div>
+                <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-if="list.length===0&&finished"/>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import {semanticInterface} from '@/api/modules/semanticsApi.js';
+export default {
+    data() {
+        return {
+            
+            keyword:'',
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+            loading:false
+        }
+    },
+    created(){
+        this.getSemanticList()
+    },
+    methods: {
+
+        handleIsShowMeChange(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getSemanticList()
+        },
+
+        handleSearch(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getSemanticList()
+        },
+
+        /* 搜索图表分页 */
+        async getSemanticList(word) {
+            let params = {
+                Keyword: this.keyword || "",
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+            };
+            this.loading=true
+            let res = await semanticInterface.compareSearch(params);
+            this.loading=false
+            if (res.Ret !== 200) return;
+            const arr = res.Data.List || [];
+            this.list =
+                this.page === 1
+                ? arr
+                : [...this.list, ...arr];
+            this.finished =  res.Data.Paging.IsEnd;
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getSemanticList()
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .right{
+            .search-box{
+                width: 330px;
+            }
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            flex: 1;
+            overflow-y: auto;
+
+        }
+    }
+}
+.chart-item {
+    width: 100%;
+    margin: 20px 0;
+    padding: 20px;
+    border: 1px solid #eaeaea;
+    border-radius: 10px;
+    font-size: 16px;
+    text-align: center;
+    img {
+        width: 100%;
+    }
+}
+</style>

+ 222 - 0
src/views/report_manage/reportV2/normalReport/components/StatisticAnalysis.vue

@@ -0,0 +1,222 @@
+<template>
+    <div class="statistic-analysis-wrap">
+        <div class="top-box">
+            <div class="left-card">
+                <span
+                    :class="['item',activeType===item.key?'active':'']" 
+                    @click="activeTypeChange(item.key)"
+                    v-for="item in typeOpts"
+                    :key="item.key"
+                >{{item.name}}</span>
+            </div>
+            <div class="right">
+                <el-input
+                    class="search-box"
+					:placeholder="$t('ReportManage.ReportList.chart_name')"
+					v-model="keyword"
+					size="medium"
+					prefix-icon="el-icon-search"
+                    @input="handleSearch"
+				/>
+            </div>
+        </div>
+        <div class="main-box">
+            <el-checkbox
+                class="onlyshowme-box"
+                v-model="isShowMe" 
+                @change="handleIsShowMeChange"
+            >{{$t('ReportManage.ReportList.just_mine_radio')}}</el-checkbox>
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+                
+                <div class="chart-item" v-for="item in list" :key="item.UniqueCode">
+                    <div class="title">{{item.ChartName}}</div>
+                    <img
+                        :src="item.ChartImage"
+                        @click="$emit('insertHtml',item)"
+                    />
+                </div>
+                <tableNoData :text="$t('ReportManage.ReportList.no_chart_table_available')" size="mini" v-if="list.length===0&&finished"/>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import chartRelevanceApi from "@/api/modules/chartRelevanceApi";
+import {
+  fittingEquationInterface,
+  statisticFeatureInterface,
+  crossVarietyInterface
+} from "@/api/modules/chartRelevanceApi";
+export default {
+    data() {
+        return {
+
+            keyword:'',
+            isShowMe:false,
+            activeType:'相关性',
+
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+            loading:false
+        }
+    },
+    created(){
+        this.getChartList()
+    },
+    methods: {
+
+        activeTypeChange(e){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.keyword=''
+            this.isShowMe=false
+            this.activeType=e
+            this.getChartList()
+        },
+
+        handleIsShowMeChange(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getChartList()
+        },
+
+        handleSearch(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getChartList()
+        },
+
+        /* 搜索图表分页 */
+        async getChartList(word) {
+            let params = {
+                Keyword: this.keyword || "",
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+                IsShowMe: this.isShowMe,
+            };
+            this.loading=true
+            let res = null;
+            if (this.activeType === '相关性') {
+                res = await chartRelevanceApi.searchChart(params);
+            } else if (this.activeType === '拟合方程曲线') {
+                res = await fittingEquationInterface.searchChart(params);
+            } else if (this.activeType === '统计特征') {
+                res = await statisticFeatureInterface.searchChart(params);
+            } else if (this.activeType === '跨品种分析') {
+                res = await crossVarietyInterface.searchChart(params);
+            }
+            this.loading=false
+
+            if (res.Ret !== 200) return;
+            const arr = res.Data.List || [];
+            this.list =
+                this.page === 1
+                ? arr
+                : [...this.list, ...arr];
+            this.finished =  res.Data.Paging.IsEnd;
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getChartList()
+        }
+    },
+    computed:{
+      typeOpts(){
+        return [
+                {
+                    name:this.$t('ReportManage.ReportList.correlation_analysis'),
+                    key:'相关性'
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.curve_fitting_radio'),
+                    key:'拟合方程曲线'
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.statistical_feature_radio'),
+                    key:'统计特征'
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.intercommodity_analysis_radio'),
+                    key:'跨品种分析'
+                }
+            ]
+      }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+    .top-box{
+        .left-card{
+            margin-bottom: 15px;
+            border-radius: 4px;
+            border: 1px solid var(--unnamed, #DCDFE6);
+            background: var(--gary-gy-3-disabled, #EBEFF6);
+            display: flex;
+            flex-wrap: wrap;
+            align-items: center;
+            gap: 0 3px;
+            padding: 6px;
+            .item{
+                cursor: pointer;
+                display: block;
+                width: 110px;
+                height: 30px;
+                line-height: 30px;
+                text-align: center;
+                border-radius: 4px;
+                font-size: 18px;
+                color: #666;
+                &.active{
+                    background: #FFF;
+                    color: #002D78;
+                }
+            }
+        }
+        .right{
+            .search-box{
+                width: 330px;
+            }
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            flex: 1;
+            overflow-y: auto;
+
+        }
+    }
+}
+.chart-item {
+    width: 100%;
+    margin: 20px 0;
+    padding: 20px;
+    border: 1px solid #eaeaea;
+    border-radius: 10px;
+    font-size: 16px;
+    text-align: center;
+    img {
+        width: 100%;
+    }
+}
+</style>

+ 160 - 0
src/views/report_manage/reportV2/normalReport/components/importMyChart.vue

@@ -0,0 +1,160 @@
+<template>
+    <div class="import-mychart-wrap">
+        <div>
+			<el-select 
+				v-model="selectMyChartClassify" 
+				filterable 
+				:placeholder="$t('ReportManage.ReportList.chart_category_name')"
+				@change="handleChange"
+			>
+				<el-option
+					v-for="item in myChartClassifyList"
+					:key="item.MyChartClassifyId"
+					:label="item.MyChartClassifyName"
+					:value="item.MyChartClassifyId"
+				>
+				</el-option>
+			</el-select>
+			<el-button type="primary" @click="handleImport">{{$t('ReportManage.ReportList.click_import')}}</el-button>
+			<el-tooltip class="item" effect="dark" :content="$t('ReportManage.ReportList.import_all_chart_msg')" placement="top-start">
+				<i style="font-size:20px;color: #666;" class="el-icon-question"></i>
+			</el-tooltip>
+		</div>
+		<div class="list" v-infinite-scroll="load" v-if="list.length>0">
+            <div class="item" v-for="item in list" :key="item.UniqueCode" @click="handleClickItem">
+                <div class="chartEn-mark" v-show="item.IsEnChart && showEnMark" style="top: 0;left: 0;">En</div>
+                <p class="color_primary">{{ item.ChartName }}</p>
+                <img :src="!item.HaveOperaAuth?$icons.lock_big:item.ChartImage" alt="">
+            </div>
+		</div>
+        <div v-if="list.length==0" class="empty-box">
+            {{$t('Table.prompt_slogan')}}
+        </div>
+    </div>
+</template>
+
+<script>
+import { mychartInterface } from '@/api/api.js';
+export default {
+    data() {
+        return {
+            myChartClassifyList:[],
+            selectMyChartClassify:'',
+            pageSize:10000,
+			CurrentIndex: 1,
+			list:[],
+            loading:false,
+            finished:false,
+
+        }
+    },
+    props:{
+        showEnMark:{
+            type:Boolean,
+            default:false
+        }
+    },
+    mounted(){
+        this.getMyChartClassify()
+    },  
+    methods: {
+        //获取我的图库中分类
+		getMyChartClassify(){
+			mychartInterface.classifyList().then(res=>{
+				if (res.Ret !== 200) return;
+				this.myChartClassifyList=res.Data?res.Data.List:[]
+			})
+		},
+        handleChange(){
+            this.CurrentIndex=1
+            this.list=[]
+            this.finished=false
+            this.loading=false
+            this.handleGetMyChartList()
+        },
+		async handleGetMyChartList(){
+            if(!this.selectMyChartClassify) return
+            this.loading=true
+            const res=await  mychartInterface.myList({
+				PageSize: this.pageSize,
+				CurrentIndex: this.CurrentIndex,
+				MyChartClassifyId: this.selectMyChartClassify || 0
+			})
+            this.loading=false
+            const arr=res.Data?res.Data.List.filter(_=>!_.Disabled):[]
+            this.list=[...this.list,...arr]
+            if(!res.Data){
+                this.finished=true
+            }
+            if(res.Data&&res.Data.Paging.IsEnd){
+                this.finished=true
+            }
+		},
+
+        load(){
+            if(this.finished) return
+            this.CurrentIndex++
+            this.handleGetMyChartList()
+        },
+
+        handleImport:_.throttle(function(){
+            if(!this.selectMyChartClassify){
+                this.$message.warning(this.$t('ReportManage.ReportList.please_select_category'))
+                return
+            }
+            let filterList = this.list.filter(_ =>_.HaveOperaAuth)
+            if(filterList.length==0){
+                this.$message.warning(this.$t('ReportManage.ReportList.no_chart_msg'))
+                return
+            }
+            this.$emit('handleImportMyChart',filterList)
+            setTimeout(() => {
+                this.CurrentIndex=1
+                this.list=[]
+                this.finished=false
+                this.loading=false
+                this.selectMyChartClassify=''
+            }, 300);
+        },1000),
+
+        handleClickItem(){
+            this.$message.warning(this.$t('ReportManage.ReportList.no_one_charts'))
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+.import-mychart-wrap{
+    .list{
+        height: calc(100vh - 320px);
+        overflow-x: hidden;
+		overflow-y: auto;
+        .item{
+            width: 100%;
+            margin: 20px 0;
+            padding: 20px;
+            box-sizing: border-box;
+            border: 1px solid #eaeaea;
+            border-radius: 10px;
+            position: relative;
+            overflow: hidden;
+            p{
+                text-align: center;
+                font-size: 16px;
+                margin-bottom: 10px;
+                color: #5882EF;
+            }
+            img{
+                width: 100%;
+            }
+        }
+    }
+    .empty-box{
+        height: calc(100vh - 320px);
+        text-align: center;
+        color: #999;
+        padding-top: 100px;
+    }
+}
+</style>

+ 80 - 0
src/views/report_manage/reportV2/normalReport/components/insertContent.vue

@@ -0,0 +1,80 @@
+<template>
+  <div class="insert-content">
+    <!-- 图库插入 -->
+    <ETAChart 
+        v-if="actTab==='etaChart'"
+        @handleImportMyChart="handleImportMyChart"
+        @insertHtml="item => {$emit('insertHtml',{item})}"
+    />
+    <!-- ETA表格 -->
+    <ETASheet v-if="actTab==='etaSheet'" @insertHtml="item =>{$emit('insertHtml',{item,type:'sheet'})}"/>
+    <!-- 统计分析 -->
+    <StatisticAnalysis v-if="actTab==='statisticAnalysis'" @insertHtml="item => {$emit('insertHtml',{item})}"/>
+    <!-- 商品价格曲线 -->
+    <ETAPriceChart v-if="actTab==='etaPriceChart'" @insertHtml="item => {$emit('insertHtml',{item})}"/>
+    <!-- 沙盘图 -->
+    <ETASandBox v-if="actTab==='etaSandBox'" @insertHtml="item=>{$emit('insertHtml',{item,type:'image'})}"/>
+    <!-- 语义分析 -->
+    <SemanticAnalysis v-if="actTab==='semanticAnalysis'" @insertHtml="item => {$emit('insertHtml',{item,type:'image'})}"/>
+
+    <span
+			class="slide-icon"
+			@click="$emit('slide')"
+		>
+			<i :class="'el-icon-d-arrow-right'"></i>
+		</span>
+  </div>
+</template>
+<script>
+import ETAChart from './ETAChart.vue'
+import ETASheet from './ETASheet.vue'
+import StatisticAnalysis from './StatisticAnalysis.vue'
+import ETAPriceChart from './ETAPriceChart.vue'
+import ETASandBox from './ETASandBox.vue'
+import SemanticAnalysis from './SemanticAnalysis.vue'
+export default {
+  props: {
+    actTab: {
+      type: String
+    }
+  },
+  components: {ETAChart,ETASheet,StatisticAnalysis,ETAPriceChart,ETASandBox,SemanticAnalysis  },
+  data() {
+    return {
+    }
+  },
+  methods: {
+      handleImportMyChart(list){
+          this.$emit('handleImportMyChart',list)
+      }
+  }
+}
+</script>
+<style scoped lang='scss'>
+*{ box-sizing: border-box; }
+.insert-content {
+  width: 400px;
+  margin-left: 20px;
+  border: 1px solid #ccc;
+  padding: 15px;
+  background: #fff;
+  border-radius: 6px;
+  position: relative;
+
+  .slide-icon {
+		padding: 20px 0;
+		box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.3);
+		border-radius: 5px;
+		background-color: #fff;
+		cursor: pointer;
+		position: absolute;
+		top: 50%;
+		transform: translateY(-50%);
+		z-index: 99;
+    left: -15px;
+		&:hover {
+			background-color: #e0e0e0;
+		}
+	}
+}
+</style>

+ 618 - 0
src/views/report_manage/reportV2/normalReport/editReport.vue

@@ -0,0 +1,618 @@
+<template>
+	<div id="editreport">
+
+		<div class="editor-wrapper">
+			<!-- 顶部操作栏 -->
+			<editHeader
+				:reportInfo="{Title: aeForm.title}"
+				@handleClearContent="handleClearContent"
+				@openBaseInfo="showReportBaseInfo=true"
+				@handleRefreshAllChart="refreshReport"
+				@handlePreviewReport="clickreportadd('yl')"
+				@handleSaveContent="clickreportadd('cg')"
+				@handlePublishOpt="clickreportadd"
+			/>
+
+			<div class="editor-main">
+				<div 
+					id="leftfroala"
+					v-loading="importChartNum>0" 
+					:element-loading-text="$t('ReportManage.ReportList.chart_insertion_progress')"
+					element-loading-spinner="el-icon-loading"
+					element-loading-background="rgba(0, 0, 0, 0.8)"
+				>
+					<froala
+						ref="froalaEditor"
+						:tag="'textarea'"
+						:config="CNEditorConfig"
+						v-model="aeForm.content"
+					></froala>
+				</div>
+
+				<!-- 可插入内容 -->
+				<insertContent
+					v-if="activeTab"
+					:actTab="activeTab"
+					@slide="activeTab=''"
+					@insertHtml="insertHtml"
+					@handleImportMyChart="handleImportMyChart"
+				/>
+				
+			</div>
+
+			<!-- 可插入模块 -->
+			<ul class="fixed-insert-wrapper">
+					<li v-for="item in insertTabs" :key="item.type" @click="activeTab=item.type">
+						<img class="icon" :src="item.icon" alt="">
+						<span>{{item.name}}</span>
+					</li>
+			</ul>
+		</div>
+
+		<!-- 定时发布弹窗 -->
+		<el-dialog 
+			v-dialogDrag 
+			:append-to-body="true" 
+			:visible.sync="showDSFB" 
+			width="500px" 
+			:title="$t('ReportManage.ReportList.scheduled_publish_btn')"
+		>
+			<div>
+				<div>
+					<span>{{$t('ReportManage.ReportList.publish_time')}}</span>
+					<el-date-picker
+						v-model="taskTime"
+						type="datetime"
+						:placeholder="$t('ReportManage.ReportList.select_date_and_time')"
+						value-format="yyyy-MM-dd HH:mm"
+						:picker-options="timePickerOpt"
+					/>
+				</div>
+				<p style="margin:15px 0">{{$t('ReportManage.ReportList.the_report_will_be_posted_on_time')}}</p>
+				<div style="text-align:right;margin:20px 0">
+					<el-button type="primary" plain @click="showDSFB=false">{{$t('Dialog.cancel_btn')}}</el-button>
+					<el-button type="primary" @click="handleSetReportPrepublish">{{$t('Dialog.confirm_btn')}}</el-button>
+				</div>
+			</div>
+		</el-dialog>
+	</div>
+</template>
+
+<script>
+import {
+	autosave,
+	reportdetail,
+	reportedit,
+	classifylist,
+	reportpublish,
+	classifyIdDetail,
+	reportSetPrepublish,
+	departInterence
+} from 'api/api.js';
+import http from '@/api/http.js';
+import mixinMsg from './mixins/messagePush'
+import reportMixin from './mixins/reportMixin';
+import reportApproveConfig from "@/mixins/reportApproveConfig.js"
+import editHeader from '../components/reportEditHeader.vue';
+import insertContent from './components/insertContent.vue';
+export default {
+	mixins:[mixinMsg,reportMixin,reportApproveConfig],
+	components: {editHeader,insertContent},
+	data() {
+		var that = this;
+		return {
+			//批量导入图表
+			importChartNum:0,//批量导入图表的数量 如果大于0则说明在加载
+			report_id: this.$route.query.id,
+
+			aeForm: {
+				add_type: 1,
+				classify_name: 1,
+				classifynameArr: [],
+				title: '',
+				abstract: '',
+				author: ['投研团队'],
+				frequency: '日度',
+				create_time: http.dateFormatter(new Date(), false),
+				content: '',
+			},
+
+			optionsArr: [],
+
+			lastEditRange: null,
+			lastsavetime: '',
+			ThsMsgIsSend:'',//是否推送过客群
+
+			showReportBaseInfo: false,
+		};
+	},
+	mounted() {
+		this.getreportdetail();
+
+		this.getSystemUserInfo()
+		this.timer = setInterval(() => {
+			this.autoSave();
+		}, 6000);
+
+		window.addEventListener('message',this.reInitIframe)
+	},
+	updated() {
+		$('#leftfroala').find('p').css({ fontSize: '16px',width:'100%'});
+	},
+	destroyed() {
+		window.removeEventListener('message',this.reInitIframe)
+		if (this.timer) {
+			clearInterval(this.timer);
+		}
+	},
+
+	methods: {
+		// 每十秒自动保存
+		autoSave() {
+			console.log(this.ischange);
+			// if (this.ischange) {
+				if(!this.autoSaveFlag) return
+				//如果富文本中有未上传完成的图片,去除这个dom
+				$('.fr-element').find('img.fr-uploading').length&&$('.fr-element').find('img.fr-uploading').remove()
+				autosave({
+					ReportId: Number(this.$route.query.id),
+					Content: $('.fr-element').html(),
+					NoChange:this.ischange?0:1
+				}).then((res) => {
+					if (res.Ret === 200) {
+						this.report_id = res.Data.ReportId;
+						this.lastsavetime = http.dateFormatter(new Date(), true);
+					}
+				});
+				this.ischange = false;
+			// }
+		},
+		userclassidreportdetail() {
+			//检查classifynameArr是否有审批流
+			let classify = this.aeForm.classifynameArr.map(i=>{
+				return JSON.parse(i).v||0
+			})
+			this.checkClassifyNameArr(1,classify)
+
+			if (this.aeForm.add_type == 1) {
+				if (this.aeForm.classifynameArr.length == 2) {
+					this.aeForm.title = JSON.parse(this.aeForm.classifynameArr[1]).l;
+				}
+				return false;
+			}
+			if (this.aeForm.classifynameArr.length == 0) {
+				return false;
+			}
+			console.log(this.aeForm.classifynameArr);
+			let params = {
+				ClassifyIdFirst: JSON.parse(this.aeForm.classifynameArr[0]).v,
+			};
+			if (this.aeForm.classifynameArr.length == 2) {
+				params.ClassifyIdSecond = JSON.parse(
+					this.aeForm.classifynameArr[1]
+				).v;
+			} else {
+				params.ClassifyIdSecond = 0;
+			}
+			classifyIdDetail(params).then((res) => {
+				if (res.Ret == 200) {
+					if (res.Data == null) {
+						this.$message.error(this.$t('ReportManage.ReportList.no_reports_msg'));
+						return false;
+					}
+					this.aeForm = {
+						add_type: 2,
+						classify_name: 1,
+						classifynameArr:
+							res.Data.ClassifyIdSecond && res.Data.ClassifyNameSecond
+								? [
+										JSON.stringify({
+											l: res.Data.ClassifyNameFirst,
+											v: res.Data.ClassifyIdFirst,
+										}),
+										JSON.stringify({
+											l: res.Data.ClassifyNameSecond,
+											v: res.Data.ClassifyIdSecond,
+										}),
+								  ]
+								: [
+										JSON.stringify({
+											l: res.Data.ClassifyNameFirst,
+											v: res.Data.ClassifyIdFirst,
+										}),
+								  ],
+						title: res.Data.Title,
+						abstract: res.Data.Abstract,
+						author: res.Data.Author ? res.Data.Author.split(',') : '',
+						frequency: res.Data.Frequency,
+						create_time: res.Data.CreateTime,
+						content: res.Data.Content,
+					};
+				}
+			});
+		},
+	
+		getreportdetail() {
+			reportdetail({ ReportId: parseInt(this.report_id) }).then((res) => {
+				if (res.Ret == 200) {
+					let data = res.Data;
+					this.aeForm = {
+						add_type: parseInt(data.AddType),
+						classify_name: 1,
+						classifynameArr:
+							data.ClassifyIdSecond && data.ClassifyNameSecond
+								? [
+										JSON.stringify({
+											l: data.ClassifyNameFirst,
+											v: parseInt(data.ClassifyIdFirst),
+										}),
+										JSON.stringify({
+											l: data.ClassifyNameSecond,
+											v: parseInt(data.ClassifyIdSecond),
+										}),
+								  ]
+								: [
+										JSON.stringify({
+											l: data.ClassifyNameFirst,
+											v: parseInt(data.ClassifyIdFirst),
+										}),
+								  ],
+						title: data.Title,
+						abstract: data.Abstract,
+						author: data.Author ? data.Author.split(',') : '',
+						frequency: data.Frequency,
+						create_time: data.CreateTime,
+						content: data.Content,
+					};
+					this.ThsMsgIsSend=data.ThsMsgIsSend
+					// 回显定时发布时间
+					if(data.PrePublishTime){
+						this.taskTime=data.PrePublishTime
+					}
+					let classify = [data.ClassifyIdFirst,data.ClassifyIdSecond]
+					this.checkClassifyNameArr(1,classify)
+				}
+			});
+		},
+		clickreportadd(tp) {
+			if (
+				!this.aeForm.classifynameArr ||
+				this.aeForm.classifynameArr.length == 0
+			) {
+				this.$message.error(this.$t('ReportManage.ReportList.please_select_category'));
+				return false;
+			}
+			if (!this.aeForm.title) {
+				this.$message.error(this.$t('ReportManage.ReportList.input_title_please'));
+				return false;
+			}
+			if(!this.autoSaveFlag){
+				this.$message.error(this.$t('ReportManage.smart_msg.img_wait'))
+				return false
+			}
+			//如果富文本中有未上传完成的图片,去除这个dom
+			$('.fr-element').find('img.fr-uploading').length&&$('.fr-element').find('img.fr-uploading').remove()
+			let params = {
+				ReportId: parseInt(this.report_id),
+				AddType: this.aeForm.add_type,
+				ClassifyIdFirst: JSON.parse(this.aeForm.classifynameArr[0]).v,
+				ClassifyNameFirst: JSON.parse(this.aeForm.classifynameArr[0]).l,
+				Title: this.aeForm.title,
+				Abstract: this.aeForm.abstract,
+				Author:
+					this.aeForm.author.length > 0
+						? this.aeForm.author.join(',')
+						: '',
+				Frequency: this.aeForm.frequency,
+				// content:this.aeForm.content,create_time:this.aeForm.create_time
+				Content: $('.fr-element').html(),
+				CreateTime: this.aeForm.create_time,
+			};
+			if (this.aeForm.classifynameArr.length == 2) {
+				params.ClassifyIdSecond = JSON.parse(
+					this.aeForm.classifynameArr[1]
+				).v;
+				params.ClassifyNameSecond = JSON.parse(
+					this.aeForm.classifynameArr[1]
+				).l;
+			}
+			params.State = 1;
+			if (tp == 'yl') {
+				sessionStorage.setItem('reportdtl', JSON.stringify(params));
+				let { href } = this.$router.resolve({ name: '预览报告' });
+				window.open(href, '_blank');
+				return false;
+			}
+			if(tp=='fb'||tp=='submit'){
+				this.isPublishloading = true;
+			}
+			const isPost = this.permissionBtn.checkPermissionBtn(this.permissionBtn.reportManageBtn.reportManage_sendMsg)&&(!this.isApprove)
+			if (tp == 'fb') {
+				// 判断是否要推送客群
+				let hasTel=0
+				if(this.aeForm.classifynameArr.length == 2){
+					this.optionsArr.forEach(item=>{
+						item.children&&item.children.forEach(childItem=>{
+							if(JSON.parse(item.value).v==params.ClassifyIdSecond){
+								hasTel=childItem.HasTeleconference
+							}
+						})
+					})
+				}else{
+					this.optionsArr.forEach(item=>{
+						if(JSON.parse(item.value).v==params.ClassifyIdFirst){
+							hasTel=item.HasTeleconference
+						}
+					})
+				}
+				console.log(hasTel);
+				if(hasTel==1||this.ThsMsgIsSend==1){
+					this.isMessagePost = false; 
+					this.reporteditMsg(params,tp)
+				}else if(isPost){
+					this.$confirm(this.$t('ReportManage.smart_msg.publishing_messages'), this.$t('ReportManage.smart_release_prompt_btn'), {
+								confirmButtonText: this.$t('ReportManage.smart_btn.push'),
+								cancelButtonText: this.$t('ReportManage.smart_btn.not_push'),
+								type: 'warning',
+						    distinguishCancelAndClose:true,
+						    beforeClose:(action, instance,done)=>{
+						        console.log(action, instance);
+						        if(action==='close') {
+						            //右上角
+									this.isPublishloading = false;
+						        } else if(action==='cancel') {
+						            //cancelButton
+									this.isMessagePost = false; 
+									this.reporteditMsg(params,tp)
+						        }else {
+						           //confirmButton
+								   	this.isMessagePost = true; 
+									this.reporteditMsg(params,tp)
+						        }
+						        done()
+						    }
+					})
+				}else{
+					this.isMessagePost = false; 
+					this.reporteditMsg(params,tp)
+				}
+			}else {
+				this.reporteditMsg(params,tp)
+			}
+
+		},
+		publishreport(id,code) {
+			//发布报告
+			reportpublish({ ReportIds: String(id) ,ReportUrl:this.generatePdfLinks(code)}).then((res) => {
+				if (res.Ret == 200) {
+					this.isPublishloading = false;
+					this.$router.push({ path: '/reportlist' });
+				}
+			});
+		},
+		generatePdfLinks(Code){
+			const baseUrl= localStorage.getItem('dynamicOutLinks') ? JSON.parse(localStorage.getItem('dynamicOutLinks')).ReportViewUrl : '';
+			return `${baseUrl}/reportshare_pdf?code=${Code}&flag=${this.waterMarkStr}`
+		},
+		// 定时发布报告
+		handleSetReportPrepublish(){
+			if(!this.taskTime){
+				this.$message.warning(this.$t('ReportManage.smart_msg.select_push_time'))
+				return
+			}
+			const now=this.$moment().format('YYYY-MM-DD HH:mm:ss')
+			if(this.$moment(this.taskTime).isBefore(now,'second')){
+				this.$message.warning(this.$t('ReportManage.smart_msg.than_current_time'))
+				return
+			}
+			// return console.log(this.reportCode,'reportCode');
+			// 如果改报告已经推送过模板消息
+			if(this.ThsMsgIsSend==1){
+				reportSetPrepublish({
+					ReportId:Number(this.report_id),
+					PrePublishTime:this.taskTime,
+					PreMsgSend:0,
+					ReportUrl:this.generatePdfLinks(this.reportCode)
+				}).then(res=>{
+					if(res.Ret===200){
+						this.$message.success(this.$t('ReportManage.smart_msg.timed_success'))
+						this.$router.push({ path: '/reportlist' });
+					}
+				})
+				return
+			}
+			const isPost = this.permissionBtn.checkPermissionBtn(this.permissionBtn.reportManageBtn.reportManage_sendMsg)
+
+			this.$confirm(isPost?this.$t('ReportManage.smart_msg.push_report_msg'):this.$t('ReportManage.smart_msg.is_push_timed'), this.$t('ReportManage.smart_release_prompt_btn'), {
+				confirmButtonText: isPost?this.$t('ReportManage.smart_btn.push'):this.$t('ReportManage.smart_btn.publish'),
+				cancelButtonText: isPost?this.$t('ReportManage.smart_btn.not_push'):this.$t('Dialog.cancel_btn'),
+				type: 'warning',
+				distinguishCancelAndClose:true,
+				beforeClose:(action, instance,done)=>{
+					console.log(action, instance);
+					if(action==='close'||action==='cancel') {
+						//右上角或者不推送
+						if(isPost){
+							reportSetPrepublish({
+								ReportId:Number(this.report_id),
+								PrePublishTime:this.taskTime,
+								PreMsgSend:0,
+								ReportUrl:this.generatePdfLinks(this.reportCode)
+							}).then(res=>{
+								if(res.Ret===200){
+									this.$message.success(this.$t('ReportManage.smart_msg.timed_success'))
+									this.$router.push({ path: '/reportlist' });
+								}
+							})
+						}
+					} else {
+						//confirmButton
+						reportSetPrepublish({
+							ReportId:Number(this.report_id),
+							PrePublishTime:this.taskTime,
+							PreMsgSend:isPost?1:0,
+							ReportUrl:this.generatePdfLinks(this.reportCode)
+						}).then(res=>{
+							if(res.Ret===200){
+								this.$message.success(this.$t('ReportManage.smart_msg.timed_success'))
+								this.$router.push({ path: '/reportlist' });
+							}
+						})
+					}
+					done()
+				}
+			})
+
+		},
+
+		getclassifylist() {
+			//获取分类列表
+			let params = { Enabled:1, KeyWord: '' ,HideDayWeek:1,/*不显示晨报/周报*/ };
+			classifylist(params).then((res) => {
+				if (res.Ret == 200 && Array.isArray(res.Data.List)) {
+					this.optionsArr = [];
+					res.Data.List.forEach((item, index) => {
+						let newitem = {
+							label: item.ClassifyName,
+							value: JSON.stringify({
+								l: item.ClassifyName,
+								v: parseInt(item.Id),
+							}),
+							HasTeleconference:item.HasTeleconference
+						};
+						if (item.Child&&item.Child.length > 0) {
+							let childnode = [];
+							item.Child.forEach((itemchild, i) => {
+								childnode.push({
+									label: itemchild.ClassifyName,
+									value: JSON.stringify({
+										l: itemchild.ClassifyName,
+										v: parseInt(itemchild.Id),
+									}),
+									HasTeleconference:itemchild.HasTeleconference
+								});
+							});
+							newitem.children = childnode;
+						} else {
+							newitem.children = undefined;
+							newitem.disabled=true
+						}
+						this.optionsArr.push(newitem);
+					});
+				}
+			});
+		},
+		getSystemUserInfo(){
+      departInterence.systemUserInfo().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)
+            this.waterMarkStr=Base64.encode(waterMarkString)
+          }
+        }
+      })
+    },
+	},
+};
+</script>
+
+<style scoped lang="scss">
+#editreport {
+	display: flex;
+	overflow: hidden;
+	background: var(--unnamed, #F2F6FA);
+	.editor-wrapper {
+		position: relative;
+		flex: 1;
+		height: 100vh;
+		overflow: auto;
+		.top-action-wrap{
+				position: sticky;
+				top: 0;
+				background-color: #fff;
+				box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.10);
+				height: 60px;
+				z-index: 99;
+				display: flex;
+				justify-content: space-between;
+				align-content: center;
+				padding: 0 24px;
+				margin-bottom: 10px;
+				.title{
+						line-height: 60px;
+						font-size: 16px;
+				}
+				.action-list{
+						display: flex;
+						align-items: center;
+						.action-item{
+								height: 36px;
+								display: flex;
+								align-items: center;
+								border-right: 1px solid #C8CDD9;
+								padding: 0 30px;
+								font-size: 16px;
+								cursor: pointer;
+								img{
+										width: 16px;
+										height: 16px;
+										margin-right: 4px;
+										position: relative;
+										top: 2px;
+								}
+								&:last-child{
+										border-right: none;
+								}
+								&.disabled{
+										pointer-events: none;
+										cursor: not-allowed;
+										color:#999;
+								}
+						}
+				}
+		}
+		.editor-main {
+			display: flex;
+			padding: 20px 120px 20px 20px;
+		}
+	}
+	#leftfroala {
+		flex: 1;
+		overflow: hidden;
+	}
+
+	.fixed-insert-wrapper {
+		width: 90px;
+		background: #fff;
+		position: fixed;
+		right: 20px;
+		top: 10%;
+		li {
+			/* width: 100px; */
+			padding: 15px;
+			text-align: center;
+			cursor: pointer;
+			&:hover {
+				background: #dde1e4;
+			}
+			.icon {
+				display: block;
+				margin: 0 auto;
+			}
+		}
+
+	}
+}
+</style>
+<style lang="scss">
+#editreport {
+	.el-tabs__nav-wrap::after {
+		height: 0;
+	}
+	.el-tabs__item { font-size: 16px; }
+}	
+</style>

+ 178 - 0
src/views/report_manage/reportV2/normalReport/mixins/messagePush.js

@@ -0,0 +1,178 @@
+import { reportadd, reportedit, messagePushPost,dataBaseInterface,reportMessageSend } from "@/api/api.js";
+import {approveInterence} from '@/api/modules/approve.js';
+import * as sheetInterface from '@/api/modules/sheetApi.js';
+import { getUrlParams } from '@/utils/common'
+export default {
+  data() {
+    return {
+      isMessagePost: false,
+      isRightFormShow:true,
+      reportCode:''
+    };
+  },
+  methods: {
+    reporteditMsg(params2, tp) {
+      reportedit(params2).then(async (res) => {
+        if (res.Ret == 200) {
+          this.$message.success(res.Msg);
+          this.reportCode=res.Data.ReportCode
+          if (tp == "yl") {
+            // this.$router.push({name:'预览报告',query:{id:res.report_id}});
+            let { href } = this.$router.resolve({
+              name: "预览报告",
+              query: { id: res.Data.ReportId },
+            });
+            window.open(href, "_blank");
+          } else if (tp == "fb") {
+            if(this.isApprove){
+                await this.publishreport(res.Data.ReportId,res.Data.ReportCode);
+                return 
+            }
+            if (this.isMessagePost) {
+              await this.publishreport(res.Data.ReportId,res.Data.ReportCode);
+              await reportMessageSend({
+                ReportId: res.Data.ReportId,
+              }).then(() => {});
+            } else {
+              this.publishreport(res.Data.ReportId,res.Data.ReportCode);
+            }
+          } else if(tp=='dsfb'){
+            this.showDSFB=true
+            // this.$router.push({path:'/reportlist'});
+          }else if(tp=='submit'){
+            this.handleSubmitReport(res.Data.ReportId)
+          }
+        }
+      });
+    },
+    reportaddMsg(params, tp) {
+      reportadd(params).then(async (res) => {
+        if (res.Ret == 200) {
+          this.$message.success(res.Msg);
+          this.report_draft_id = res.Data.ReportId;
+          this.reportCode=res.Data.ReportCode
+          if (tp == "yl") {
+            // this.$router.push({name:'预览报告',query:{id:res.report_id}});
+            let { href } = this.$router.resolve({
+              name: "预览报告",
+              query: { id: res.Data.ReportId },
+            });
+            window.open(href, "_blank");
+          } else if (tp == "fb") {
+            if(this.isApprove){
+                await this.publishreport(res.Data.ReportId,res.Data.ReportCode);
+                return 
+            }
+            if (this.isMessagePost) {
+              await this.publishreport(res.Data.ReportId,res.Data.ReportCode);
+              await reportMessageSend({
+                ReportId: res.Data.ReportId,
+              }).then(() => {});
+            } else {
+              this.publishreport(res.Data.ReportId,res.Data.ReportCode);
+            }
+          } else if(tp=='dsfb'){
+            this.showDSFB=true
+            // this.$router.push({path:'/reportlist'});
+          }else if(tp=='submit'){
+            this.handleSubmitReport(res.Data.ReportId)
+          }
+          //已经添加过报告
+          this.isAddEnter = true;
+        }
+      });
+    },
+
+    //刷报告中的所有图表和表格
+    refreshReport: _.debounce ( async function() {
+      let code_arr = [];
+      let sheet_code_arr = []
+      $('iframe').each((k,i) => {
+        try {
+          let href = $(i).attr('src');
+          if(href.includes('chartshow')){
+            code_arr.push(getUrlParams(href,'code'));
+          }
+          if(href.includes('sheetshow')){
+            sheet_code_arr.push(getUrlParams(href,'code'))
+          }
+        } catch (err) {
+        }
+      });
+
+      if(!code_arr.length&&!sheet_code_arr.length) return this.$message.warning(this.$t('ReportManage.smart_msg.chart_is_table_msg'))
+
+      const fromPage = this.$route.path === "/reportEnEditor" ? "english_report" : "report";
+      if(this.$route.query.id&&code_arr.length) {
+        let res = await dataBaseInterface.getReportrefreshStatus({
+          Source: fromPage,
+          ReportId: Number(this.$route.query.id),
+          ReportChapterId: 0
+        });
+        
+        if(!res.Data.RefreshResult) return this.$message.warning(this.$t('ReportManage.ReportList.chart_refreshed_msg'))
+        const { Ret,Msg } = await dataBaseInterface.reportRefresh({
+            ChartInfoCode: code_arr
+          })
+          
+          if(Ret === 200) {
+            $('iframe').each((k,i) => {
+                let href = $(i).attr('src');
+                if(href.includes('chartshow')){
+                    $(i).attr('src',$(i).attr('src'))
+                }
+            });
+            this.$message.success(Msg);
+          }
+      }
+
+      if(this.$route.query.id&&sheet_code_arr.length){
+        //获取刷新结果
+        let res = await sheetInterface.getRefreshResult({
+            Source: fromPage,
+            ReportId: Number(this.$route.query.id),
+            ReportChapterId: 0
+          });
+        if(!res.Data.RefreshResult) return this.$message.warning(this.$t('ReportManage.ReportList.chart_refreshed_msg'))
+        const { Ret,Msg } = await sheetInterface.refreshSheet({
+            ExcelCodes: sheet_code_arr
+          })
+          
+          if(Ret === 200) {
+            $('iframe').each((k,i) => {
+                let href = $(i).attr('src');
+                if(href.includes('sheetshow')){
+                    $(i).attr('src',$(i).attr('src'))
+                }
+            });
+            this.$message.success(Msg);
+          }
+      }
+    },1000),
+    //展示提交审批弹窗
+    handleSubmitReport(id){
+        this.submitId = id
+        this.$confirm(this.$t('ReportManage.smart_msg.submit_approval'),this.$t('Confirm.prompt'),{
+          confirmButtonText: this.$t('Dialog.confirm_btn'),
+          cancelButtonText: this.$t('Dialog.cancel_btn'),
+          type:'warning',
+        }).then(()=>{
+            this.submitReport("submit")
+        })
+        
+    },
+    //提交审批
+    submitReport(type){
+        /* if(type==='submit'){ */
+            approveInterence.reportCnSubmit({
+                ReportId:Number(this.submitId)
+            }).then(res=>{
+                if(res.Ret!==200) return
+                this.$message.success(this.$t('ReportManage.smart_msg.submit_success'))
+                this.isPublishloading = false;
+                this.$router.push({ path: '/reportlist' });
+            })
+        /* } */
+    }
+  },
+};

+ 594 - 0
src/views/report_manage/reportV2/normalReport/mixins/reportMixin.js

@@ -0,0 +1,594 @@
+import * as sheetInterface from "@/api/modules/sheetApi.js";
+import { dataBaseInterface } from "@/api/api.js";
+import futuresInterface from "@/api/modules/futuresBaseApi";
+import chartRelevanceApi from "@/api/modules/chartRelevanceApi";
+import {
+  fittingEquationInterface,
+  statisticFeatureInterface,
+  crossVarietyInterface
+} from "@/api/modules/chartRelevanceApi";
+export default {
+  watch:{
+    'taskTime'(){
+          this.taskTime=this.$moment(this.taskTime).format('YYYY-MM-DD HH:mm')+':00'
+			    const date = this.$moment(this.taskTime).startOf('day').format('x');
+	        const nowDate = this.$moment().startOf('day').format('x');
+	        // 如果选择的是今天 则需要禁用已经过去的时间节点
+	        if (date <= nowDate) {
+	            // 默认选择的最新时间 是当前时间的两分钟后 (留出2分钟的富裕时间)
+	            this.timePickerOpt.selectableRange = (
+	                `${this.$moment().add(2,'m').format('HH:mm:ss')} - 23:59:59`
+	            );
+	        }else {
+				// 如果是以后的日期,则不需要禁用时间节点
+	            this.timePickerOpt.selectableRange = '00:00:00 - 23:59:59';
+	        }
+		},
+  },
+  computed:{
+      CNEditorConfig(){
+          return {...this.froalaConfig,...{fontFamily:{'Arial,Helvetica,sans-serif': 'Arial',
+          'Georgia,serif': 'Georgia',
+          'Impact,Charcoal,sans-serif': 'Impact',
+          'Tahoma,Geneva,sans-serif': 'Tahoma',
+          "'Times New Roman',Times,serif": 'Times New Roman',
+          'Verdana,Geneva,sans-serif': 'Verdana',
+          '思源宋体':'思源宋体',
+          '思源黑体':'思源黑体',}}
+        }
+      },
+      insertTabs(){
+        return [
+            {
+              name:this.$t('ReportManage.ReportList.chart_top_type'),
+              type:'etaChart',
+              icon:require('@/assets/img/smartReport/icon04.png')
+            },
+            {
+                name:this.$t('ReportManage.ReportList.eta_top_type'),
+                type:'etaSheet',
+                icon:require('@/assets/img/smartReport/icon05.png')
+            },
+            {
+                name:this.$t('ReportManage.ReportList.statistical_top_type'),
+                type:'statisticAnalysis',
+                icon:require('@/assets/img/smartReport/icon06.png')
+            },
+            {
+                name:this.$t('ReportManage.ReportList.price_curve_radio'),
+                type:'etaPriceChart',
+                icon:require('@/assets/img/smartReport/icon07.png')
+            },
+            {
+                name:this.$t('ReportManage.ReportList.sandbox_top_type'),
+                type:'etaSandBox',
+                icon:require('@/assets/img/smartReport/icon08.png')
+            },
+            {
+                name:this.$t('ReportManage.ReportList.semantic_top_type'),
+                type:'semanticAnalysis',
+                icon:require('@/assets/img/smartReport/icon09.png')
+            }
+          ]
+      },
+      
+      //语言版本
+      currentLang() {
+        return this.$store.state.lang
+      }
+  },
+  data() {
+    let that = this;
+    return {
+      editor: null,
+      froalaConfig: {
+        toolbarButtons: [
+          "insertImage",
+          "insertVideo",
+          "insertLink",
+          "embedly",
+          "insertFile",
+          "textColor",
+          "bold",
+          "italic",
+          "underline",
+          "strikeThrough",
+          "subscript",
+          "superscript",
+          "fontFamily",
+          "fontSize",
+          "color",
+          "inlineClass",
+          "inlineStyle",
+          "paragraphStyle",
+          "lineHeight",
+          "paragraphFormat",
+          "align",
+          "formatOL",
+          "formatUL",
+          "outdent",
+          "indent",
+          "quote",
+          "insertTable",
+          "emoticons",
+          "fontAwesome",
+          "specialCharacters",
+          "insertHR",
+          "selectAll",
+          "clearFormatting",
+          /* "html", */
+          "undo",
+          "redo",
+        ],
+        height: 800,
+        fontSize: ["12", "13","14","15", "16", "18", "20", "24", "28", "32", "36", "40"],
+        fontSizeDefaultSelection: "16",
+        theme: "dark", //主题
+        placeholderText: localStorage.getItem('i18n') == 'en' ? 'Please input content' : "请输入内容",
+        language: localStorage.getItem('i18n') == 'en' ? 'en' : "zh_cn", //国际化
+        imageUploadURL: process.env.VUE_APP_API_ROOT + "/report/uploadImg", //上传url
+        videoUploadURL: process.env.VUE_APP_API_ROOT + "/report/uploadImg", //上传url
+        fileUploadURL: process.env.VUE_APP_API_ROOT + "/report/uploadImg", //上传url 更多上传介绍 请访问https://www.froala.com/wysiwyg-editor/docs/options
+        imageDefaultWidth: false,
+        quickInsertButtons: ["image", "table", "ul", "ol", "hr"], //快速插入项
+        toolbarVisibleWithoutSelection: true, //是否开启 不选中模式
+        // disableRightClick:true,//是否屏蔽右击
+        // colorsHEXInput:false,//关闭16进制色值
+        toolbarSticky: false, //操作栏是否自动吸顶
+        // zIndex:99999,
+        saveInterval: 0,
+        events: {
+          //this.editor 定义在vue data 中
+          initialized: function () {
+            that.editor = this;
+          },
+          keyup: function (e, editor) {
+            //添加事件,在每次按键按下时,都记录一下最后停留位置
+            that.$nextTick(function () {
+              getSelection().rangeCount &&
+                (that.lastEditRange = getSelection().getRangeAt(0));
+            });
+          },
+          click: function (e, editor) {
+            //添加事件,在每次鼠标点击时,都记录一下最后停留位置
+            that.$nextTick(function () {
+              getSelection().rangeCount &&
+                (that.lastEditRange = getSelection().getRangeAt(0));
+            });
+          },
+          //内容改变事件
+          contentChanged: function () {
+            that.ischange = true;
+            that.lastEditRange = getSelection().rangeCount
+              ? getSelection().getRangeAt(0)
+              : 0;
+          },
+          //粘贴图片上传事件
+          "image.beforePasteUpload": function (img) {
+            //console.log('image.beforePasteUpload',img)
+            //暂停自动保存
+            that.autoSaveFlag = false;
+          },
+          //点击toolbar上传图片事件
+          "image.beforeUpload": function (imgs) {
+            //console.log('image.beforeUpload',imgs)
+            //暂停自动保存
+            that.autoSaveFlag = false;
+          },
+          "image.inserted": function ($img, response) {
+            //console.log('img-inserted',$img)
+            //开启自动保存
+            that.autoSaveFlag = true;
+          },
+          //如果上传图片出错,重置autoSaveFlag
+          "image.error": function (error, response) {
+            that.autoSaveFlag = true;
+          },
+          "paste.before":function(e,editor){
+            let content = e.clipboardData.getData('text/html');
+           // console.log(content)
+            var tempDiv = document.createElement('div');
+            tempDiv.innerHTML = content;
+            var iframes = tempDiv.querySelectorAll('iframe');
+            const srcArr = Array.from(iframes).map(i=>i.src)
+            //console.log(srcArr);
+            if(srcArr.filter(i=>!i.includes(that.$setting.dynamicOutLinks.ChartViewUrl)).length){
+                that.$message.warning("粘贴内容含有外链,请核对内容或粘贴纯文本")
+                return false
+            }
+          },
+        },
+        charCounterCount: false,
+        reportloadding: false,
+        lastsavetime: "",
+        isAddEnter: false, //是否已经添加过
+        timer: null,
+        ischange: false,
+        isPublishloading: false,
+      },
+
+      isPublishloading: false,
+      lastsavetime: "",
+
+      setEnName: false,
+      // 传入的formItem所需内容
+      formItemArray: [],
+      
+      activeTab: '',
+      chart_source: 1, //图表来源 1 eta 2 商品价格
+
+      //截面散点设置英文props
+      enChartInfo: {},
+      enEdblist: [],
+
+      autoSaveFlag: true, //是否开启自动保存
+
+      showDSFB:false,//显示定时发布弹窗
+			taskTime:'',//定时发布的时间
+			timePickerOpt:{
+				disabledDate(e){
+					return e.getTime()< new Date().getTime()-24 * 60 * 60 * 1000
+				},
+				selectableRange:'00:00:00 - 23:59:59',
+        format:'HH:mm'
+			},
+    };
+  },
+
+  methods: {
+    insertHtml({item, type = "chart"}) {
+      const noAuthMsg = {
+        'chart': this.$t('MsgPrompt.no_chart_auth'),
+        'sheet': this.$t('MsgPrompt.no_sheet_auth')
+      }
+      if(!item.HaveOperaAuth&&noAuthMsg[type]) return this.$message.warning(noAuthMsg[type])
+
+      //设置编辑器获取焦点
+      this.editor.events.focus();
+      // 获取选定对象
+      const selection = getSelection();
+      // 判断是否有最后光标对象存在
+      if (this.lastEditRange) {
+        // 存在最后光标对象,选定对象清除所有光标并添加最后光标还原之前的状态
+        selection.removeAllRanges();
+        selection.addRange(this.lastEditRange);
+      }
+
+      const insertMap = {
+        image: this.insertImage,
+        chart: this.insertChart,
+        sheet: this.insertSheet,
+      };
+      insertMap[type](item);
+      this.lastEditRange = selection.getRangeAt(0);
+    },
+
+    /* 插入图片 */
+    insertImage(item) {
+      this.$nextTick(() => {
+        this.editor.html.insert(
+          `<img style='width:100%' src='${item.PicUrl}' />`
+        );
+      });
+    },
+
+    /* 插入图表 */
+    insertChart(item) {
+      if (item.Disabled)
+        return this.$message.warning("内部图表,不允许插入报告");
+
+      const LINK_CHART_URL = this.$setting.dynamicOutLinks.ChartViewUrl+'/chartshow';
+      let lang = this.$route.path === "/reportEnEditor" ? "en" : this.currentLang;
+      
+      this.$nextTick(() => {
+        this.editor.html.insert(
+          `<p style='text-align:left; margin-top:10px;'>
+						<iframe src='${LINK_CHART_URL}?code=${item.UniqueCode}&lang=${lang}' width='100%' height='350' style='border-width:0px; min-height:350px;'></iframe>
+					</p>`
+        );
+      });
+    },
+
+    /* 插入表格 */
+    insertSheet(item) {
+      const LINK_URL = this.$setting.dynamicOutLinks.ChartViewUrl+'/sheetshow';
+
+      this.$nextTick(() => {
+        this.editor.html.insert(
+          `<p style='text-align:left; margin-top:10px;'>
+            <span style='font-size:17px'>${item.ExcelName}</span>
+            <iframe 
+              src='${LINK_URL}?code=${item.UniqueCode}&fromScene=2' 
+              width='100%' 
+              class='iframe${item.UniqueCode}' 
+              style='border-width:0px;'
+              />
+              </p>`
+        );
+      });
+    },
+
+    /* 适配iframe高度 */
+    reInitIframe(e) {
+      const { height, code } = e.data;
+      let iframeDom = document.getElementsByClassName(`iframe${code}`);
+      iframeDom.forEach((ele) => {
+        ele.height = `${height+1}px`;
+      });
+    },
+
+    //批量插入我的图表
+		handleImportMyChart(data){
+      console.log(data)
+			//设置编辑器获取焦点
+			this.editor.events.focus();
+			// 获取选定对象
+			const selection = getSelection();
+			// 判断是否有最后光标对象存在
+			if (this.lastEditRange) {
+				// 存在最后光标对象,选定对象清除所有光标并添加最后光标还原之前的状态
+				selection.removeAllRanges();
+				selection.addRange(this.lastEditRange);
+			}
+			//插入内容
+			let htmlStr=''
+			const LINK_CHART_URL = this.$setting.dynamicOutLinks.ChartViewUrl+'/chartshow';
+			
+			data.forEach(item=>{
+				const t=new Date().getTime()
+				item.domId=item.UniqueCode+t //避免多次添加同一图表 id相同
+				htmlStr=htmlStr+`<p style='text-align:left; margin-top:10px;'>
+							<iframe id='${item.domId}' src='${LINK_CHART_URL}?code=${item.UniqueCode}' width='100%' height='350' style='border-width:0px; min-height:350px;'></iframe>
+						</p>`
+			})
+			this.$nextTick(()=>{
+				console.log('import start',data);
+				this.importChartNum=data.length
+				this.editor.html.insert(htmlStr)
+				this.handleListenIframeLoad(data)
+			})
+			
+			this.lastEditRange = selection.getRangeAt(0);
+		},
+		// 监听批量导入的iframe是否加载完
+		handleListenIframeLoad(list){
+			list.forEach(item=>{
+				let ifm=document.getElementById(item.domId)
+				ifm.onload=(e)=>{
+					this.importChartNum--
+				}
+			})
+		},
+
+    /* 设置英文配置 */
+    async setEnHandle({ UniqueCode }) {
+      this.formItemArray = { chartInfo: [], chartsList: [] };
+
+      const { Ret, Data } = this.chart_source === 2
+        ? await futuresInterface.getChartBasicInfo({ UniqueCode })
+        : await dataBaseInterface.getChartByCode({ UniqueCode })
+
+      if (Ret !== 200) return;
+      let chartInfo = Data.ChartInfo;
+      let tableData = [2, 5].includes(chartInfo.Source)
+        ? [Data.EdbInfoList[0]]
+        : Data.EdbInfoList;
+
+      this.enChartInfo = chartInfo;
+      this.enEdblist = tableData;
+
+      this.formItemArray.chartInfo.push(
+        {
+          label: "图表名称",
+          value: chartInfo.ChartName,
+          key: "ChartName",
+          id: chartInfo.ChartInfoId,
+          source: chartInfo.Source,
+          notEdit: true,
+        },
+        {
+          label: "英文图表名称",
+          value: chartInfo.ChartNameEn,
+          key: "ChartNameEn",
+          id: chartInfo.ChartInfoId,
+          placeholder: "请输入英文图表名称",
+        }
+      );
+      if ([1,2,5].includes(chartInfo.Source)) {
+        this.formItemArray.chartsList = tableData.map((item) => {
+          return item.Unit
+            ? [
+                {
+                  label: "指标名称",
+                  value: item.EdbName,
+                  key: "EdbName",
+                  id: item.EdbInfoId,
+                  notEdit: true,
+                },
+                {
+                  label: "单位",
+                  value: item.Unit,
+                  key: "Unit",
+                  id: item.EdbInfoId,
+                  notEdit: true,
+                },
+                {
+                  label: "英文指标名称",
+                  value: item.EdbNameEn,
+                  key: "EdbNameEn",
+                  id: item.EdbInfoId,
+                  placeholder: "请输入英文指标名称",
+                },
+                {
+                  label: "英文单位",
+                  value: item.UnitEn,
+                  key: "UnitEn",
+                  id: item.EdbInfoId,
+                  placeholder: "请输入英文单位",
+                },
+              ]
+            : [
+                {
+                  label: "指标名称",
+                  value: item.EdbName,
+                  key: "EdbName",
+                  id: item.EdbInfoId,
+                  notEdit: true,
+                },
+                {
+                  label: "英文指标名称",
+                  value: item.EdbNameEn,
+                  key: "EdbNameEn",
+                  id: item.EdbInfoId,
+                  placeholder: "请输入英文指标名称",
+                },
+              ];
+        });
+      }
+
+      //价格曲线
+      if (chartInfo.Source === 2) {
+        this.formItemArray.chartInfo.push(
+          {
+            label: "期货名称",
+            value: Data.EdbInfoList[1].EdbName,
+            key: "FutureGoodName",
+            id: chartInfo.ChartInfoId,
+            notEdit: true,
+          },
+          {
+            label: "英文期货名称",
+            value: Data.EdbInfoList[1].EdbNameEn,
+            key: "FutureGoodNameEn",
+            id: chartInfo.ChartInfoId,
+            placeholder: "请输入英文期货名称",
+          }
+        );
+      }
+
+      //利润曲线
+      else if (chartInfo.Source === 5) {
+        this.formItemArray.chartInfo.push(
+          {
+            label: "盘面利润名称",
+            value: Data.DataResp.ProfitName,
+            key: "ProfitName",
+            id: chartInfo.ChartInfoId,
+            notEdit: true,
+          },
+          {
+            label: "英文盘面利润名称",
+            value: Data.DataResp.ProfitNameEn,
+            key: "ProfitNameEn",
+            id: chartInfo.ChartInfoId,
+            placeholder: "请输入英文盘面利润名称",
+          }
+        );
+      }
+
+       //跨品种分析
+      else if(chartInfo.Source===10) {
+        let res = await crossVarietyInterface.chartLangOption({ChartInfoId: chartInfo.ChartInfoId})
+
+        const { TagList,VarietyList } = res.Data;
+
+        this.formItemArray.chartInfo.push({
+          label:'X轴名称',
+          value:Data.DataResp.XName,
+          key:'XName',
+          id:TagList[0].ChartTagId,
+          notEdit:true
+        },
+        {
+          label:'英文X轴名称',
+          value:Data.DataResp.XNameEn,
+          key:'XNameEn',
+          id:TagList[0].ChartTagId,
+          placeholder:'请输入英文X轴名称'
+        },{
+          label:'Y轴名称',
+          value:Data.DataResp.YName,
+          key:'YName',
+          id:TagList[1].ChartTagId,
+          notEdit:true
+        },
+        {
+          label:'英文Y轴名称',
+          value:Data.DataResp.YNameEn,
+          key:'YNameEn',
+          id:TagList[1].ChartTagId,
+          placeholder:'请输入英文Y轴名称'
+        })
+
+        VarietyList.forEach(item => {
+          this.formItemArray.chartsList.push([
+            {
+              label:'品种名称',
+              value:item.ChartVarietyName,
+              key:'ChartVarietyName',
+              id:item.ChartVarietyId,
+              notEdit:true
+            },
+            {
+              label:'英文品种名称',
+              value:item.ChartVarietyNameEn,
+              key:'ChartVarietyNameEn',
+              id:item.ChartVarietyId,
+              placeholder:'请输入英文品种名称'
+            }
+          ])
+        })
+      }
+      this.setEnName = true;
+    },
+
+    // 更新英文信息
+    async updateEnName(enNameData) {
+      let res = null;
+      if (this.chart_source === 1) {
+        res = await dataBaseInterface.chartInfoEditEn(enNameData);
+      } else if ([2, 5].includes(this.chart_source)) {
+        res = await futuresInterface.editChartEn({
+          ChartInfoId: enNameData.ChartInfoId,
+          ChartNameEn: enNameData.ChartNameEn,
+          UnitEn: enNameData.ChartEdbInfoList[0].UnitEn || "",
+          EdbNameEn: enNameData.ChartEdbInfoList[0].EdbNameEn || "",
+          FutureGoodNameEn: enNameData.FutureGoodNameEn || "",
+          ProfitNameEn: enNameData.ProfitNameEn || "",
+        });
+      } else if (this.chart_source === 3) {
+        res = await chartRelevanceApi.editChartEn({
+          ChartInfoId: enNameData.ChartInfoId,
+          ChartNameEn: enNameData.ChartNameEn,
+        });
+      } else if (this.chart_source === 6) {
+        //拟合方程
+        res = await fittingEquationInterface.editChartEn({
+          ChartInfoId: enNameData.ChartInfoId,
+          ChartNameEn: enNameData.ChartNameEn,
+        });
+      } else if (this.chart_source === 7) {
+        //统计特征
+        res = await statisticFeatureInterface.editChartEn({
+          ChartInfoId: enNameData.ChartInfoId,
+          ChartNameEn: enNameData.ChartNameEn,
+        });
+      }else if (this.chart_source === 10) {
+        res=await crossVarietyInterface.editChartEn(enNameData)
+      }
+
+      if (res.Ret !== 200) return;
+
+      this.$message({
+        message: res.Msg,
+        type: "success",
+      });
+      this.setEnName = false;
+    },
+
+    handleClearContent() {
+
+    }
+  },
+
+};

+ 0 - 23
src/views/report_manage/reportV2/normalReportEditor.vue

@@ -1,23 +0,0 @@
-<template>
-  <div>
-
-  </div>
-</template>
-<script>
-export default {
-  data() {
-    return {
-
-    }
-  },
-  mounted(){
-
-  },
-  methods:{
-
-  },
-}
-</script>
-<style scoped lang='scss'>
-
-</style>

+ 316 - 0
src/views/report_manage/reportV2/smartReport/components/BaseInfo.vue

@@ -0,0 +1,316 @@
+<template>
+    <el-dialog
+        :title="$t('ReportManage.ReportList.information_title')"
+        :visible.sync="show"
+        :modal-append-to-body="false"
+        :close-on-click-modal="false"
+        :center="true"
+        v-dialogDrag
+        custom-class="dialogclass"
+        width="440px"
+        @close="handleClose"
+    >
+        <el-form 
+            :model="formData" 
+            :rules="rules" 
+            ref="baseinfoForm"
+            class="baseinfo-form-wrap"
+        >  
+            <el-form-item prop="type">
+                <el-radio-group v-model="formData.type" :disabled="id" @change="handleUpdateBaseInfo">
+                    <el-radio :label="1">{{$t('ReportManage.ReportList.new_report_radio')}}</el-radio>
+                    <el-radio :label="2">{{$t('ReportManage.ReportList.inherit_report_radio')}}</el-radio>
+                </el-radio-group>
+            </el-form-item>
+            <el-form-item prop="classify">
+                <el-cascader
+					ref="cascader"
+					:options="classifyArr"
+					v-model="formData.classify"
+					:placeholder="$t('ReportManage.ReportList.please_select_category')"
+					size="medium"
+                    style="width:340px"
+                    @change="handleUpdateBaseInfo"
+				/>
+            </el-form-item>
+            <el-form-item prop="title">
+                <el-input :placeholder="$t('ReportManage.ReportList.input_title_please')" v-model="formData.title" style="width:340px"></el-input>
+            </el-form-item>
+            <el-form-item prop="abstract">
+                <el-input type="textarea" :placeholder="$t('ReportManage.ReportList.please_input_abstract')" v-model="formData.abstract" style="width:340px"></el-input>
+            </el-form-item>
+            <el-form-item prop="author">
+				<el-select
+					v-model="formData.author"
+					multiple
+					:placeholder="$t('ReportManage.ReportList.please_select_author')"
+					size="medium"
+					style="width: 340px"
+				>
+					<el-option
+						v-for="(item, i) in authorlist"
+						:key="i"
+						:label="item.ReportAuthor"
+						:value="item.ReportAuthor"
+					></el-option>
+				</el-select>
+			</el-form-item>
+            <el-form-item prop="frequency">
+                <el-select
+					v-model="formData.frequency"
+					:placeholder="$t('ReportManage.ReportList.please_select_frequency')"
+					size="medium"
+					style="width: 340px"
+				>
+                    <el-option :label="$t('ReportManage.smart_annually')" :value="$t('ReportManage.smart_annually')"></el-option>
+                    <el-option :label="$t('ReportManage.smart_semi_annually')" :value="$t('ReportManage.smart_semi_annually')"></el-option>
+                    <el-option :label="$t('ReportManage.smart_quarterly')" :value="$t('ReportManage.smart_quarterly')"></el-option>
+                    <el-option :label="$t('ReportManage.smart_monthly')" :value="$t('ReportManage.smart_monthly')"></el-option>
+                    <el-option :label="$t('ReportManage.smart_bi_weekly')" :value="$t('ReportManage.smart_bi_weekly')"></el-option>
+                    <el-option :label="$t('ReportManage.smart_weekly')" :value="$t('ReportManage.smart_weekly')"></el-option>
+                    <el-option :label="$t('ReportManage.smart_daily')" :value="$t('ReportManage.smart_daily')"></el-option>
+                    <el-option :label="$t('ReportManage.smart_irregularly')" :value="$t('ReportManage.smart_irregularly')"></el-option>
+                </el-select>
+            </el-form-item>
+            <el-form-item prop="time">
+                <el-date-picker
+					v-model="formData.time"
+					type="date"
+					value-format="yyyy-MM-dd"
+					:placeholder="$t('ReportManage.ReportList.please_select_date')"
+					size="medium"
+					:clearable="false"
+					style="width: 340px"
+				></el-date-picker>
+            </el-form-item>
+        </el-form>
+        <div style="text-align:center;margin-top:60px;margin-bottom:40px">
+            <el-button type="primary" plain style="width:120px" @click="handleClose">{{$t('Dialog.cancel_btn')}}</el-button>
+            <el-button type="primary" style="width:120px" @click="handleConfirm">{{$t('Dialog.confirm_btn')}}</el-button>
+        </div>
+    </el-dialog>
+</template>
+
+<script>
+import {apiSmartReport}  from '@/api/modules/smartReport'
+export default {
+    name:"BaseInfo",
+    model:{
+        prop:'show',
+        event:'showChange'
+    },
+    props:{
+        show:{
+            type:Boolean,
+            default:false
+        },
+        id:{
+            type:Number,
+            default:0
+        }
+    },
+    watch: {
+        show(n){
+            if(!n){
+                this.formData.type=1
+                this.formData.classify=[]
+                this.formData.title=''
+                this.formData.abstract=''
+                this.formData.author=['投研团队']
+                this.formData.frequency='日度'
+                this.formData.time=this.$moment().format('YYYY-MM-DD')
+            }else{
+                if(this.id){
+                    apiSmartReport.reportDetail({
+                        SmartReportId:Number(this.id)
+                    }).then(res=>{
+                        if(res.Ret===200){
+                            this.formData.type=res.Data.AddType
+                            this.formData.classify=[res.Data.ClassifyIdFirst,res.Data.ClassifyIdSecond]
+                            this.formData.title=res.Data.Title
+                            this.formData.abstract=res.Data.Abstract
+                            this.formData.author=res.Data.Author ? res.Data.Author.split(',') : []
+                            this.formData.frequency=res.Data.Frequency
+                            this.formData.time=res.Data.CreateTime
+                        }
+                    })
+                }
+            }
+        }  
+    },
+    data() {
+        return {
+            
+            formData:{
+                type:1,
+                classify:[],
+                title:'',
+                abstract:'',
+                author:['投研团队'],
+                frequency:'日度',
+                time:this.$moment().format('YYYY-MM-DD')||''
+            },
+            classifyArr:[],
+            authorlist:[]
+        }
+    },
+    computed:{
+        rules(){
+            return {
+                type:[{ required: true, message: this.$t('ReportManage.ReportList.please_report_type_select'), trigger: 'change' }],
+                classify:[{ required: true, message: this.$t('ReportManage.ReportList.please_report_type_select'), trigger: 'change' }],
+                title:[{ required: true, message: this.$t('ReportManage.ReportList.please_report_title_input'), trigger: 'blur' }],
+            }
+        }
+    },
+    methods: {
+        handleClose(){
+            this.$emit('showChange', false)
+        },
+
+        handleConfirm(){
+            this.$refs.baseinfoForm.validate((valid)=>{
+                if(valid){
+
+                    const params={
+                        AddType: this.formData.type,
+                        ClassifyIdFirst: this.formData.classify[0]?this.formData.classify[0]:0,
+                        ClassifyNameFirst: '',
+                        ClassifyIdSecond:this.formData.classify[1]?this.formData.classify[1]:0,
+                        ClassifyNameSecond:'',
+                        Title: this.formData.title,
+                        Abstract: this.formData.abstract,
+                        Author:
+                            this.formData.author.length > 0
+                                ? this.formData.author.join(',')
+                                : '',
+                        Frequency: this.formData.frequency,
+                        CreateTime: this.formData.time,
+                    }
+                    this.classifyArr.forEach(item=>{
+                        if(item.value===params.ClassifyIdFirst){
+                            params.ClassifyNameFirst=item.label
+                            const arr=item.children||[]
+                            arr.forEach(_item=>{
+                                if(_item.value===params.ClassifyIdSecond){
+                                    params.ClassifyNameSecond=_item.label
+                                }
+                            })
+                        }
+                    })
+                    // 编辑
+                    if(this.id){
+                        this.$emit('save',params)
+                        return
+                    }
+                    apiSmartReport.reportAdd(params).then(res=>{
+                        if(res.Ret===200){
+                            this.handleClose()
+                            let { href } = this.$router.resolve({
+                                path: "/smartReportEdit",
+                                query: { id: res.Data.SmartReportId },
+                            });
+                            window.open(href, "_blank");
+                        }
+                    })
+
+                }
+            })
+        },
+
+        handleUpdateBaseInfo(){
+            if(this.formData.type===1){
+                if(this.formData.classify.length===2){
+                    this.formData.title=this.getSelectClassifyName()[1]
+                }
+                return
+            }
+            //获取上次报告
+            apiSmartReport.getLastReport({
+                ClassifyIdFirst:this.formData.classify[0],
+                ClassifyIdSecond:this.formData.classify[1]
+            }).then(res=>{
+                if(res.Ret!==200) return
+                if (res.Data == null) {
+					this.$message.warning(this.$t('ReportManage.ReportList.no_reports_msg'));
+					return false;
+				}
+                this.formData.title=res.Data.Title
+                this.formData.abstract=res.Data.Abstract
+                this.formData.author=res.Data.Author ? res.Data.Author.split(',') : ''
+                this.formData.frequency=res.Data.Frequency
+            })
+        },
+
+        // 获取选择的分类名称
+        getSelectClassifyName(){
+            let arr=[]
+            this.classifyArr.forEach(item=>{
+                if(this.formData.classify[0]&&item.value===this.formData.classify[0]){
+                    arr.push(item.label)
+                    if(item.children&&item.children.length>0){
+                        item.children.forEach(_item=>{
+                            if(this.formData.classify[1]&&_item.value===this.formData.classify[1]){
+                                arr.push(_item.label)
+                            }
+                        })
+                    }
+                }
+            })
+            return arr
+        },
+
+        // 获取分类
+        getclassifylist() {
+            let params = { Enabled:1, KeyWord: "",HideDayWeek:1,/*不显示晨报/周报*/ };
+            apiSmartReport.classifyList(params).then((res) => {
+                if (res.Ret == 200 && Array.isArray(res.Data.List)) {
+                    this.classifyArr = [];
+                    res.Data.List.forEach((item, index) => {
+                        let newitem = {
+                            label: item.ClassifyName,
+                            value: item.Id,
+                        };
+                        if (item.Child) {
+                            let childnode = [];
+                            item.Child.forEach((itemchild, i) => {
+                                childnode.push({
+                                    label: itemchild.ClassifyName,
+                                    value: itemchild.Id,
+                                });
+                            });
+                            newitem.children = childnode;
+                        }
+                        this.classifyArr.push(newitem);
+                    });
+                }
+            });
+        },
+        // 获取作者
+        getreportauthor() {
+			apiSmartReport.reportAuthor({}).then((res) => {
+				if (res.Ret == 200) {
+					this.authorlist = res.Data.List || [];
+				}
+			});
+		},
+    },
+    mounted(){
+        this.getclassifylist()
+        this.getreportauthor()
+    },
+}
+</script>
+
+<style lang="scss">
+.baseinfo-form-wrap{
+    .el-input{
+        width: 100%;
+    }
+    .el-form-item{
+        width: 340px;
+        margin-left: auto;
+        margin-right: auto;
+    }
+}
+</style>

+ 20 - 0
src/views/report_manage/reportV2/smartReport/components/ChartComp.vue

@@ -0,0 +1,20 @@
+<template>
+    <div 
+        class="report-comp-item chart-comp"
+        style="width:100%;height:100%;overflow: hidden;display:flex;flex-direction: column;"
+    >
+        <iframe :src="compData.content" style="flex:1;width:100%;height:100%;border-width:0px;"></iframe>
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        compData:{}
+    }
+}
+</script>
+
+<style>
+
+</style>

+ 106 - 0
src/views/report_manage/reportV2/smartReport/components/ETAChart.vue

@@ -0,0 +1,106 @@
+<template>
+    <div class="eta-chart-wrap">
+        <div class="top-box">
+            <div class="left-card">
+                <span :class="['item',activeType==='ETA图库'?'active':'']" @click="activeTypeChange('ETA图库')">{{$t('ReportManage.ReportList.chart_inventory_radio')}}</span>
+                <span :class="['item',activeType==='MyETA'?'active':'']" @click="activeTypeChange('MyETA')">{{$t('MyEtaPage.tab_my')}}</span>
+            </div>
+            <div class="right">
+                <el-input
+                    class="search-box"
+					:placeholder="$t('ReportManage.ReportList.chart_name')"
+					v-model="keyword"
+					size="medium"
+					prefix-icon="el-icon-search"
+                    v-if="activeType==='ETA图库'"
+                    @input="handleETAChartSearch"
+				/>
+            </div>
+        </div>
+        <div class="main-box">
+            <ImportETAChart ref="ETAChartWrap" v-if="activeType==='ETA图库'"/>
+            <ImportMyETAChart @handleImportMyChart="handleImportMyChart" v-if="activeType==='MyETA'"/>
+        </div>
+    </div>
+</template>
+
+<script>
+import ImportETAChart from './ImportETAChart.vue';
+import ImportMyETAChart from './ImportMyETAChart.vue';
+export default {
+    name:"ETAChartWrap",
+    components:{ImportETAChart,ImportMyETAChart},
+    data() {
+        return {
+            keyword:'',
+            activeType:'ETA图库',
+        }
+    },
+    methods: {
+        activeTypeChange(e){
+            if(this.activeType===e) return
+            this.activeType=e
+        },
+
+        handleETAChartSearch(){
+            this.$refs.ETAChartWrap.handleSearch(this.keyword)
+        },
+
+        handleImportMyChart(list){
+            this.$emit('handleImportMyChart',list)
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.eta-chart-wrap{
+    width: 100%;
+    min-width: 600px;
+    overflow-x: auto;
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .left-card{
+            border-radius: 4px;
+            border: 1px solid var(--unnamed, #DCDFE6);
+            background: var(--gary-gy-3-disabled, #EBEFF6);
+            display: flex;
+            align-items: center;
+            padding: 6px;
+            .item{
+                cursor: pointer;
+                display: block;
+                width: 110px;
+                height: 30px;
+                line-height: 30px;
+                text-align: center;
+                border-radius: 4px;
+                font-size: 18px;
+                color: #666;
+                &.active{
+                    background: #FFF;
+                    color: #002D78;
+                }
+            }
+        }
+        .right{
+            .search-box{
+                width: 330px;
+            }
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 0 20px 20px 20px;
+    }
+}
+</style>

+ 180 - 0
src/views/report_manage/reportV2/smartReport/components/ETAPriceChart.vue

@@ -0,0 +1,180 @@
+<template>
+    <div class="statistic-analysis-wrap">
+        <div class="top-box">
+            <div class="left-card">
+                <span>{{$t('ReportManage.ReportList.price_curve_radio')}}</span>
+            </div>
+            <div class="right">
+                <el-input
+                    class="search-box"
+					placeholder="图表名称"
+					v-model="keyword"
+					size="medium"
+					prefix-icon="el-icon-search"
+                    @input="handleSearch"
+				/>
+            </div>
+        </div>
+        <div class="main-box">
+            <el-checkbox
+                class="onlyshowme-box"
+                v-model="isShowMe" 
+                @change="handleIsShowMeChange"
+            >{{$t('ReportManage.ReportList.just_mine_radio')}}</el-checkbox>
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+                <draggable
+                    :list="list"
+                    :group="{ name: 'component', pull: 'clone', put: false }"
+                    class="chart-list-box"
+                    animation="300"
+                    :sort="false"
+                    tag="div"
+                >
+                    <div class="chart-item" :comp-data="getCompData(item)" v-for="item in list" :key="item.UniqueCode">
+                        <div class="title">{{item.ChartName}}</div>
+                        <div class="img" :style="'backgroundImage:url('+item.ChartImage+')'"></div>
+                    </div>
+                </draggable>
+                <tableNoData :text="$t('ReportManage.ReportList.no_chart_table_available')" size="mini" v-if="list.length===0&&finished"/>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import futuresInterface from "@/api/modules/futuresBaseApi";
+export default {
+    data() {
+        return {
+            
+            keyword:'',
+            isShowMe:false,
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+            loading:false
+        }
+    },
+    created(){
+        this.getChartList()
+    },
+    methods: {
+        // 生产随机id
+        getCompId(type){
+            return type+new Date().getTime()
+        },
+
+        getCompData(item){
+            const LINK_CHART_URL = this.$setting.dynamicOutLinks.ChartViewUrl+'/chartshow';
+            const obj={
+                compId:3,
+                compType:'chart',
+                content:`${LINK_CHART_URL}?code=${item.UniqueCode}`
+            }
+            return JSON.stringify(obj)
+        },
+
+        handleIsShowMeChange(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getChartList()
+        },
+
+        handleSearch(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getChartList()
+        },
+
+        /* 搜索图表分页 */
+        async getChartList(word) {
+            let params = {
+                Keyword: this.keyword || "",
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+                IsShowMe: this.isShowMe,
+            };
+            this.loading=true
+            let res = await futuresInterface.searchChart(params);
+            this.loading=false
+            if (res.Ret !== 200) return;
+            const arr = res.Data.List || [];
+            this.list =
+                this.page === 1
+                ? arr
+                : [...this.list, ...arr];
+            this.finished =  res.Data.Paging.IsEnd;
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getChartList()
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .right{
+            .search-box{
+                width: 330px;
+            }
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            flex: 1;
+            overflow-y: auto;
+
+        }
+    }
+}
+.chart-list-box{
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20px;
+    .chart-item{
+                cursor: move;
+                padding: 0 10px;
+                width: 250px;
+                border-radius: 4px;
+                border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+                background: var(--gary-gy-white, #FFF);
+                .title{
+                    padding: 10px 0;
+                    text-align: center;
+                    border-bottom: 1px solid #C8CDD9;
+                    overflow: hidden;
+                    white-space: nowrap;
+                    text-overflow: ellipsis;
+                }
+                .img{
+                    width: 100%;
+                    height: 197px;
+                    background-size: cover;
+                    background-position: center;
+                    background-repeat: no-repeat;
+                }
+            }
+}
+</style>

+ 172 - 0
src/views/report_manage/reportV2/smartReport/components/ETASandBox.vue

@@ -0,0 +1,172 @@
+<template>
+    <div class="statistic-analysis-wrap">
+        <div class="top-box">
+            <div class="left-card">
+                <span>{{$t('ReportManage.ReportList.sandbox_top_type')}}</span>
+            </div>
+            <div class="right">
+                <el-input
+                    class="search-box"
+					:placeholder="$t('ReportManage.ReportList.no_reports_msg')"
+					v-model="keyword"
+					size="medium"
+					prefix-icon="el-icon-search"
+                    @input="handleSearch"
+				/>
+            </div>
+        </div>
+        <div class="main-box">
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+                <draggable
+                    :list="list"
+                    :group="{ name: 'component', pull: 'clone', put: false }"
+                    class="chart-list-box"
+                    animation="300"
+                    :sort="false"
+                    tag="div"
+                >
+                    <div class="chart-item" :comp-data="getCompData(item)" v-for="item in list" :key="item.SandboxId">
+                        <div class="title">{{item.Name}}</div>
+                        <div class="img" :style="'backgroundImage:url('+item.PicUrl+')'"></div>
+                    </div>
+                </draggable>
+                <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-if="list.length===0&&finished"/>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import {sandInterface} from "@/api/api.js";
+export default {
+    data() {
+        return {
+            
+            keyword:'',
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+            loading:false
+        }
+    },
+    created(){
+        this.getSandBoxList()
+    },
+    methods: {
+        // 生产随机id
+        getCompId(type){
+            return type+new Date().getTime()
+        },
+
+        getCompData(item){
+            const obj={
+                compId:2,
+                compType:'img',
+                content:item.PicUrl
+            }
+            return JSON.stringify(obj)
+        },
+
+        handleIsShowMeChange(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getSandBoxList()
+        },
+
+        handleSearch(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getSandBoxList()
+        },
+
+        /* 搜索图表分页 */
+        async getSandBoxList(word) {
+            let params = {
+                Keyword: this.keyword || "",
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+            };
+            this.loading=true
+            let res = await sandInterface.sandlistByQuote(params);
+            this.loading=false
+            if (res.Ret !== 200) return;
+            const arr = res.Data.List || [];
+            this.list =
+                this.page === 1
+                ? arr
+                : [...this.list, ...arr];
+            this.finished =  res.Data.Paging.IsEnd;
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getSandBoxList()
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .right{
+            .search-box{
+                width: 330px;
+            }
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            flex: 1;
+            overflow-y: auto;
+
+        }
+    }
+}
+.chart-list-box{
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20px;
+    .chart-item{
+                cursor: move;
+                padding: 0 10px;
+                width: 250px;
+                border-radius: 4px;
+                border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+                background: var(--gary-gy-white, #FFF);
+                .title{
+                    padding: 10px 0;
+                    text-align: center;
+                    border-bottom: 1px solid #C8CDD9;
+                    overflow: hidden;
+                    white-space: nowrap;
+                    text-overflow: ellipsis;
+                }
+                .img{
+                    width: 100%;
+                    height: 197px;
+                    background-size: contain;
+                    background-position: center;
+                    background-repeat: no-repeat;
+                }
+            }
+}
+</style>

+ 172 - 0
src/views/report_manage/reportV2/smartReport/components/ETASheet.vue

@@ -0,0 +1,172 @@
+<template>
+    <div class="eta-sheet-wrap">
+        <div class="top-box">
+            <span>{{$t('ReportManage.ReportList.eta_top_type')}}</span>
+            <el-input
+                class="search-box"
+				:placeholder="$t('ReportManage.ReportList.table_name_tabs')"
+				v-model="keyword"
+				size="medium"
+				prefix-icon="el-icon-search"
+                @input="handleSearch"
+			/>
+        </div>
+        <div class="main-box">
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+            <draggable
+                :list="list"
+                :group="{ name: 'component', pull: 'clone', put: false }"
+                class="sheet-list-box"
+                animation="300"
+                :sort="false"
+                tag="div"
+                :move="onMoveItemHandle"
+            >
+                <div class="sheet-item" :comp-data="getCompData(item)" v-for="item in list" :key="item.ExcelInfoId">
+                    <div class="title">{{item.ExcelName}}</div>
+                    <div class="img" :style="`backgroundImage:url(${ !item.HaveOperaAuth?$icons.lock_big:item.ExcelImage })`"></div>
+                </div>
+            </draggable>
+            <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-if="list.length===0"/>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import * as sheetInterface from "@/api/modules/sheetApi.js";
+export default {
+    data() {
+        return {
+            keyword:'',
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+            loading:false
+        }
+    },
+    created(){
+        this.getSheetList()
+    },
+    methods: {
+        // 生产随机id
+        getCompId(type){
+            return type+new Date().getTime()
+        },
+
+        getCompData(item){
+            const LINK_URL = this.$setting.dynamicOutLinks.ChartViewUrl+'/sheetshow';
+            // console.log(LINK_URL);
+            const obj={
+                compId:4,
+                compType:'sheet',
+                content:`${LINK_URL}?code=${item.UniqueCode}&fromScene=1`
+            }
+            return JSON.stringify(obj)
+        },
+
+        handleSearch(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getSheetList()
+        },
+        getSheetList() {
+            this.loading=true
+            sheetInterface.sheetList({
+                Keyword: this.keyword,
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+            }).then((res) => {
+                this.loading=false
+                if (res.Ret !== 200) return;
+                const arr = res.Data.List || [];
+                this.list =
+                    this.page === 1
+                    ? arr
+                    : [...this.list, ...arr];
+                this.finished =  res.Data.Paging.IsEnd;
+            });
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getSheetList()
+        },
+
+        onMoveItemHandle(e) {
+            /* 无权限 */
+            if (!e.draggedContext.element.HaveOperaAuth) {
+                this.messageTip()
+                return false;
+            }
+
+            return true
+        },
+        
+        messageTip: _.debounce(function() {
+            this.$message.warning(this.$t('MsgPrompt.no_sheet_auth'))
+        },200)
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.eta-sheet-wrap{
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        .search-box{
+            width: 330px;
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            flex: 1;
+            overflow-y: auto;
+
+        }
+        .sheet-list-box{
+            display: flex;
+            flex-wrap: wrap;
+            gap: 20px;
+            .sheet-item{
+                cursor: move;
+                padding: 0 10px 10px 10px;
+                width: 250px;
+                border-radius: 4px;
+                border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+                background: var(--gary-gy-white, #FFF);
+                .title{
+                    padding: 10px 0;
+                    text-align: center;
+                    border-bottom: 1px solid #C8CDD9;
+                    overflow: hidden;
+                    white-space: nowrap;
+                    text-overflow: ellipsis;
+                }
+                .img{
+                    width: 100%;
+                    height: 197px;
+                    background-size: contain;
+                    background-position: center;
+                    background-repeat: no-repeat;
+                }
+            }
+        }
+    }
+}
+</style>

+ 16 - 0
src/views/report_manage/reportV2/smartReport/components/ImgComp.vue

@@ -0,0 +1,16 @@
+<template>
+    <div 
+        class="report-comp-item img-comp" 
+        style="width:100%;height:100%;overflow-y: auto;"
+    >
+        <img style="width:100%;display:block" :src="compData.content" alt="">
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        compData:{}
+    }
+}
+</script>

+ 141 - 0
src/views/report_manage/reportV2/smartReport/components/ImgEdit.vue

@@ -0,0 +1,141 @@
+<template>
+    <div class="img-edit-wrap" @paste="handleListenPaste">
+        <div style="font-size:16px;margin-bottom:20px">{{$t('ReportManage.ReportList.img_uplaod_title')}}</div>
+        <div class="main-box">
+            <input type="file" size="small" name="file" @change="fileSelected" id="file" class="true-file" style="display:none;">
+            <div class="upload-box" @click="clickinput">
+                <img class="bg" :src="content" alt="" v-if="content">
+                <img src="~@/assets/img/smartReport/icon15.png" alt="">
+                <div>{{$t('ReportManage.ReportList.click_img_upload')}}</div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import { bannerupload } from 'api/api.js';
+export default {
+    name:'ImgEdit',
+    props:{
+        content:''
+    },
+    created() {
+        window.addEventListener('paste',this.handleListenPaste)
+    },
+     
+    destroyed(){
+        window.removeEventListener('paste',this.handleListenPaste)
+    },
+    methods: {
+        clickinput(){  //上传模拟点击
+			$(`#file`).click();
+		},
+        fileSelected(file){  //选择文件上传
+            let hostfile=document.getElementById('file').files[0]||file
+			const that = this;
+		    if( hostfile ){
+		        let size = Math.floor(hostfile.size / 1024 / 1024);
+		        if( size>200 ){
+		            that.$message.warning(this.$t('ReportManage.smart_msg.uploaded_limitation'));
+		            hostfile = {};
+		            return false
+		        }
+		        if( hostfile.name.toLowerCase().includes('.png') || hostfile.name.toLowerCase().includes('.jpg') || hostfile.name.toLowerCase().includes('.jpeg') ){
+		        	let form = new FormData();
+		        	form.append('file',hostfile);  //hostfile.name
+					bannerupload(form).then((res) => {
+						if( res.Ret === 200 ){
+							that.$emit('imgChange', res.Data.ResourceUrl)
+                            that.content=res.Data.ResourceUrl
+						}
+						$("#file").val('');
+						hostfile = {};
+					});
+				}else{
+					that.$message.warning(this.$t('ReportManage.smart_msg.upload_format'));
+		        }
+		    } 
+		},
+
+        handleListenPaste:_.throttle(async function(e){
+            if(!e.clipboardData) return
+            const clipboardDataItems = e.clipboardData.items
+            const clipboardDataFirstItem = clipboardDataItems[0]
+            if(clipboardDataFirstItem){
+                for (const item of clipboardDataItems) {
+                    if (item.kind === 'file' && item.type.indexOf('image') !== -1) {
+                        const imageFile = item.getAsFile()
+                        console.log('读取成功1',imageFile);
+                        if (imageFile) this.fileSelected(imageFile)
+                        return
+                    }
+                }
+                return
+            }
+            //clipboardData中没有图片,从navigator.clipboard.read里获取图片
+            let clipboardItems = null
+            try{
+                clipboardItems = await navigator.clipboard.read()
+            }catch(error){
+                this.$message.warning("剪贴板读取不到文件!")
+                return
+            }
+            const blob = await this.checkClipboardItems(clipboardItems)
+            console.log('读取成功2',blob);
+            if(blob) this.fileSelected(blob)
+
+        },1000),
+
+        checkClipboardItems(clipboard){
+            for(const Item of clipboard){
+                for(const type of Item.types){
+                    if(type.includes('image')){
+                        return Item.getType(type)
+                    }
+                }
+            }
+            return null
+        }
+    },
+
+
+
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+
+.main-box{
+    width: 100%;
+    height: calc(100vh - 150px);
+    border-radius: 4px;
+    border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+    background: #FFF;
+    padding: 30px;
+    .upload-box{
+        cursor: pointer;
+        width: 120px;
+        height: 120px;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+        justify-content: center;
+        border: 1px dashed var(--gary-gy-5-line, #C8CDD9);
+        background: var(--gary-gy-1-bottom-bk, #F8F8F8);
+        color: #999;
+        position: relative;
+        .bg{
+            width: 100%;
+            height: 100%;
+            position: absolute;
+            left: 0;
+            top: 0;
+            z-index: 10;
+            background: #FFF;
+        }
+    }
+}
+</style>

+ 209 - 0
src/views/report_manage/reportV2/smartReport/components/ImgSource.vue

@@ -0,0 +1,209 @@
+<template>
+    <div class="statistic-analysis-wrap">
+        <div class="top-box">
+            <div class="left-card">
+                <span>{{$t('ReportManage.ReportList.select_img_card')}}</span>
+            </div>
+            <div class="right">
+                <el-input
+                    class="search-box"
+					:placeholder="$t('ReportManage.ReportList.img_name_ipt')"
+					v-model="keyword"
+                    @input="handleSearch"
+                    style="width:240px"
+                    size="medium"
+				/>
+                <el-select :placeholder="$t('ReportManage.ReportList.select_img_type')" v-model="type" style="width:240px" @change="handleSearch" size="medium">
+                    <el-option :label="$t('ReportManage.ReportList.page_header_op')" :value="1"></el-option>
+                    <el-option :label="$t('ReportManage.ReportList.page_trailer_op')" :value="2"></el-option>
+                </el-select>
+            </div>
+        </div>
+        <div class="main-box">
+            <!-- <div class="type-select-box">
+                <span style="margin-right:20px">版面设置</span>
+                <el-radio-group v-model="setType">
+                    <el-radio :label="1">版头</el-radio>
+                    <el-radio :label="2">版尾</el-radio>
+                </el-radio-group>
+            </div> -->
+            <div style="flex:1;overflow-y: auto;padding:20px 0">
+            <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-if="list.length===0&&finished"/>
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="false">
+                <div 
+                    :class="['item',selectItem&&selectItem.ResourceId===item.ResourceId?'active':'']" 
+                    v-for="item in list" 
+                    :key="item.ResourceId" 
+                    @click="handleSelectItem(item)"
+                >
+                    <div class="img" :style="'backgroundImage:url('+item.ImgUrl+')'"></div>
+                    <div class="title">{{item.ImgName}}</div>
+                </div>
+            </div>
+            </div>
+            <div class="btns-box">
+                <el-button type="primary" plain @click="handleClose">{{$t('Dialog.cancel_btn')}}</el-button>
+                <el-button type="primary" @click="handleSave">{{$t('Dialog.confirm_save_btn')}}</el-button>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import {apiSmartReport}  from '@/api/modules/smartReport'
+export default {
+    data() {
+        return {
+            keyword:'',
+            type:1,
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+
+            setType:'',
+            selectItem:null
+        }
+    },
+    created(){
+        this.getImgList()
+    },
+    methods: {
+        //资源库列表
+        async getImgList(){
+            const res=await apiSmartReport.imgReourceList({
+                CurrentIndex:this.page,
+                PageSize:this.pageSize,
+                Type:this.type,
+                Keyword:this.keyword
+            })
+            if(res.Ret===200){
+                const arr = res.Data.List || [];
+                this.list =
+                    this.page === 1
+                    ? arr
+                    : [...this.list, ...arr];
+                this.finished =  res.Data.Paging.IsEnd;
+            }
+        },
+
+        handleLoadMore(){
+            if(this.finished) return
+            this.page++
+            this.getImgList()
+        },
+
+        handleSearch(){
+            this.page=1
+            this.finished=false
+            this.selectItem=null
+            this.getImgList()
+        },
+
+        handleSelectItem(e){
+            this.selectItem=e
+        },
+
+        handleClose(){
+            this.$emit('close')
+        },
+
+        handleSave(){
+            // if(!this.setType){
+            //     this.$message.warning('请选择设置的版面类型')
+            //     return
+            // }
+            if(!this.selectItem){
+                this.$message.warning(this.type==1?'请选择版头':'请选择版尾')
+                return
+            }
+            this.$emit('change',{
+                type:this.type,
+                data:this.selectItem
+            })
+        }
+        
+
+    },
+
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .right{
+            .search-box{
+                width: 330px;
+            }
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            display: flex;
+            flex-wrap: wrap;
+            gap: 20px;
+            .item{
+                width: 240px;
+                cursor: pointer;
+                .img{
+                    background: var(--gary-gy-3-disabled, #EBEFF6);
+                    width: 240px;
+                    height: 240px;
+                    background-size: contain;
+                    background-position: center;
+                    background-repeat: no-repeat;
+                }
+                .title{
+                    margin-top: 5px;
+                    display: -webkit-box;
+                    overflow: hidden;
+                    text-overflow: ellipsis;
+                    -webkit-line-clamp: 2;
+                    line-break: anywhere;
+                    -webkit-box-orient: vertical;
+                }
+            }
+            .active{
+                position: relative;
+                .img{
+                    border: 1px solid #0052D9;
+                }
+                &::before{
+                    content: '';
+                    display: block;
+                    width: 20px;
+                    height: 20px;
+                    position: absolute;
+                    left: 0;
+                    top: 0;
+                    background-image: url('~@/assets/img/smartReport/icon17.png');
+                    background-size: cover;
+                    background-repeat: no-repeat;
+                }
+            }
+        }
+        .btns-box{
+            padding-top: 20px;
+            text-align: center;
+            .el-button{
+                width: 200px;
+            }
+        }
+    }
+}
+</style>

+ 166 - 0
src/views/report_manage/reportV2/smartReport/components/ImportETAChart.vue

@@ -0,0 +1,166 @@
+<template>
+    <div class="import-eta-chart-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+            <el-checkbox
+                class="onlyshowme-box"
+                v-model="isShowMe" 
+                @change="handleIsShowMeChange"
+            >{{$t('ReportManage.ReportList.just_mine_radio')}}</el-checkbox>
+            <draggable
+                :list="list"
+                :group="{ name: 'component', pull: 'clone', put: false }"
+                class="chart-list-box"
+                animation="300"
+                :sort="false"
+                tag="div"
+                :move="onMoveItemHandle"
+            >
+                <div class="chart-item" :comp-data="getCompData(item)" v-for="item in list" :key="item.UniqueCode">
+                    <div class="title">{{item.ChartName}}</div>
+                    <div class="img" :style="`backgroundImage:url(${ !item.HaveOperaAuth?$icons.lock_big:item.ChartImage })`"></div>
+                </div>
+            </draggable>
+            <tableNoData :text="$t('ReportManage.ReportList.no_chart_table_available')" size="mini" v-if="list.length===0"/>
+    </div>
+</template>
+
+<script>
+import { dataBaseInterface } from "@/api/api.js";
+export default {
+    data() {
+        return {
+            isShowMe:false,
+            page:1,
+            pageSize:20,
+            list:[],
+            finished:false,
+            keyword:'',
+            loading:false
+        }
+    },
+    computed: {
+        //语言版本
+        currentLang() {
+            return this.$store.state.lang
+        }
+    },
+    created() {
+        this.getETAChartList()
+    },
+    methods: {
+        // 生产随机id
+        getCompId(type){
+            return type+new Date().getTime()
+        },
+
+        getCompData(item){
+            const LINK_CHART_URL = this.$setting.dynamicOutLinks.ChartViewUrl+'/chartshow';
+            const obj={
+                compId:3,
+                compType:'chart',
+                content:`${LINK_CHART_URL}?code=${item.UniqueCode}&lang=${this.currentLang}`
+            }
+            return JSON.stringify(obj)
+        },
+
+        async getETAChartList(){
+            this.loading=true
+            const res=await dataBaseInterface.chartSearchByEs({
+                Keyword: this.keyword || "",
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+                IsShowMe: this.isShowMe,
+            })
+            this.loading=false
+            if(res.Ret===200){
+                const arr=res.Data.List || []
+                this.list=[...this.list,...arr]
+                this.finished=res.Data.Paging.IsEnd
+            }
+        },
+
+        handleIsShowMeChange(){
+            this.page=1
+            this.finished=false
+            this.list=[]
+            this.getETAChartList()
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getETAChartList()
+        },
+
+        handleSearch(key){
+            this.page=1
+            this.finished=false
+            this.list=[]
+            this.keyword=key
+            this.getETAChartList()
+        },
+
+        onMoveItemHandle(e) {
+            /* 无权限 */
+            if (!e.draggedContext.element.HaveOperaAuth) {
+                this.messageTip()
+                return false;
+            }
+
+            return true
+        },
+        
+        messageTip: _.debounce(function() {
+            this.$message.warning(this.$t('MsgPrompt.no_chart_auth'))
+        },200)
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.import-eta-chart-wrap{
+    height: 100%;
+    width: 100%;
+    position: relative;
+    overflow-y: auto;
+    overflow-x: hidden;
+    padding-top: 20px;
+    .onlyshowme-box{
+            display: block;
+            position: sticky;
+            top: -20px;
+            padding: 20px 0;
+            background-color: #FFF;
+        }
+        .chart-list-box{
+            display: flex;
+            flex-wrap: wrap;
+            gap: 20px;
+            .chart-item{
+                cursor: move;
+                padding: 0 10px;
+                width: 250px;
+                border-radius: 4px;
+                border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+                background: var(--gary-gy-white, #FFF);
+                .title{
+                    padding: 10px 0;
+                    text-align: center;
+                    border-bottom: 1px solid #C8CDD9;
+                    overflow: hidden;
+                    white-space: nowrap;
+                    text-overflow: ellipsis;
+                }
+                .img{
+                    width: 100%;
+                    height: 197px;
+                    background-size: cover;
+                    background-position: center;
+                    background-repeat: no-repeat;
+                }
+            }
+        }
+}
+</style>

+ 171 - 0
src/views/report_manage/reportV2/smartReport/components/ImportMyETAChart.vue

@@ -0,0 +1,171 @@
+<template>
+    <div class="import-mychart-wrap">
+        <div class="select-box">
+			<el-select 
+				style="width:300px" 
+				v-model="selectMyChartClassify" 
+				filterable 
+				:placeholder="$t('ReportManage.ReportList.chart_category_name')"
+				@change="handleChange"
+			>
+				<el-option
+					v-for="item in myChartClassifyList"
+					:key="item.MyChartClassifyId"
+					:label="item.MyChartClassifyName"
+					:value="item.MyChartClassifyId"
+				>
+				</el-option>
+			</el-select>
+			<el-button type="primary" @click="handleImport">{{$t('ReportManage.ReportList.click_import')}}</el-button>
+			<el-tooltip class="item" effect="dark" :content="$t('ReportManage.ReportList.import_all_chart_msg')" placement="top-start">
+				<i style="font-size:24px;color: #666;" class="el-icon-question"></i>
+			</el-tooltip>
+		</div>
+		<div class="list" v-infinite-scroll="load" v-if="list.length>0">
+            <div class="chart-item" v-for="item in list" :key="item.UniqueCode" @click="handleClickItem">
+                <div class="title">{{item.ChartName}}</div>
+                <div class="img" :style="`backgroundImage:url(${ !item.HaveOperaAuth?$icons.lock_big:item.ChartImage })`"></div>
+            </div>
+		</div>
+        <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-if="list.length===0"/>
+    </div>
+</template>
+
+<script>
+import { mychartInterface } from '@/api/api.js';
+export default {
+    data() {
+        return {
+            myChartClassifyList:[],
+            selectMyChartClassify:'',
+            pageSize:20,
+			CurrentIndex: 1,
+			list:[],
+            loading:false,
+            finished:false,
+
+        }
+    },
+    props:{
+        showEnMark:{
+            type:Boolean,
+            default:false
+        }
+    },
+    mounted(){
+        this.getMyChartClassify()
+    },  
+    methods: {
+        //获取我的图库中分类
+		getMyChartClassify(){
+			mychartInterface.classifyList().then(res=>{
+				if (res.Ret !== 200) return;
+				this.myChartClassifyList=res.Data?res.Data.List:[]
+			})
+		},
+        handleChange(){
+            this.CurrentIndex=1
+            this.list=[]
+            this.finished=false
+            this.loading=false
+            this.handleGetMyChartList()
+        },
+		async handleGetMyChartList(){
+            if(!this.selectMyChartClassify) return
+            this.loading=true
+            const res=await  mychartInterface.myList({
+				PageSize: this.pageSize,
+				CurrentIndex: this.CurrentIndex,
+				MyChartClassifyId: this.selectMyChartClassify || 0
+			})
+            this.loading=false
+            const arr=res.Data?res.Data.List.filter(_=>!_.Disabled):[]
+            this.list=[...this.list,...arr]
+            if(!res.Data){
+                this.finished=true
+            }
+            if(res.Data&&res.Data.Paging.IsEnd){
+                this.finished=true
+            }
+		},
+
+        load(){
+            if(this.finished) return
+            this.CurrentIndex++
+            this.handleGetMyChartList()
+        },
+
+        handleImport:_.throttle(function(){
+            if(!this.selectMyChartClassify){
+                this.$message.warning(this.$t('ReportManage.ReportList.please_select_category'))
+                return
+            }
+             let filterList = this.list.filter(_ =>_.HaveOperaAuth)
+            if(filterList.length==0){
+                this.$message.warning(this.$t('ReportManage.ReportList.no_chart_msg'))
+                return
+            }
+            this.$emit('handleImportMyChart',filterList)
+            setTimeout(() => {
+                this.CurrentIndex=1
+                this.list=[]
+                this.finished=false
+                this.loading=false
+                this.selectMyChartClassify=''
+            }, 300);
+        },1000),
+
+        handleClickItem(){
+            this.$message.warning(this.$t('ReportManage.ReportList.no_one_charts'))
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.import-mychart-wrap{
+    position: relative;
+    height: 100%;
+    padding-top: 20px;
+    .select-box{
+        position: absolute;
+        top: -75px;
+        right: 0;
+    }
+    .list{
+        max-height: calc(100vh - 220px);;
+        overflow-x: hidden;
+		overflow-y: auto;
+        display: flex;
+            flex-wrap: wrap;
+            gap: 20px;
+            .chart-item{
+                cursor: move;
+                padding: 0 10px;
+                width: 250px;
+                max-height: 260px;
+                border-radius: 4px;
+                border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+                background: var(--gary-gy-white, #FFF);
+                .title{
+                    padding: 10px 0;
+                    text-align: center;
+                    border-bottom: 1px solid #C8CDD9;
+                    overflow: hidden;
+                    white-space: nowrap;
+                    text-overflow: ellipsis;
+                }
+                .img{
+                    width: 100%;
+                    height: 197px;
+                    background-size: cover;
+                    background-position: center;
+                    background-repeat: no-repeat;
+                }
+            }
+    }
+}
+</style>

+ 172 - 0
src/views/report_manage/reportV2/smartReport/components/SemanticAnalysis.vue

@@ -0,0 +1,172 @@
+<template>
+    <div class="statistic-analysis-wrap">
+        <div class="top-box">
+            <div class="left-card">
+                <span>{{$t('ReportManage.ReportList.semantic_top_type')}}</span>
+            </div>
+            <div class="right">
+                <el-input
+                    class="search-box"
+					:placeholder="$t('ReportManage.ReportList.keyword_search')"
+					v-model="keyword"
+					size="medium"
+					prefix-icon="el-icon-search"
+                    @input="handleSearch"
+				/>
+            </div>
+        </div>
+        <div class="main-box">
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+                <draggable
+                    :list="list"
+                    :group="{ name: 'component', pull: 'clone', put: false }"
+                    class="chart-list-box"
+                    animation="300"
+                    :sort="false"
+                    tag="div"
+                >
+                    <div class="chart-item" :comp-data="getCompData(item)" v-for="item in list" :key="item.SaCompareId">
+                        <div class="title">{{item.Title}}</div>
+                        <div class="img" :style="'backgroundImage:url('+item.ResultImg+')'"></div>
+                    </div>
+                </draggable>
+                <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-if="list.length===0&&finished"/>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import {semanticInterface} from '@/api/modules/semanticsApi.js';
+export default {
+    data() {
+        return {
+            
+            keyword:'',
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+            loading:false
+        }
+    },
+    created(){
+        this.getSemanticList()
+    },
+    methods: {
+        // 生产随机id
+        getCompId(type){
+            return type+new Date().getTime()
+        },
+
+        getCompData(item){
+            const obj={
+                compId:2,
+                compType:'img',
+                content:item.ResultImg
+            }
+            return JSON.stringify(obj)
+        },
+
+        handleIsShowMeChange(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getSemanticList()
+        },
+
+        handleSearch(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getSemanticList()
+        },
+
+        /* 搜索图表分页 */
+        async getSemanticList(word) {
+            let params = {
+                Keyword: this.keyword || "",
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+            };
+            this.loading=true
+            let res = await semanticInterface.compareSearch(params);
+            this.loading=false
+            if (res.Ret !== 200) return;
+            const arr = res.Data.List || [];
+            this.list =
+                this.page === 1
+                ? arr
+                : [...this.list, ...arr];
+            this.finished =  res.Data.Paging.IsEnd;
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getSemanticList()
+        }
+    },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .right{
+            .search-box{
+                width: 330px;
+            }
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            flex: 1;
+            overflow-y: auto;
+
+        }
+    }
+}
+.chart-list-box{
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20px;
+    .chart-item{
+                cursor: move;
+                padding: 0 10px;
+                width: 250px;
+                border-radius: 4px;
+                border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+                background: var(--gary-gy-white, #FFF);
+                .title{
+                    padding: 10px 0;
+                    text-align: center;
+                    border-bottom: 1px solid #C8CDD9;
+                    overflow: hidden;
+                    white-space: nowrap;
+                    text-overflow: ellipsis;
+                }
+                .img{
+                    width: 100%;
+                    height: 197px;
+                    background-size: contain;
+                    background-position: center;
+                    background-repeat: no-repeat;
+                }
+            }
+}
+</style>

+ 41 - 0
src/views/report_manage/reportV2/smartReport/components/SheetComp.vue

@@ -0,0 +1,41 @@
+<template>
+    <div 
+        class="report-comp-item sheet-comp"
+        style="width:100%;overflow: hidden;"
+    >
+        <iframe :class="id" :src="compData.content" width="100%" style="border-width:0px;"></iframe>
+    </div>
+</template>
+
+<script>
+function GetQueryString(url) {
+    let urlStr=url.split('?')[1]
+    let obj={}
+    let paramsArr=urlStr.split('&')
+    for (let index = 0; index < paramsArr.length; index++) {
+        let arr=paramsArr[index].split('=')
+        obj[arr[0]]=arr[1]
+    }
+    return obj
+}
+export default {
+    props:{
+        compData:{}
+    },
+    computed: {
+        id(){
+            if(this.compData.content){
+                // console.log(this.compData.content);
+                let params = GetQueryString(this.compData.content)
+                // console.log(params);
+                return `iframe${params.code}`
+            }
+            return ''
+        }
+    },
+}
+</script>
+
+<style>
+
+</style>

+ 258 - 0
src/views/report_manage/reportV2/smartReport/components/StatisticAnalysis.vue

@@ -0,0 +1,258 @@
+<template>
+    <div class="statistic-analysis-wrap">
+        <div class="top-box">
+            <div class="left-card">
+                <span
+                    :class="['item',activeType===item.key?'active':'']" 
+                    @click="activeTypeChange(item.key)"
+                    v-for="item in typeOpts"
+                    :key="item.key"
+                >{{item.name}}</span>
+            </div>
+            <div class="right">
+                <el-input
+                    class="search-box"
+					:placeholder="$t('ReportManage.ReportList.chart_name')"
+					v-model="keyword"
+					size="medium"
+					prefix-icon="el-icon-search"
+                    @input="handleSearch"
+				/>
+            </div>
+        </div>
+        <div class="main-box">
+            <el-checkbox
+                class="onlyshowme-box"
+                v-model="isShowMe" 
+                @change="handleIsShowMeChange"
+            >{{$t('ReportManage.ReportList.just_mine_radio')}}</el-checkbox>
+            <div class="list-wrap" v-infinite-scroll="handleLoadMore" :infinite-scroll-immediate="true">
+                <draggable
+                    :list="list"
+                    :group="{ name: 'component', pull: 'clone', put: false }"
+                    class="chart-list-box"
+                    animation="300"
+                    :sort="false"
+                    tag="div"
+                >
+                    <div class="chart-item" :comp-data="getCompData(item)" v-for="item in list" :key="item.UniqueCode">
+                        <div class="title">{{item.ChartName}}</div>
+                        <div class="img" :style="'backgroundImage:url('+item.ChartImage+')'"></div>
+                    </div>
+                </draggable>
+                <tableNoData :text="$t('ReportManage.ReportList.no_chart_table_available')" size="mini" v-if="list.length===0&&finished"/>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+import chartRelevanceApi from "@/api/modules/chartRelevanceApi";
+import {
+  fittingEquationInterface,
+  statisticFeatureInterface,
+  crossVarietyInterface
+} from "@/api/modules/chartRelevanceApi";
+export default {
+    data() {
+        return {
+
+            keyword:'',
+            isShowMe:false,
+            activeType:'相关性',
+
+            list:[],
+            page:1,
+            pageSize:20,
+            finished:false,
+            loading:false
+        }
+    },
+    created(){
+        this.getChartList()
+    },
+    methods: {
+        // 生产随机id
+        getCompId(type){
+            return type+new Date().getTime()
+        },
+
+        getCompData(item){
+            const LINK_CHART_URL = this.$setting.dynamicOutLinks.ChartViewUrl+'/chartshow';
+            const obj={
+                compId:3,
+                compType:'chart',
+                content:`${LINK_CHART_URL}?code=${item.UniqueCode}`
+            }
+            return JSON.stringify(obj)
+        },
+
+        activeTypeChange(e){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.keyword=''
+            this.isShowMe=false
+            this.activeType=e
+            this.getChartList()
+        },
+
+        handleIsShowMeChange(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getChartList()
+        },
+
+        handleSearch(){
+            this.list=[]
+            this.page=1
+            this.finished=false
+            this.getChartList()
+        },
+
+        /* 搜索图表分页 */
+        async getChartList(word) {
+            let params = {
+                Keyword: this.keyword || "",
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+                IsShowMe: this.isShowMe,
+            };
+            this.loading=true
+            let res = null;
+            if (this.activeType === '相关性') {
+                res = await chartRelevanceApi.searchChart(params);
+            } else if (this.activeType === '拟合方程曲线') {
+                res = await fittingEquationInterface.searchChart(params);
+            } else if (this.activeType === '统计特征') {
+                res = await statisticFeatureInterface.searchChart(params);
+            } else if (this.activeType === '跨品种分析') {
+                res = await crossVarietyInterface.searchChart(params);
+            }
+            this.loading=false
+
+            if (res.Ret !== 200) return;
+            const arr = res.Data.List || [];
+            this.list =
+                this.page === 1
+                ? arr
+                : [...this.list, ...arr];
+            this.finished =  res.Data.Paging.IsEnd;
+        },
+
+        handleLoadMore(){
+            if(this.finished||this.loading) return
+            this.page++
+            this.getChartList()
+        }
+    },
+    computed:{
+      typeOpts(){
+        return [
+                {
+                    name:this.$t('ReportManage.ReportList.correlation_analysis'),
+                    key:'相关性'
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.curve_fitting_radio'),
+                    key:'拟合方程曲线'
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.statistical_feature_radio'),
+                    key:'统计特征'
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.intercommodity_analysis_radio'),
+                    key:'跨品种分析'
+                }
+            ]
+      }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+    box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+    .top-box{
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        .left-card{
+            border-radius: 4px;
+            border: 1px solid var(--unnamed, #DCDFE6);
+            background: var(--gary-gy-3-disabled, #EBEFF6);
+            display: flex;
+            align-items: center;
+            gap: 0 3px;
+            padding: 6px;
+            .item{
+                cursor: pointer;
+                display: block;
+                width: 110px;
+                height: 30px;
+                line-height: 30px;
+                text-align: center;
+                border-radius: 4px;
+                font-size: 18px;
+                color: #666;
+                &.active{
+                    background: #FFF;
+                    color: #002D78;
+                }
+            }
+        }
+        .right{
+            .search-box{
+                width: 330px;
+            }
+        }
+    }
+    .main-box{
+        margin-top: 30px;
+        height: calc(100vh - 180px);
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px;
+        display: flex;
+        flex-direction: column;
+        .list-wrap{
+            flex: 1;
+            overflow-y: auto;
+
+        }
+    }
+}
+.chart-list-box{
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20px;
+    .chart-item{
+                cursor: move;
+                padding: 0 10px;
+                width: 250px;
+                border-radius: 4px;
+                border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+                background: var(--gary-gy-white, #FFF);
+                .title{
+                    padding: 10px 0;
+                    text-align: center;
+                    border-bottom: 1px solid #C8CDD9;
+                    overflow: hidden;
+                    white-space: nowrap;
+                    text-overflow: ellipsis;
+                }
+                .img{
+                    width: 100%;
+                    height: 197px;
+                    background-size: cover;
+                    background-position: center;
+                    background-repeat: no-repeat;
+                }
+            }
+}
+</style>

+ 20 - 0
src/views/report_manage/reportV2/smartReport/components/TextComp.vue

@@ -0,0 +1,20 @@
+<template>
+    <div 
+        class="report-comp-item text-comp" 
+        style="width:100%;height: 100%;overflow-y: auto;"
+    >
+        <div class="rich-text-box" v-html="compData.content"></div>
+    </div>
+</template>
+
+<script>
+export default {
+    props:{
+        compData:{}
+    }
+}
+</script>
+
+<style>
+
+</style>

+ 168 - 0
src/views/report_manage/reportV2/smartReport/components/TextEdit.vue

@@ -0,0 +1,168 @@
+<template>
+    <div class="text-edit-wrap">
+        <div style="font-size:16px;margin-bottom:20px">{{$t('ReportManage.ReportList.text_editing')}}</div>
+        <froala
+			id="froala-editor"
+			ref="froalaEditor"
+			:tag="'textarea'"
+			:config="froalaConfig"
+			v-model="html"
+		/>
+    </div>
+</template>
+
+<script>
+import VueFroala from 'vue-froala-wysiwyg';
+export default {
+    name:'TextEdit',
+    props:{
+        content:''
+    },
+    data() {
+        const that = this;
+        return {
+            html:this.content||'',
+            editor: null,
+            lastEditRange: null,
+            froalaConfig:{
+                imageUploadURL: process.env.VUE_APP_API_ROOT + "/report/uploadImg", //上传url
+                videoUploadURL: process.env.VUE_APP_API_ROOT + "/report/uploadImg", //上传url
+                fileUploadURL: process.env.VUE_APP_API_ROOT + "/report/uploadImg", //上传url 更多上传介绍 请访问https://www.froala.com/wysiwyg-editor/docs/options
+                toolbarButtons: [
+                    "textColor",
+                    "bold",
+                    "italic",
+                    "underline",
+                    "strikeThrough",
+                    "subscript",
+                    "superscript",
+                    "fontFamily",
+                    "fontSize",
+                    "color",
+                    "inlineClass",
+                    "inlineStyle",
+                    "paragraphStyle",
+                    "lineHeight",
+                    "paragraphFormat",
+                    "align",
+                    "formatOL",
+                    "formatUL",
+                    "outdent",
+                    "indent",
+                    "quote",
+                    "specialCharacters",
+                    "insertHR",
+                    "selectAll",
+                    "clearFormatting",
+                    /* "html", */
+                    "undo",
+                    "redo",
+                ],
+                height: 800,
+                fontSize: ["12", "13","14","15", "16", "18", "20", "24", "28", "32", "36", "40"],
+                fontSizeDefaultSelection: "16",
+                theme: "dark", //主题
+                placeholderText: localStorage.getItem('i18n') == 'en' ? 'Please input content' : "请输入内容",
+                language: localStorage.getItem('i18n') == 'en' ? 'en' : "zh_cn", //国际化
+                imageDefaultWidth: false,
+                quickInsertEnabled: false,
+                toolbarVisibleWithoutSelection: true, //是否开启 不选中模式
+                toolbarSticky: false, //操作栏是否自动吸顶
+                saveInterval: 0,
+                fontFamily:{
+                    'Arial,Helvetica,sans-serif': 'Arial',
+                    'Georgia,serif': 'Georgia',
+                    'Impact,Charcoal,sans-serif': 'Impact',
+                    'Tahoma,Geneva,sans-serif': 'Tahoma',
+                    'Times New Roman,Times,serif': 'Times New Roman',
+                    'Verdana,Geneva,sans-serif': 'Verdana',
+                    '思源宋体':'思源宋体',
+                    '思源黑体':'思源黑体',
+                },
+                events: {
+                    //this.editor 定义在vue data 中
+                    initialized: function () {
+                        // this.editor = editor;
+                        that.editor = this;
+                        // that.editor.html.set(that.value);
+                        // that.setHtml()
+                    },
+                    keyup: function (e, editor) {
+                        //添加事件,在每次按键按下时,都记录一下最后停留位置
+                        that.$nextTick(function () {
+                            getSelection().rangeCount &&
+                                (that.lastEditRange = getSelection().getRangeAt(0));
+                        });
+                    },
+                    click: function (e, editor) {
+                        //添加事件,在每次鼠标点击时,都记录一下最后停留位置
+                        that.$nextTick(function () {
+                            getSelection().rangeCount &&
+                            (that.lastEditRange = getSelection().getRangeAt(0));
+                        });
+                    },
+                    //内容改变事件
+                    contentChanged: function () {
+                        that.lastEditRange = getSelection().rangeCount
+                            ? getSelection().getRangeAt(0)
+                            : 0;
+                        
+                        // that.$emit('textChange', that.html)
+                        that.sendHtml()
+                    },
+                    "paste.before":function(e,editor){
+                        let content = e.clipboardData.getData('text/html');
+                        // console.log(content)
+                        var tempDiv = document.createElement('div');
+                        tempDiv.innerHTML = content;
+                        var iframes = tempDiv.querySelectorAll('iframe');
+                        const srcArr = Array.from(iframes).map(i=>i.src)
+                        //console.log(srcArr);
+                        if(srcArr.filter(i=>!i.includes(that.$setting.dynamicOutLinks.ChartViewUrl)).length){
+                            that.$message.warning("粘贴内容含有外链,请核对内容或粘贴纯文本")
+                            return false
+                        }
+                    },
+                },
+            }
+        }
+    },
+    methods: {
+        sendHtml(){
+            const str=this.html.replace(/<p data-f-id=\"pbf\".*?<\/p>/g, "")
+            //如果富文本中有未上传完成的图片,去除这个dom
+			$('.fr-element').find('img.fr-uploading').length&&$('.fr-element').find('img.fr-uploading').remove()
+            this.$emit('textChange', str)
+        }
+    },
+    components:{}
+}
+</script>
+
+<style lang="scss">
+.text-edit-wrap{
+    .fr-box.fr-basic{
+        flex: 1;
+        overflow: hidden;
+        display: flex;
+        flex-direction: column;
+        .fr-wrapper{
+            flex: 1;
+            overflow: auto;
+        }
+    }
+}
+</style>
+<style lang="scss" scoped>
+.text-edit-wrap{
+    width:100%;
+    height: 100%;
+    overflow: hidden;
+    display: flex;
+    flex-direction: column;
+    #froala-editor{
+        flex:1;
+        overflow: auto;
+    }
+}
+</style>

+ 1571 - 0
src/views/report_manage/reportV2/smartReport/editReport.vue

@@ -0,0 +1,1571 @@
+<template>
+    <div class="edit-smart-report-page">
+        <!-- 顶部操作栏 -->
+        <editHeader
+            :reportInfo="{Title: reportInfo.title}"
+            @handleClearContent="handleClearContent"
+            @openBaseInfo="showReportBaseInfo=true"
+            @handleRefreshAllChart="handleRefreshAllChart"
+            @handlePreviewReport="handlePreviewReport"
+            @handleSaveContent="handleSaveContent"
+            @handlePublishOpt="handlePublishOpt"
+        />
+        
+        <div class="main-wrap">
+            <div class="report-action-wrap">
+                <ul class="top-type-list">
+                    <li class="item" v-for="item in topTypeList" :key="item.name" @click="handleShowRight(item)">
+                        <img class="icon" :src="item.icon" alt="">
+                        <span>{{item.name}}</span>
+                    </li>
+                </ul>
+                <!-- 公共组件 -->
+                <draggable
+                    :list="compList"
+                    :group="{ name: 'component', pull: 'clone', put: false }"
+                    class="report-comp-wrap"
+                    animation="300"
+                    :sort="false"
+                    tag="ul"
+                    filter='.unDrag'
+                >
+                    <li class="comp-item" :comp-data="JSON.stringify(comp)" v-for="comp in compList" :key="comp.id">
+                        <img :src="comp.icon">
+                    </li>
+                    <li class="comp-item unDrag" style="cursor: pointer;">
+                        <el-color-picker v-model="bgColor" @change="handleBgColorChange"></el-color-picker>
+                    </li>
+                </draggable>
+
+                <div class="report-content-box" id="report-content-box" :style="{backgroundColor:bgColor}">
+                    <div class="html-head-img-box">
+                        <div class="opt-btn-box" style="display: none;">
+                            <div class="del-btn" @click.stop="deleteLayoutPic(1)"></div>
+                        </div>
+                        <img :src="headImg" alt="" style="display:block;width:100%">
+                        <div class="head-layout-item" v-for="item in headImgStyle" :key="item.value"
+                        :style="{fontFamily:item.family,fontSize:(item.size*2)+'px',fontWeight:item.weight,textAlign:item.align,color:item.color,
+                            width:item.width,height:item.height,left:item.left,top:item.top
+                        }">
+                            {{ layoutBaseInfo[item.value] }}
+                        </div>
+                    </div>
+                    <draggable
+                        :list="conList"
+                        :group="{ name: 'component', pull: true, put: true }"
+                        class="report-html-wrap"
+                        id="report-html-content"
+                        animation="300"
+                        tag="div"
+                        handle=".drag-btn_p"
+                        @add="handleParentAdd"
+                        @remove="handleParentRemove"
+                        :move="handleParentMove"
+                    >
+                        <div 
+                            :class="[
+                                'report-drag-item-wrap',
+                                activeId===item.id?'blue-bg':'',
+                                item.child&&!item.child.length?'report-drag-item-out':''
+                            ]"
+                            v-for="item,index in conList" 
+                            :key="item.id"
+                            :comp-type="item.compType"
+                            @click="handleChoose(item,index)"
+                            :style="item.style"
+                        >
+                            <!-- 缩放的盒子 -->
+                            <div class="resize-drag-box" @mousedown.stop="handleResizeP($event,index)"></div>
+                            <div class="opt-btn-box" style="display: none;">
+                                <div class="drag-btn drag-btn_p"></div>
+                                <div class="del-btn" @click.stop="handleDelItem(index,-1)"></div>
+                            </div>
+                            <div 
+                                v-if="item.child&&!item.child.length"
+                                class="report-drag-item-wrap_content"
+                                style="width:100%;height:100%"
+                                :data-id="item.id"
+                            >
+                                <component :is="getComponentName(item)" :compData="item"/>
+                            </div>
+                            <draggable
+                                :list="item.child"
+                                :group="{ name: 'component', pull: true, put: item.child&&item.child.length<3?true:false }"
+                                animation="300"
+                                tag="div"
+                                class="report-drag-item-wrap_child-wrap"
+                                @add="handleChildAdd($event,item,index)"
+                                @remove="handleChildRemove($event,item.child)"
+                                handle=".drag-btn_c"
+                                style="display: flex;gap: 3px;align-items: flex-start;"
+                            >
+                                <div 
+                                    :class="['report-drag-item-wrap_child_content',activeId===child.id?'blue-bg':'']" 
+                                    v-for="child,cindex in item.child" 
+                                    :key="child.id"
+                                    :comp-type="child.compType"
+                                    :data-id="child.id"
+                                    @click.stop="handleChoose(child,index,cindex)"
+                                    style="flex:1"
+                                    :style="child.style"
+                                >
+                                    <div class="opt-btn-box2" style="display: none;">
+                                        <div class="drag-btn drag-btn_c"></div>
+                                        <div class="del-btn" @click.stop="handleDelItem(index,cindex)"></div>
+                                    </div>
+                                    <!-- 拖动按钮 -->
+                                    <div class="resize-drag-box_lb" @mousedown.stop="handleResizeC($event,index,cindex,'lb')"></div>
+                                    <div class="resize-drag-box_rb" @mousedown.stop="handleResizeC($event,index,cindex,'rb')"></div>
+                                    <component :is="getComponentName(child)" :compData="child"/>
+                                    <!--  -->
+                                    <div class="mark-box" v-if="isDragResize" style="position: absolute;left:0;right:0;top:0;bottom: 0;z-index: 10;"></div>
+                                </div>
+                            </draggable>
+                        </div>
+                    </draggable>
+
+                    <div class="html-end-img-box">
+                        <div class="opt-btn-box" style="display: none;">
+                            <div class="del-btn" @click.stop="endImg=''"></div>
+                        </div>
+                        <img :src="endImg" alt="" style="display:block;width:100%">
+                        <div class="head-layout-item" v-for="item in endImgStyle" :key="item.value"
+                        :style="{fontFamily:item.family,fontSize:(item.size*2)+'px',fontWeight:item.weight,textAlign:item.align,color:item.color,
+                            width:item.width,height:item.height,left:item.left,top:item.top
+                        }">
+                            {{ layoutBaseInfo[item.value] }}
+                        </div>
+                    </div>
+                </div>
+            </div>
+
+            <div class="right-action-wrap" v-show="showRight">
+                <div class="close-icon" @click="handleCloseRight">
+                    <img src="~@/assets/img/smartReport/icon14.png" alt="">
+                </div>
+                <div style="overflow-x:auto;height:calc(100% + 12px);">
+                <div style="min-width:800px;height: 100%;">
+                <TextEdit 
+                    v-if="rightType==='text'"
+                    :key="activeId"
+                    :content="activeContent" 
+                    @textChange="handleTextChange" 
+                />
+                <ImgEdit 
+                    v-if="rightType==='img'"
+                    :key="activeId"
+                    :content="activeContent" 
+                    @imgChange="handleTextChange" 
+                />
+                <!-- 图库插入 -->
+                <ETAChart 
+                    v-if="rightType==='etaChart'"
+                    @handleImportMyChart="handleImportMyChart"
+                />
+                <!-- ETA表格 -->
+                <ETASheet v-if="rightType==='etaSheet'"/>
+                <!-- 统计分析 -->
+                <StatisticAnalysis v-if="rightType==='statisticAnalysis'"/>
+                <!-- 商品价格曲线 -->
+                <ETAPriceChart v-if="rightType==='etaPriceChart'"/>
+                <!-- 沙盘图 -->
+                <ETASandBox v-if="rightType==='etaSandBox'"/>
+                <!-- 语义分析 -->
+                <SemanticAnalysis v-if="rightType==='semanticAnalysis'"/>
+                <!-- 版图资源库 -->
+                <ImgSource v-if="rightType==='imgSource'" @change="handleInsertImgSource" @close="handleCloseRight"/>
+                </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 报告基础信息 -->
+        <BaseInfo  v-model="showReportBaseInfo" :id="$route.query.id" @save="handleReportEdit" />
+
+        <!-- 定时发布弹窗 -->
+		<el-dialog 
+			v-dialogDrag 
+			:append-to-body="true" 
+			:visible.sync="showDSFB" 
+			width="500px" 
+			:title="$t('ReportManage.ReportList.scheduled_publish_btn')"
+		>
+			<div>
+				<div>
+					<span>{{$t('ReportManage.ReportList.publish_time')}}</span>
+					<el-date-picker
+						v-model="taskTime"
+						type="datetime"
+						:placeholder="$t('ReportManage.ReportList.select_date_and_time')"
+						value-format="yyyy-MM-dd HH:mm"
+						:picker-options="timePickerOpt"
+					/>
+				</div>
+				<p style="margin:15px 0">{{$t('ReportManage.ReportList.the_report_will_be_posted_on_time')}}</p>
+				<div style="text-align:right;margin:20px 0">
+					<el-button type="primary" plain @click="showDSFB=false">{{$t('Dialog.cancel_btn')}}</el-button>
+					<el-button type="primary" @click="handleSetReportPrepublish">{{$t('Dialog.confirm_btn')}}</el-button>
+				</div>
+			</div>
+		</el-dialog>
+
+    </div>
+</template>
+
+<script>
+import draggable from 'vuedraggable'
+import TextComp from './components/TextComp.vue'
+import ChartComp from './components/ChartComp.vue'
+import ImgComp from './components/ImgComp.vue'
+import SheetComp from './components/SheetComp.vue'
+import _ from 'lodash'
+import TextEdit from './components/TextEdit.vue'
+import ImgEdit from './components/ImgEdit.vue'
+import ETAChart from './components/ETAChart.vue'
+import ETASheet from './components/ETASheet.vue'
+import { getPublicSettingsApi } from '@/api/modules/oldApi';
+import { dataBaseInterface } from "@/api/api.js";
+import {apiSmartReport}  from '@/api/modules/smartReport'
+import {approveInterence} from '@/api/modules/approve.js';
+import * as sheetInterface from '@/api/modules/sheetApi.js';
+import BaseInfo from './components/BaseInfo.vue'
+import StatisticAnalysis from './components/StatisticAnalysis.vue'
+import ETAPriceChart from './components/ETAPriceChart.vue'
+import ETASandBox from './components/ETASandBox.vue'
+import SemanticAnalysis from './components/SemanticAnalysis.vue'
+import { getUrlParams } from '@/utils/common'
+import reportApproveConfig from "@/mixins/reportApproveConfig.js"
+import ImgSource from './components/ImgSource.vue'
+import editHeader from '../components/reportEditHeader.vue';
+export default {
+    mixins:[reportApproveConfig],
+    name:"smartReportEdit",
+    components: {
+        draggable,
+        BaseInfo,
+        TextComp,
+        ChartComp,
+        ImgComp,
+        SheetComp,
+        TextEdit,
+        ImgEdit,
+        ETAChart,
+        ETASheet,
+        StatisticAnalysis,
+        ETAPriceChart,
+        ETASandBox,
+        SemanticAnalysis,
+        ImgSource,
+        editHeader
+    },
+    watch:{
+        'taskTime'(){
+            this.taskTime=this.$moment(this.taskTime).format('YYYY-MM-DD HH:mm')+':00'
+			const date = this.$moment(this.taskTime).startOf('day').format('x');
+	        const nowDate = this.$moment().startOf('day').format('x');
+	        // 如果选择的是今天 则需要禁用已经过去的时间节点
+	        if (date <= nowDate) {
+	            // 默认选择的最新时间 是当前时间的两分钟后 (留出2分钟的富裕时间)
+	            this.timePickerOpt.selectableRange = (
+	                `${this.$moment().add(2,'m').format('HH:mm:ss')} - 23:59:59`
+	            );
+	        }else {
+				// 如果是以后的日期,则不需要禁用时间节点
+	            this.timePickerOpt.selectableRange = '00:00:00 - 23:59:59';
+	        }
+		},
+        conList:{
+            handler(n,o){
+                console.log('内容改变');
+                this.contentChange=true
+            },
+            deep:true
+        }
+    },
+    data() {
+        return {
+            reportInfo:null,
+            showReportBaseInfo:false,
+
+            compList:[
+                {   
+                    compId:1,
+                    compType:'text',
+                    icon:require('@/assets/img/smartReport/icon10.png')
+                },
+                {
+                    compId:2,
+                    compType:'img',
+                    icon:require('@/assets/img/smartReport/icon11.png')
+                },
+                // {
+                //     compId:3,
+                //     compType:'chart',
+                // },
+                // {
+                //     compId:4,
+                //     compType:'sheet',
+                // }
+                
+            ],
+            conList:[],
+            activeId:'',
+            activeContent:'',
+            activePindex:'',
+            activeCindex:'',
+            showRight:false,
+            rightType:'',
+
+            timer:null,//自动保存定时器
+
+            showDSFB:false,//显示定时发布弹窗
+			taskTime:'',//定时发布的时间
+			timePickerOpt:{
+				disabledDate(e){
+					return e.getTime()< new Date().getTime()-24 * 60 * 60 * 1000
+				},
+				selectableRange:'00:00:00 - 23:59:59',
+                format:'HH:mm'
+			},
+
+            contentChange:false,//内容是否发生变化
+
+            isDragResize:false,//是否正在拖动缩放
+
+            bgColor:'',//背景色
+            headImg:'',//版头图片
+            endImg:'',//版尾图片
+            headImgId:'',//版头Id
+            endImgId:'',//版尾Id
+            headImgStyle:'',//版头style
+            endImgStyle:'',//版尾style
+            layoutBaseInfo:{
+                研报标题:'',
+                研报作者:'',
+                创建时间:''
+            }
+        }
+    },
+    methods: {
+        // 大盒子的高度缩放
+        handleResizeP(e,index){
+            this.isDragResize=true
+            e.preventDefault()
+            const parentBox=e.target.parentNode.parentNode
+            const parentBoxWidth=parentBox.offsetWidth
+
+            const targetBox=e.target.parentNode
+            const targetBoxHeight=targetBox.offsetHeight
+            const targetBoxWidth=targetBox.offsetWidth
+
+            const startY=e.clientY
+            const startX=e.clientX
+            document.onmousemove=(mouseEl)=>{
+                mouseEl.preventDefault()
+                const h=mouseEl.clientY-startY+targetBoxHeight
+                // targetBox.style.minHeight=`${h<50?50:h}px`
+                targetBox.style.height=`${h}px`
+
+                // 去除minhight
+                targetBox.style.minHeight=`10px`
+
+                // 计算宽度
+                const w=mouseEl.clientX-startX+targetBoxWidth
+                const resW= (w/parentBoxWidth)*100//计算出的百分比结果值
+                targetBox.style.width=`${resW>=100?100:resW}%`
+            }
+            document.onmouseup=(el)=>{
+                console.log(targetBox.style.cssText);
+                this.$set(this.conList[index],'style',targetBox.style.cssText)
+                el.preventDefault()
+                document.onmousemove=null
+                setTimeout(() => {
+                    this.isDragResize=false
+                }, 50);
+                
+            }
+        },
+        // 内部元素的缩放
+        handleResizeC(e,index,cindex,type){
+            this.isDragResize=true
+            e.preventDefault()
+            const parentBox=e.target.parentNode.parentNode
+            const parentBoxWidth=parentBox.offsetWidth
+            console.log(e);
+            const targetBox=e.target.parentNode
+            const targetBoxHeight=targetBox.offsetHeight
+            const targetBoxWidth=targetBox.offsetWidth
+            const startY=e.clientY
+            const startX=e.clientX
+            const initW=targetBoxWidth //拖动前要拖动盒子所占的宽度
+
+            let computerW=0//存放其他兄弟节点要改变的宽度的值
+
+            document.onmousemove=(mouseEl)=>{
+                mouseEl.preventDefault()
+                const h=mouseEl.clientY-startY+targetBoxHeight
+                // 计算宽度
+                const w=type==='rb'?mouseEl.clientX-startX+targetBoxWidth:startX-mouseEl.clientX+targetBoxWidth
+                const resW= (w/parentBoxWidth)*100//计算出的百分比结果值
+                targetBox.style.width=resW+'%'
+                targetBox.style.flex='none'
+
+                // 处理兄弟盒子的宽度
+                const changeW=w-initW //宽度变化值
+                computerW=changeW
+                if(parentBox.childNodes.length===3){
+                    computerW=changeW/2
+                }
+                // console.log('改变的宽度',computerW);
+
+                // targetBox.style.height=`${h<50?50:h}px`
+                targetBox.style.height=`${h}px`
+            }   
+            document.onmouseup=(el)=>{
+                if(document.onmousemove){
+                    parentBox.childNodes.forEach(item=>{
+                        if(item!==targetBox){
+                            const temw=item.offsetWidth-computerW
+                            item.style.width=((temw/parentBoxWidth)*100)+'%'
+                        }
+                    })
+                    // 存储修改的值
+                    parentBox.childNodes.forEach((item,idx)=>{
+                        this.$set(this.conList[index].child[idx],'style',item.style.cssText)
+                    })
+                }
+                el.preventDefault()
+                document.onmousemove=null
+                setTimeout(() => {
+                    this.isDragResize=false
+                    document.onmouseup=null
+                }, 50);
+            }
+        },
+
+        // 跳转预览
+        handlePreviewReport(){
+            const htmlStr=document.getElementById('report-html-content').outerHTML;
+            sessionStorage.setItem('smartReportContent', htmlStr);
+            sessionStorage.setItem('smartReportContentBg', this.bgColor);
+			let { href } = this.$router.resolve({ 
+                path: '/smartReportDetail',
+                query:{
+                    id:this.$route.query.id,
+                    type:'preview'
+                }
+            });
+			window.open(href, '_blank');
+        },
+
+        // 批量插入myETA数据
+        handleImportMyChart(list){
+            const LINK_CHART_URL = this.$setting.dynamicOutLinks.ChartViewUrl+'/chartshow';
+            // console.log(list);
+            let arr=[]
+            // 分成两个一组
+            for (let index = 0; index < list.length; index+=2) {
+                const temarr=list.slice(index,index+2)
+                let resArr={child:[]}
+                if(temarr.length===1){//落单了
+                    resArr={
+                        compId:3,
+                        compType:'chart',
+                        content:`${LINK_CHART_URL}?code=${temarr[0].UniqueCode}`,
+                        id:this.getCompId(`chart${temarr[0].UniqueCode}_`),
+                        style:'height:350px',
+                        child:[]
+                    }
+                }else{
+                    temarr.forEach(e => {
+                        resArr.child.push({
+                            compId:3,
+                            compType:'chart',
+                            content:`${LINK_CHART_URL}?code=${e.UniqueCode}`,
+                            id:this.getCompId(`chart${e.UniqueCode}_`),
+                            style:'height:350px',
+                            child:[]
+                        })
+                    });
+                }
+                arr.push(resArr)
+            }
+            // console.log(arr);
+            this.conList=[...this.conList,...arr]
+            
+        },
+
+        // 设置sheet iframe 样式
+        setSheetIframeStyle(e){
+            const { height, code } = e.data;
+            // console.log(e.data);
+            let iframeDom = document.getElementsByClassName(`iframe${code}`);
+            // console.log(iframeDom);
+            iframeDom.forEach((ele) => {
+                ele.height = `${height + 45}px`;
+            });
+        },
+
+        handleParentAdd(e){
+            console.log('container-onAdd操作------------------->');
+
+            const {item,newDraggableIndex}=e
+
+            const hasid=item.getAttribute('data-id')
+            console.log(hasid);
+
+            this.conList.forEach(item=>{
+                if(item.id==hasid&&item.style){
+                    const styleArr=item.style.split(';').filter(s=>s&&(s.indexOf('width')===-1&&s.indexOf('flex')===-1)).join(';')
+                    item.style=styleArr
+                }
+            })
+            if(hasid) return
+
+            // 要添加的元素数据
+            const compData=JSON.parse(item.getAttribute('comp-data'))
+            // console.log(compData);
+            // 非注册组件返回
+            // if(!comp){
+            //     this.conList.splice(newDraggableIndex,1)
+            //     return
+            // }
+            const tempCompData={
+                compId:compData.compId,
+                compType:compData.compType,
+                id:this.getCompId(compData.compType),
+                content:compData.content||'',
+                style:compData.compType==='chart'?'height:350px':'',
+                child:[]
+            }
+            // console.log(tempCompData);
+            this.conList.splice(newDraggableIndex,1,tempCompData)
+            // this.activeId=tempCompData.id
+        },
+
+        handleChildAdd(e,parent,parentIndex){
+            console.log('child-onAdd操作------------------->');
+            // console.log(parent);
+            const {item,newDraggableIndex}=e
+
+            const compData=JSON.parse(item.getAttribute('comp-data'))
+
+            console.log(compData,newDraggableIndex);
+
+            const index=parentIndex
+            // if(index>-1){
+                let obj=_.cloneDeep(this.conList[index]) 
+
+                console.log(obj);
+
+                if(obj.child&&obj.child.length===1&&obj.id){
+                    if(compData){
+                        obj={
+                            child:[
+                                {
+                                    compId:obj.compId,
+                                    compType:obj.compType,
+                                    id:obj.id,
+                                    content:obj.content,
+                                    style:obj.compType==='chart'?'height:350px':'',
+                                    child:[]
+                                },
+                                {
+                                    compId:compData.compId,
+                                    compType:compData.compType,
+                                    content:compData.content||'',
+                                    id:this.getCompId(compData.compType),
+                                    style:compData.compType==='chart'?'height:350px':'',
+                                    child:[]
+                                }
+                            ]
+                        }
+                    }else{//是内容区域拖动排序的
+                        const temItem=_.cloneDeep(obj.child[0])
+                        if(temItem.child.length>0){//如果拖动的盒子里面有子元素则不能进入
+                            obj={
+                                ...obj,
+                                child:[]
+                            }
+                            setTimeout(() => {
+                                this.conList.splice(index,0,temItem)
+                            }, 50);
+                        }else{
+                            obj={
+                                child:[
+                                    {
+                                        compId:obj.compId,
+                                        compType:obj.compType,
+                                        id:obj.id,
+                                        content:obj.content,
+                                        style:obj.compType==='chart'?'height:350px':'',
+                                        child:[]
+                                    },
+                                    {
+                                        ...temItem
+                                    }
+                                ]
+                            }
+                        }
+                    }
+                    
+                }else{
+                    if(compData){//如果是从内容区域拖入的没有compData
+                        obj.child.splice(newDraggableIndex,1,{
+                            compId:compData.compId,
+                            compType:compData.compType,
+                            content:compData.content||'',
+                            id:this.getCompId(compData.compType),
+                            style:compData.compType==='chart'?'height:350px':'',
+                            child:[]
+                        })
+                    }
+                }
+                console.log(obj);
+
+                this.conList.splice(index,1,obj)
+            // }
+        },
+
+        handleParentMove(e){
+            // console.log(e.draggedContext);
+            // console.log(e.relatedContext);
+            // // console.log(e.relatedContext.compType);
+            // console.log(e.draggedContext.element.child.length>0&&!e.relatedContext.compType);
+            // if(e.draggedContext.element.child.length>0&&(!e.relatedContext.compType||e.relatedContext.element.compType)) return false
+        },
+
+        // 移除事件 
+        handleChildRemove(e,arr){
+            console.log('child-remove操作------------------->');
+            // 如果都移除了则删除这个
+            // this.conList=this.conList.filter(_item=>!(_item.child&&_item.child.length===0&&!_item.id))
+
+            // 如果当前移出的这个child还有两个的话则重置他们的宽度
+            arr.forEach(item=>{
+                if(item.style){
+                    const styleArr=item.style.split(';').filter(s=>s&&(s.indexOf('width')===-1&&s.indexOf('flex')===-1)).join(';')
+                    item.style=styleArr
+                }
+            })
+
+
+            // 如果child只剩一个了则移出来
+            this.conList=this.conList.map(_item=>{
+                if(_item.child&&_item.child.length===1){
+                    const obj=_item.child[0]
+                    if(obj.style){
+                        const styleArr=obj.style.split(';').filter(s=>s&&(s.indexOf('width')===-1&&s.indexOf('flex')===-1)).join(';')
+                        obj.style=styleArr
+                    }
+                    return obj
+                }else{
+                    return _item
+                }
+            })
+        },
+
+        handleParentRemove(e){
+            console.log('container-remove操作------------------->');
+        },
+
+        // 点击删除某个
+        handleDelItem(pindex,cindex){
+            if(cindex===-1){
+                this.conList.splice(pindex,1)
+            }else{//删除子盒子
+                this.conList[pindex].child.splice(cindex,1)
+                if(this.conList[pindex].child.length===1){//只剩一个子盒子了则变成一个大盒子
+                    const styleArr=this.conList[pindex].child[0].style.split(';').filter(s=>s&&(s.indexOf('width')===-1&&s.indexOf('flex')===-1)).join(';')
+                    this.conList[pindex]=this.conList[pindex].child[0]
+                    this.conList[pindex].style=styleArr
+                }
+            }
+        },
+
+        // 富文本编辑组件/图片组件数据变化
+        handleTextChange(e){
+            console.log(e);
+            this.activeContent=e
+            if(this.activeCindex>=0&&this.activeCindex!==''){
+                if(this.conList[this.activePindex].child[this.activeCindex].content){
+                    this.conList[this.activePindex].child[this.activeCindex].content=e
+                }else{
+                    this.$set(this.conList[this.activePindex].child[this.activeCindex],'content',e)
+                }
+            }else{
+                if(this.conList[this.activePindex].content){
+                    this.conList[this.activePindex].content=e
+                }else{
+                    this.$set(this.conList[this.activePindex],'content',e)
+                }
+            }
+        },
+
+        // 当前再编辑哪个
+        handleChoose(item,index,cindex){
+            //{item:数据,index:父序号,cindex:子序号}
+            if(!item.id||this.isDragResize||!['text','img'].includes(item.compType)) return
+            this.activeId=item.id
+            this.showRight=true
+            this.rightType=item.compType
+            this.activeContent=item.content||''
+            this.activePindex=index
+            this.activeCindex=cindex>=0?cindex:''
+        },
+
+        //点击顶部插入图或者图表等类型
+        handleShowRight(item){
+            this.rightType=item.type
+            this.activeId=''
+            this.activeContent=''
+            this.activePindex=''
+            this.activeCindex=''
+            this.showRight=true 
+        },
+
+        // 关闭右侧
+        handleCloseRight(){
+            this.activeId=''
+            this.activeContent=''
+            this.activePindex=''
+            this.activeCindex=''
+            this.showRight=false
+            this.rightType=''
+        },
+
+        getComponentName(item){
+            const temMap=new Map([
+                ['text',TextComp],
+                ['chart',ChartComp],
+                ['img',ImgComp],
+                ['sheet',SheetComp]
+            ])
+            return temMap.get(item.compType)
+        },
+        // 生产随机id
+        getCompId(type){
+            return type+new Date().getTime()
+        },
+
+        // 编辑保存报告
+        handleReportEdit(e){
+            const html=document.getElementById('report-html-content').outerHTML;
+            const params={
+                SmartReportId:Number(this.$route.query.id)||0,
+                ...e,
+                Content:html,
+                ContentStruct:JSON.stringify(this.conList),
+                HeadImg:this.headImg,
+                EndImg:this.endImg,
+                HeadResourceId:this.headImgId,
+                EndResourceId:this.endImgId,
+                CanvasColor:this.bgColor
+            }
+            console.log(params);
+            //检查classifynameArr是否有审批流
+            let classify = [e.ClassifyIdFirst,e.ClassifyIdSecond]
+            this.checkClassifyNameArr(3,classify)
+
+            apiSmartReport.reportEdit({...params}).then(res=>{
+                if(res.Ret===200){
+                    this.$message.success(this.$t('MsgPrompt.saved_msg'))
+                    this.reportInfo.Title=params.Title
+                    this.layoutBaseInfo['研报标题']=params.Title
+                    this.layoutBaseInfo['研报作者']=params.Author
+                    this.layoutBaseInfo['创建时间']=params.CreateTime
+                    this.showReportBaseInfo=false
+                }
+            })
+        },
+
+        /* 获取动态配置 外部动态链接 */
+        async getPublicSettings() {
+            const res =  await getPublicSettingsApi();
+            if(res.Ret !== 200) return
+            
+            this.$store.commit('SET_DYNAMIC_LINK',res.Data)
+        },
+
+        // 获取报告详情
+        getReportDetail(){
+            const id=this.$route.query.id||0
+            if(!id) return
+            apiSmartReport.reportDetail({
+                SmartReportId:Number(id)
+            }).then(res=>{
+                if(res.Ret===200){
+                    this.reportInfo=res.Data
+                    this.conList=res.Data.ContentStruct?JSON.parse(res.Data.ContentStruct):[]
+                    this.headImg=res.Data.HeadImg
+                    this.endImg=res.Data.EndImg
+                    this.headImgId=res.Data.HeadResourceId
+                    this.endImgId=res.Data.EndResourceId
+
+                    this.headImgStyle=res.Data.HeadStyle?JSON.parse(res.Data.HeadStyle):[]
+                    this.headImgStyle.map(st =>{
+                        st.value=st.value || st.label
+                    })
+                    this.endImgStyle=res.Data.EndStyle?JSON.parse(res.Data.EndStyle):[]
+                    this.endImgStyle.map(st =>{
+                        st.value=st.value || st.label
+                    })
+                    this.bgColor=res.Data.CanvasColor
+                    this.layoutBaseInfo['研报标题']=res.Data.Title
+                    this.layoutBaseInfo['研报作者']=res.Data.Author
+                    this.layoutBaseInfo['创建时间']=res.Data.CreateTime
+                    this.$nextTick(()=>{
+                        this.contentChange=false
+                    })
+                    let classify = [res.Data.ClassifyIdFirst,res.Data.ClassifyIdSecond]
+                    this.checkClassifyNameArr(3,classify)
+                }
+            })
+        },
+
+        // 刷新所有图表和表格
+        handleRefreshAllChart: _.debounce ( async function() {
+            let code_arr = [];
+            let sheet_code_arr = []
+            $('iframe').each((k,i) => {
+                try {
+                    let href = $(i).attr('src');
+                    if(href.includes('chartshow')){
+                        code_arr.push(getUrlParams(href,'code'));
+                    }
+                    if(href.includes('sheetshow')){
+                        sheet_code_arr.push(getUrlParams(href,'code'))
+                    }
+                } catch (err) {
+                }
+            });
+
+            if(!code_arr.length&&!sheet_code_arr.length) return this.$message.warning(this.$t('ReportManage.ReportList.insert_charts_msg'));
+
+            if(this.$route.query.id&&code_arr.length) {
+                let res = await dataBaseInterface.getReportrefreshStatus({
+                Source: 'smart_report',
+                ReportId: Number(this.$route.query.id),
+                ReportChapterId: 0
+                });
+                
+                if(!res.Data.RefreshResult) return this.$message.warning(this.$t('ReportManage.ReportList.chart_refreshed_msg'))
+
+                const { Ret,Msg } = await dataBaseInterface.reportRefresh({
+                    ChartInfoCode: code_arr
+                })
+                
+                if(Ret === 200) {
+                    $('iframe').each((k,i) => {
+                        let href = $(i).attr('src');
+                        if(href.includes('chartshow')){
+                            $(i).attr('src',$(i).attr('src'))
+                        }
+                    });
+                    this.$message.success(Msg);
+                }
+            }
+            if(this.$route.query.id&&sheet_code_arr.length){
+                //获取刷新结果
+                let res = await sheetInterface.getRefreshResult({
+                    Source: 'smart_report',
+                    ReportId: Number(this.$route.query.id),
+                    ReportChapterId: 0
+                });
+                if(!res.Data.RefreshResult) return this.$message.warning('表格正在刷新中,请勿重复操作')
+                const { Ret,Msg } = await sheetInterface.refreshSheet({
+                    ExcelCodes: sheet_code_arr
+                })
+                
+                if(Ret === 200) {
+                    $('iframe').each((k,i) => {
+                        let href = $(i).attr('src');
+                        if(href.includes('sheetshow')){
+                            $(i).attr('src',$(i).attr('src'))
+                        }
+                    });
+                    this.$message.success(Msg);
+                }
+            }
+
+        },1000),
+        
+        // 自动/存草稿保存内容
+        handleSaveContent({isAutoSave}){
+            const html=document.getElementById('report-html-content').outerHTML;
+            return new Promise((resolve,reject)=>{
+                const id=this.$route.query.id||0
+                if(!id) return
+                apiSmartReport.saveReportContent({
+                    SmartReportId:Number(id),
+                    Content:html,
+                    ContentStruct:JSON.stringify(this.conList),
+                    NoChange:this.contentChange?2:1,
+                    HeadImg:this.headImg,
+                    EndImg:this.endImg,
+                    HeadResourceId:this.headImgId,
+                    EndResourceId:this.endImgId,
+                    CanvasColor:this.bgColor
+                }).then(res=>{
+                    if(res.Ret===200){
+                        resolve(true)
+                        if(!isAutoSave){
+                            this.$message.success(this.$t('MsgPrompt.saved_msg'))
+                        }
+                    }
+                    if(res.Msg==='报告已发布, 不允许编辑'){
+                        this.$router.replace({ path: '/smartReportList' });
+                    }
+                })
+            })
+        },
+
+        // 点击定时发布/发布
+        async handlePublishOpt(type){
+            // 存一次草稿
+            const saveRes=await this.handleSaveContent({isAutoSave:true})
+            if(!saveRes) return
+            if(type==='dsfb'){
+                this.showDSFB=true
+                return
+            }
+            // 发布
+            if(type==='submit'){
+                this.submitReport()
+                return
+            }
+            //截止至ETA1.3.8 智能研报无推送模板消息,所有的reportInfo.MsgIsSend都为1
+            if(this.reportInfo.MsgIsSend==1){//该报告已经推送过模板消息
+                this.reportPublish({sendMsg:false})
+            }else{
+                const isPost = this.permissionBtn.checkPermissionBtn(this.permissionBtn.smartReportManageBtn.reportManage_sendMsg)
+                this.$confirm(
+                    isPost?this.$t('ReportManage.smart_msg.publishing_messages'):this.$t('ReportManage.smart_msg.should_published_immediately'), 
+                    this.$t('ReportManage.smart_release_prompt_btn'), 
+                    {
+                        confirmButtonText: isPost?this.$t('ReportManage.smart_btn.push'):this.$t('ReportManage.smart_btn.publish'),
+				        cancelButtonText: isPost?this.$t('ReportManage.smart_btn.not_push'):this.$t('Dialog.cancel_btn'),
+                        type: 'warning',
+                        distinguishCancelAndClose:true,
+                    
+                        beforeClose:(action, instance,done)=>{
+                            if(action==='close') {
+                                //右上角
+                                // this.isPublishloading = false;
+                            } else if(action==='cancel') {
+                                //cancelButton
+                                if(isPost){
+                                    this.reportPublish({sendMsg:false})
+                                }
+                            }else {
+                                //confirmButton
+                                this.reportPublish({sendMsg:isPost?true:false})
+                            }
+                            done()
+                        }
+                    }
+                )
+            }
+        },
+        //提交报告
+        submitReport(){
+             this.$confirm(this.$t('ReportManage.smart_msg.submit_approval'),this.$t('Confirm.prompt'),{
+                confirmButtonText: this.$t('Dialog.confirm_btn'),
+                cancelButtonText: this.$t('Dialog.cancel_btn'),
+                type:'warning',
+            }).then(()=>{
+                approveInterence.reportSmartSubmit({
+                    ReportId:Number(this.$route.query.id)
+                }).then(res=>{
+                    if(res.Ret!==200) return 
+                    this.$message.success(this.$t('ReportManage.smart_msg.submit_success'))
+                    this.$router.replace({ path: '/smartReportList' });
+                })
+            })
+        },
+
+        // 定时发布报告
+        async handleSetReportPrepublish(){
+            if(!this.taskTime){
+				this.$message.warning(this.$t('ReportManage.smart_msg.select_push_time'))
+				return
+			}
+			const now=this.$moment().format('YYYY-MM-DD HH:mm:ss')
+			// console.log(now);
+			// console.log(this.taskTime);
+			if(this.$moment(this.taskTime).isBefore(now,'second')){
+				this.$message.warning(this.$t('ReportManage.smart_msg.than_current_time'))
+				return
+			}
+            // 如果该报告已经推送过模板消息
+            if(this.reportInfo.MsgIsSend==1){
+                apiSmartReport.prePublishReport({
+                    SmartReportId:Number(this.$route.query.id),
+                    PrePublishTime:this.taskTime,
+                    PreMsgSend:0,
+                    ReportUrl:this.generatePdfLinks(this.reportInfo.ReportCode)
+                }).then(res=>{
+                    if(res.Ret===200){
+                        this.$message.success(this.$t('ReportManage.smart_msg.timed_success'))
+                        this.$router.replace({ path: '/smartReportList' });
+                    }
+                })
+                return
+            }
+
+            const isPost = this.permissionBtn.checkPermissionBtn(this.permissionBtn.smartReportManageBtn.reportManage_sendMsg)
+
+           this.$confirm(isPost?this.$t('ReportManage.smart_msg.push_report_msg'):this.$t('ReportManage.smart_msg.is_push_timed'), this.$t('ReportManage.smart_release_prompt_btn'), {
+				confirmButtonText: isPost?this.$t('ReportManage.smart_btn.push'):this.$t('ReportManage.smart_btn.publish'),
+				cancelButtonText: isPost?this.$t('ReportManage.smart_btn.not_push'):this.$t('Dialog.cancel_btn'),
+				type: 'warning',
+				distinguishCancelAndClose:true,
+				beforeClose:(action, instance,done)=>{
+					console.log(action, instance);
+					if(action==='close'||action==='cancel') {
+						//右上角或者不推送
+						if(isPost){
+							apiSmartReport.prePublishReport({
+								SmartReportId:Number(this.$route.query.id),
+								PrePublishTime:this.taskTime,
+								PreMsgSend:0,
+                                ReportUrl:this.generatePdfLinks(this.reportInfo.ReportCode)
+							}).then(res=>{
+								if(res.Ret===200){
+									this.$message.success(this.$t('ReportManage.smart_msg.timed_success'))
+									this.$router.replace({ path: '/smartReportList' });
+								}
+							})
+						}
+					} else {
+						//confirmButton
+						apiSmartReport.prePublishReport({
+							SmartReportId:Number(this.$route.query.id),
+							PrePublishTime:this.taskTime,
+							PreMsgSend:isPost?1:0,
+                            ReportUrl:this.generatePdfLinks(this.reportInfo.ReportCode)
+						}).then(res=>{
+							if(res.Ret===200){
+								this.$message.success(this.$t('ReportManage.smart_msg.timed_success'))
+								this.$router.replace({ path: '/smartReportList' });
+							}
+						})
+					}
+					done()
+				}
+			})
+        },
+
+        // 发布报告
+        reportPublish({sendMsg}){
+            apiSmartReport.publishReport({
+                SmartReportId:Number(this.$route.query.id),
+                PublishState:2,
+                ReportUrl:this.generatePdfLinks(this.reportInfo.ReportCode)
+            }).then(res=>{
+                if(res.Ret===200){
+                    if(sendMsg){
+                        this.reportSendMsg()
+                    }
+                    this.$router.replace({ path: '/smartReportList' });
+                }
+            })
+        },
+        generatePdfLinks(Code){
+            const baseUrl= localStorage.getItem('dynamicOutLinks') ? JSON.parse(localStorage.getItem('dynamicOutLinks')).ReportViewUrl : '';
+            return `${baseUrl}/reportshare_smart_pdf?code=${Code}`
+        },
+        //报告消息推送
+        reportSendMsg(){
+            apiSmartReport.reportMsgSend({SmartReportId:Number(this.$route.query.id)}).then(res=>{})
+        },
+
+        // 插入版头版尾
+        handleInsertImgSource(e){
+            console.log(e,'eeee');
+            if(e.type=='1'){
+                this.$message.success(this.$t('ReportManage.ReportList.header_setting_msg'))
+                this.headImg=e.data.ImgUrl
+                this.headImgId = e.data.ResourceId
+                this.headImgStyle=e.data.Style?JSON.parse(e.data.Style):[]
+            }else{
+                this.$message.success(this.$t('ReportManage.ReportList.trailer_setting_msg'))
+                this.endImg=e.data.ImgUrl
+                this.endImgId = e.data.ResourceId
+                this.endImgStyle=e.data.Style?JSON.parse(e.data.Style):[]
+            }
+            this.contentChange=true
+        },
+
+        handleBgColorChange(e){
+            this.bgColor=e||''
+            this.contentChange=true
+        },
+        // 删除版头版尾
+        deleteLayoutPic(type){
+            if(type=='1'){
+                this.headImg=''
+                this.headImgId = 0
+            }else{
+                this.endImg=''
+                this.endImgId = 0
+            }
+            this.contentChange=true
+        }
+    },
+    computed:{
+      topTypeList(){
+           return [
+                {
+                    name:this.$t('ReportManage.ReportList.library_top_type'),
+                    type:'imgSource',
+                    icon:require('@/assets/img/smartReport/icon04.png')
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.chart_top_type'),
+                    type:'etaChart',
+                    icon:require('@/assets/img/smartReport/icon04.png')
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.eta_top_type'),
+                    type:'etaSheet',
+                    icon:require('@/assets/img/smartReport/icon05.png')
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.statistical_top_type'),
+                    type:'statisticAnalysis',
+                    icon:require('@/assets/img/smartReport/icon06.png')
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.price_curve_radio'),
+                    type:'etaPriceChart',
+                    icon:require('@/assets/img/smartReport/icon07.png')
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.sandbox_top_type'),
+                    type:'etaSandBox',
+                    icon:require('@/assets/img/smartReport/icon08.png')
+                },
+                {
+                    name:this.$t('ReportManage.ReportList.semantic_top_type'),
+                    type:'semanticAnalysis',
+                    icon:require('@/assets/img/smartReport/icon09.png')
+                }
+            ]
+      }
+    },
+    created() {
+        this.getPublicSettings()
+        this.getReportDetail()
+    },
+    mounted () {
+        window.addEventListener('message',this.setSheetIframeStyle)
+        this.timer = setInterval(() => {
+			this.handleSaveContent({isAutoSave:true});
+		}, 6000);
+    },
+    destroyed() {
+		window.removeEventListener('message',this.setSheetIframeStyle)
+        if (this.timer) {
+			clearInterval(this.timer);
+		}
+	},
+}
+</script>
+
+<style lang="scss">
+// 拖拽时的样式
+.edit-smart-report-page{
+.sortable-ghost{
+    position: relative !important;
+    &::before{
+        content: '' !important;
+        display: block !important;
+        width: 100% !important;
+        height: 10px !important;
+        background-color: rgba(64, 158, 255, 0.74) !important;
+        position: absolute !important;
+        left: 0 !important;
+        top: 0 !important;
+    }
+    // height: 5px !important;
+    // background-color: #0052D9 !important;
+    // overflow: hidden !important;
+    // padding: 0 !important;
+    // min-height: 0 !important;
+    // border: none !important;
+}
+
+.el-color-picker__trigger{
+    &::after{
+        content:'';
+        display: block;
+        position: absolute;
+        top: 0;
+        left: 0;
+        width: 100%;
+        height: 100%;
+        background-color: #fff;
+    }
+    .el-color-picker__color::after{
+        content: '';
+        display: block;
+        width: 16px;
+        height: 16px;
+        position: absolute;
+        left: 7px;
+        top: 7px;
+        background-image: url('~@/assets/img/smartReport/icon18.png');
+        background-size: cover;
+        background-repeat: no-repeat;
+        z-index: 10;
+    }
+}
+
+}
+</style>
+<style lang='scss' scoped>
+div{
+    box-sizing: border-box;
+}
+.edit-smart-report-page{
+    background: var(--unnamed, #F2F6FA);
+    min-width: 100vw;
+    min-height: 100vh;
+    .top-action-wrap{
+        position: sticky;
+        top: 0px;
+        background-color: #fff;
+        box-shadow: 0px 2px 12px 0px rgba(0, 0, 0, 0.10);
+        height: 60px;
+        display: flex;
+        justify-content: space-between;
+        align-content: center;
+        padding: 0 24px;
+        .title{
+            line-height: 60px;
+            font-size: 16px;
+        }
+        .action-list{
+            display: flex;
+            align-items: center;
+            .action-item{
+                height: 36px;
+                display: flex;
+                align-items: center;
+                border-right: 1px solid #C8CDD9;
+                padding: 0 30px;
+                font-size: 16px;
+                cursor: pointer;
+                img{
+                    width: 16px;
+                    height: 16px;
+                    margin-right: 4px;
+                    position: relative;
+                    top: 2px;
+                }
+                &:last-child{
+                    border-right: none;
+                }
+                &.disabled{
+                    pointer-events: none;
+                    cursor: not-allowed;
+                    color:#999;
+                }
+            }
+        }
+    }
+    .main-wrap{
+        display: flex;
+        justify-content: center;
+    }
+}
+.report-action-wrap{
+    width: 800px;
+    flex-shrink: 0;
+    margin-left: 90px;
+    margin-right: 60px;
+    margin-top: 30px;
+    position: relative;
+    .report-comp-wrap{
+            position: absolute;
+            left: -62px;
+            top: 72px;
+            width: 40px;
+            border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+            background: var(--gary-gy-white, #FFF);
+            border-radius: 4px;
+            overflow: hidden;
+            .comp-item{
+                cursor: move;
+                height: 40px;
+                display: flex;
+                align-items: center;
+                justify-content: center;
+                border-bottom: 1px solid var(--gary-gy-5-line, #C8CDD9);
+                &:last-child{
+                    border-bottom: none;
+                }
+                img{
+                    width: 16px;
+                }
+            }
+    }
+    .top-type-list{
+        margin-bottom: 20px;
+        display: flex;
+        align-items: center;
+        background-color: #fff;
+        height: 80px;
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        .item{
+            cursor: pointer;
+            flex: auto;
+            display: flex;
+            flex-direction: column;
+            align-items: center;
+            justify-content: center;
+            border-right: 1px solid #C8CDD9;
+            font-size: 16px;
+            &:last-child{
+                border-right: none;
+            }
+            .icon{
+                width: 20px;
+                height: 20px;
+                // margin-right: 4px;
+            }
+        }
+    }
+    .report-content-box{
+        border-radius: 4px;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        background: #FFF;
+        padding: 20px 20px 20px 44px;
+        height: calc(100vh - 210px);
+        position: relative;
+        overflow-y: auto;
+        .html-head-img-box,.html-end-img-box{
+            position: relative;
+            &:hover{
+                .opt-btn-box{
+                    display: block !important;
+                }
+            }
+            .opt-btn-box{
+                position: absolute;
+                left: -36px;
+                padding-right: 8px;
+                top: 0;
+                .del-btn::after{
+                    content: '';
+                    display: block;
+                    width: 28px;
+                    height: 28px;
+                    background-image: url('~@/assets/img/smartReport/icon13.png');
+                    background-size: cover;
+                    cursor: pointer;
+                }
+            }
+            .head-layout-item{
+                position: absolute;
+                overflow: hidden;
+                box-sizing: border-box
+            }
+        }
+    }
+}
+
+
+
+.main-wrap{
+    .report-html-wrap{
+        &::after{
+            content: '';
+            display: block;
+            height: 300px;
+        }
+        min-height: 100%;
+        .report-drag-item-wrap{
+            width: 100%;
+            padding: 6px;
+            min-height: 80px;
+            border: 1px dashed #0052D9;
+            position: relative;
+            margin-bottom: 3px;
+            &:hover{
+                border-style: solid;
+                .opt-btn-box{
+                    display: block !important;
+                }
+                .resize-drag-box{
+                    display: block;
+                }
+            }
+            .opt-btn-box{
+                position: absolute;
+                left: -36px;
+                padding-right: 8px;
+                top: 0;
+                .drag-btn::after{
+                    content: '';
+                    display: block;
+                    width: 28px;
+                    height: 28px;
+                    background-image: url('~@/assets/img/smartReport/icon12.png');
+                    background-size: cover;
+                    cursor: pointer;
+                }
+                .del-btn::after{
+                    content: '';
+                    display: block;
+                    width: 28px;
+                    height: 28px;
+                    background-image: url('~@/assets/img/smartReport/icon13.png');
+                    background-size: cover;
+                    cursor: pointer;
+                }
+            }
+            .resize-drag-box{
+                position: absolute;
+                right: -4px;
+                bottom: -4px;
+                width: 8px;
+                height: 8px;
+                display: none;
+                border: 1px solid #0052D9;
+                cursor: nw-resize;
+            }
+        }
+        .report-drag-item-out{
+            .report-drag-item-wrap_child-wrap{
+                position: absolute;
+                width: 40px;
+                right: 0;
+                top: 0;
+                height: 100%;
+            }
+        }
+        .report-drag-item-wrap_child-wrap{
+            // min-height: 30px;
+        }
+        .report-drag-item-wrap_child_content{
+            min-height: 80px;
+            border: 1px dashed #0052D9;
+            flex: 1;
+            position: relative;
+            &:hover{
+                border-style: solid;
+                .opt-btn-box2{
+                    display: block !important;
+                }
+                .resize-drag-box_lt,
+                .resize-drag-box_lb,
+                .resize-drag-box_rt,
+                .resize-drag-box_rb{
+                    display: block;
+                }
+            }
+            .opt-btn-box2{
+                position: absolute;
+                right: -15px;
+                top: 0;
+                z-index: 10;
+                .drag-btn::after{
+                    content: '';
+                    display: block;
+                    width: 28px;
+                    height: 28px;
+                    background-image: url('~@/assets/img/smartReport/icon12.png');
+                    background-size: cover;
+                    cursor: pointer;
+                }
+                .del-btn::after{
+                    content: '';
+                    display: block;
+                    width: 28px;
+                    height: 28px;
+                    background-image: url('~@/assets/img/smartReport/icon13.png');
+                    background-size: cover;
+                    cursor: pointer;
+                }
+            }
+            .resize-drag-box_lt,
+            .resize-drag-box_lb,
+            .resize-drag-box_rt,
+            .resize-drag-box_rb{
+                position: absolute;
+                width: 8px;
+                height: 8px;
+                display: none;
+                border: 1px solid #0052D9;
+            }
+            .resize-drag-box_lt{
+                left: -4px;
+                top: -4px;
+                cursor: nw-resize;
+            }
+            .resize-drag-box_lb{
+                left: -4px;
+                bottom: -4px;
+                cursor: ne-resize;
+            }
+            .resize-drag-box_rt{
+                right: -4px;
+                top: -4px;
+                cursor: ne-resize;
+            }
+            .resize-drag-box_rb{
+                right: -4px;
+                bottom: -4px;
+                cursor: nw-resize;
+            }
+        }
+        .blue-bg{
+            background: var(--brand-brand-1-light, #ECF2FE);
+        }
+    }
+}
+
+.main-wrap{
+    .right-action-wrap{
+        height: calc(100vh - 60px);
+        overflow: hidden;
+        flex: 1;
+        position: relative;
+        padding-top: 30px;
+        padding-left: 75px;
+        padding-right: 30px;
+        padding-bottom: 30px;
+        &::before{
+            display: block;
+            content: '';
+            width: 1px;
+            height: 100vh;
+            background-color: #C8CDD9;
+            position: absolute;
+            left: 15px;
+            top: 0;
+        }
+        .close-icon{
+            width: 20px;
+            height: 20px;
+            border-radius: 4px;
+            background: #FFF;
+            box-shadow: 0px 4px 4px 0px rgba(0, 0, 0, 0.25);
+            display: flex;
+            justify-content: center;
+            align-items: center;
+            cursor: pointer;
+            position: absolute;
+            left: 5px;
+            top: 22px;
+            img{
+                width: 16px;
+                height: 16px;
+            }
+        }
+    }
+}
+</style>

+ 338 - 0
src/views/report_manage/reportV2/smartReport/reportDetail.vue

@@ -0,0 +1,338 @@
+<template>
+    <div class="smart-report-detail">
+        <div class="main-box" :style="{backgroundColor:bgColor}">
+            <!-- <div class="top-box">
+                <div class="title">{{reportInfo&&reportInfo.Title}}</div>
+                <div class="flex">
+                    <span>{{reportInfo&&reportInfo.Author}}</span>
+                    <span>{{reportInfo&&reportInfo.PublishTime}}</span>
+                </div>
+            </div> -->
+            <div class="html-head-img-box" v-if="reportInfo && !!reportInfo.NeedSplice && reportInfo.HeadImg">
+                <img :src="reportInfo.HeadImg" alt="" style="display:block;width:100%">
+                <div class="head-layout-item" v-for="item in headImgStyle" :key="item.value"
+                :style="{fontFamily:item.family,fontSize:(item.size*2)+'px',fontWeight:item.weight,textAlign:item.align,color:item.color,
+                    width:item.width,height:item.height,left:item.left,top:item.top
+                }">
+                    {{ layoutBaseInfo[item.value] }}
+                </div>
+            </div>
+            <!-- 无版头版尾 -->
+            <div class="no-layout-img-box" v-if="reportInfo && !!reportInfo.NeedSplice && (!reportInfo.HeadImg) && (!reportInfo.EndImg)">
+                <header>{{reportInfo.Title}}</header>
+                <div style=" box-sizing:border-box; color:#666; font-size:24px; overflow:hidden;">
+                    <span>{{ reportInfo.Author}}</span>
+                    <span style="float:right;">{{reportInfo.CreateTime}}</span>
+                </div>
+            </div>
+            <div class="abstract" v-if="reportInfo && !!reportInfo.NeedSplice">
+                <div>摘要: <span v-html="reportInfo.Abstract"></span></div> 
+            </div>
+            <div class="html-wrap" v-html="content"></div>
+            <div class="html-end-img-box" v-if="reportInfo && !!reportInfo.NeedSplice && reportInfo.EndImg">
+                <img :src="reportInfo.EndImg" alt="" style="display:block;width:100%">
+                <div class="head-layout-item" v-for="item in endImgStyle" :key="item.value"
+                :style="{fontFamily:item.family,fontSize:(item.size*2)+'px',fontWeight:item.weight,textAlign:item.align,color:item.color,
+                    width:item.width,height:item.height,left:item.left,top:item.top
+                }">
+                    {{ layoutBaseInfo[item.value] }}
+                </div>
+            </div> 
+        </div>
+        <div class="right-opt-box" v-if="$route.query.type!=='preview'&&!reportId">
+            <div 
+                class="item copy" 
+                v-if="linkUrl" 
+                :data-clipboard-text='linkUrl' 
+                @click="copyHandle"
+                v-permission="permissionBtn.smartReportManageBtn.reportManage_reportView_copyWechat"
+            >
+                <img src="~@/assets/img/icons/cop.png" alt="" style="width:30px;height:30px;margin-right:10px;">
+                <span>复制链接</span>
+            </div>
+            <div 
+                class="item wechat-item" 
+                v-if="linkUrl"
+                v-permission="permissionBtn.smartReportManageBtn.reportManage_reportView_copyWechat"
+            >
+                <img src="~@/assets/img/icons/wechat.png" alt="" style="width:30px;height:30px;margin-right:10px;">
+                <span>微信分享</span>
+                <vue-qr 
+                    :text="linkUrl" 
+                    :margin="0" 
+                    colorDark="#333" 
+                    colorLight="#fff" 
+                    :dotScale="1" 
+                    :size="100" 
+                    class="qrcode"
+                ></vue-qr>
+            </div>
+            <!-- 去除详情页导出图片 放到报告列表页去 -->
+            <!-- <div class="item" v-if="reportInfo.State == 2" @click="handleGetReportImg" v-permission="permissionBtn.smartReportManageBtn.reportManage_reportView_exportImg">
+                <img src="~@/assets/img/smartReport/icon16.png" alt="" style="width:30px;height:30px;marginRight:10px;">
+                <span>导&nbsp;&nbsp;图</span>
+            </div> -->
+        </div>
+
+        <!-- 报告图片 -->
+        <div class="report-img-box" v-if="showReportImg&&reportImgUrl" @click="showReportImg=false">
+            <img :src="reportImgUrl" alt="" @click.stop="">
+        </div>
+    </div>
+</template>
+
+<script>
+import {apiSmartReport}  from '@/api/modules/smartReport'
+import vueQr from 'vue-qr'
+export default {
+    computed: {
+		linkUrl(){
+			let str=''
+			const baseUrl= localStorage.getItem('dynamicOutLinks') ? JSON.parse(localStorage.getItem('dynamicOutLinks')).ReportViewUrl : '';
+			if(this.$route.query.code){
+				str=`${baseUrl}/reportshare_smart_report?code=${this.$route.query.code}`
+			}
+			return str
+		},
+        //是否开启审批流,若开启,导图按钮在非已审批的状态不显示
+        isApprove(){
+            const type = this.$setting.dynamicOutLinks.ApprovalFlow ||
+                        this.$store.state.dynamicOutLinks.ApprovalFlow ||
+                        JSON.parse(localStorage.getItem('dynamicOutLinks')).ApprovalFlow||''
+            return ['2','3'].includes(type)
+        }
+    },
+    props:{
+        reportId:{//审批详情-预览报告
+            type:Number,
+            default:0
+        }
+    },
+    data() {
+        return {
+            /**
+             * NeedSplice 0-不需要 1-需要
+             */
+            reportInfo:null,
+            content:'',
+            bgColor:'',
+            reportImgUrl:'',
+            showReportImg:false,
+            headImgStyle:null,//版头style
+            endImgStyle:null,//版尾style
+            layoutBaseInfo:{
+                研报标题:'',
+                研报作者:'',
+                创建时间:''
+            }
+        }
+    },
+    created() {
+        this.getReportDetail()
+    },
+    methods: {
+        // 获取报告详情
+        getReportDetail(){
+            const id=this.$route.query.id||this.reportId||0
+            if(!id) return
+            this.$emit("reportStartLoading")
+            apiSmartReport.reportDetail({
+                SmartReportId:Number(id)
+            }).then(res=>{
+                this.$emit("reportEndLoading")
+                if(res.Ret===200){
+                    this.reportInfo=res.Data || {}
+                    this.headImgStyle=this.reportInfo.HeadStyle?JSON.parse(this.reportInfo.HeadStyle):[]
+                    this.headImgStyle.map(st =>{
+                        st.value=st.value || st.label
+                    })
+                    this.endImgStyle=this.reportInfo.EndStyle?JSON.parse(this.reportInfo.EndStyle):[]
+                    this.endImgStyle.map(st =>{
+                        st.value=st.value || st.label
+                    })
+                    this.layoutBaseInfo['研报标题']=this.reportInfo.Title
+                    this.layoutBaseInfo['研报作者']=this.reportInfo.Author
+                    this.layoutBaseInfo['创建时间']=this.reportInfo.CreateTime
+                    if(this.$route.query.type==='preview'){
+                       this.content=sessionStorage.getItem('smartReportContent')
+                       this.bgColor=sessionStorage.getItem('smartReportContentBg')
+                    }else{
+                        this.content=res.Data.Content
+                        this.bgColor=res.Data.CanvasColor
+                    }
+                }else{
+                    this.$emit("reportError")
+                }
+            })
+        },
+
+        /* 复制链接 */
+		copyHandle() {
+				var clipboard = new this.Clipboard('.copy')
+				clipboard.on('success', e => {
+					this.$message.success('复制链接成功')
+					e.clearSelection() // 释放内存
+					clipboard.destroy()
+				})
+				// // 浏览器不支持
+				clipboard.on('error', e => {
+					this.$message.warning('浏览器暂不支持')
+					// 释放内存
+					clipboard.destroy()
+				})
+		},
+
+        handleGetReportImg(){
+            // if(this.reportImgUrl){
+            //     this.showReportImg=true
+            //     return
+            // }
+            apiSmartReport.getReportImg({
+                SmartReportId:Number(this.$route.query.id)
+            }).then(res=>{
+                if(res.Ret===200){
+                    // this.reportImgUrl=res.Data
+                    // this.showReportImg=true
+                    // 改为直接下载图片不是展示
+                    this.saveImg(res.Data)
+                }else{
+                    if(res.Ret!==403){
+                        this.$message.warning(res.Msg)
+                    }
+                }
+            })
+        },
+
+        saveImg(imgUrl){
+            let img=new Image()
+            img.setAttribute('crossOrigin', 'anonymous');
+            img.src=imgUrl
+            img.onload=()=>{
+                let canvas = document.createElement("canvas");
+                canvas.width = img.width;
+                canvas.height = img.height;
+                let context = canvas.getContext('2d');
+                context.drawImage(img, 0, 0, img.width, img.height);
+                let dataURL = canvas.toDataURL("image/png", 1);
+                const a=document.createElement('a')
+                a.setAttribute("download",this.reportInfo.Title)
+                a.style.display = "none"
+                a.href=dataURL
+                document.body.appendChild(a);
+                a.click()
+            }
+            img.onerror=(e)=>{
+                console.log(e);
+                this.$message.warning("自动下载图片失败,请手动保存")
+                if(imgUrl){
+                    this.reportImgUrl=imgUrl
+                    this.showReportImg=true
+                }
+            }
+        }
+    },
+}
+</script>
+
+<style lang="scss">
+div{
+    box-sizing: border-box;
+}
+.smart-report-detail{
+    .right-opt-box{
+            position: fixed;
+            top: 100px;
+            left: calc(50% + 450px);
+            .item{
+                display: flex;
+                align-items: center;
+                cursor: pointer;
+                margin-bottom: 20px;
+                position: relative;
+                .qrcode{
+                    position: absolute;
+                    left: 110%;
+                    display: none !important;
+                    z-index: 9;
+                }
+            }
+            .wechat-item{
+                &:hover{
+                    .qrcode{
+                        display: inline-block !important;
+                    }
+                }
+            }
+    }
+    .main-box{
+        width: 800px;
+        padding: 20px 20px 20px 44px;
+        margin: 20px auto;
+        border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+        border-radius: 4px;
+        overflow: hidden;
+        position: relative;
+        .top-box{
+            width: 100%;
+            height: 160px;
+            background-image: url('~@/assets/img/smartReport/bg01.png');
+            background-size: cover;
+            background-repeat: no-repeat;
+            background-position: center;
+            padding: 40px;
+            color: #fff;
+            .title{
+                font-size: 20px;
+                margin-bottom: 20px;
+            }
+            .flex{
+                display: flex;
+                justify-content: space-between;
+            }
+        }
+        .html-wrap{
+            // padding: 30px;
+            .report-drag-item-wrap{
+                padding: 6px;
+                margin-bottom: 3px;
+            }
+        }
+        .html-head-img-box,.html-end-img-box{
+            position: relative;
+            .head-layout-item{
+                position: absolute;
+                overflow: hidden;
+                box-sizing: border-box
+            }
+        }
+        .no-layout-img-box{
+            header{
+                padding:10px 0; box-sizing:border-box; font-size:28px; font-weight:500; color:#333; background:#fff; 
+            }
+        }
+        .abstract{
+            padding:10px 0; box-sizing:border-box; font-size:22px; line-height:36px;
+            div{
+                padding: 10px 20px;
+                box-sizing: border-box;
+                background: rgba(20, 121, 253, 0.1);
+                color: #4099ef;
+                border-radius: 10px;
+            }
+        }
+    }
+    .report-img-box{
+        position: fixed;
+        left: 0;
+        top: 0;
+        bottom: 0;
+        right: 0;
+        overflow-y: auto;
+        background: rgba($color: #000000, $alpha: 0.6);
+        text-align: center;
+        img{
+            max-width: 800px;
+        }
+    }
+}
+</style>

+ 0 - 24
src/views/report_manage/reportV2/smartReportEditor.vue

@@ -1,24 +0,0 @@
-<template>
-  <div>
-
-  </div>
-</template>
-<script>
-export default {
-  data() {
-    return {
-
-    }
-  },
-  mounted(){
-
-  },
-  methods:{
-
-  },
-}
-
-</script>
-<style scoped lang='scss'>
-
-</style>