Browse Source

合并master

yujinwen 6 months ago
parent
commit
95bf495560
42 changed files with 1923 additions and 226 deletions
  1. 38 2
      src/api/modules/pptApi.js
  2. 38 3
      src/api/modules/reportV2.js
  3. 21 0
      src/api/modules/smartReport.js
  4. BIN
      src/assets/img/version_record.png
  5. 2 0
      src/lang/modules/ReportManagement/ReportList.js
  6. 10 0
      src/lang/modules/Slides/pptPresent.js
  7. 14 2
      src/lang/modules/systemManage/BaseConfig.js
  8. 14 1
      src/utils/buttonConfig.js
  9. 13 4
      src/views/chartRelevance_manage/components/saveChartSetting.vue
  10. 19 13
      src/views/dataEntry_manage/addChart.vue
  11. 18 10
      src/views/dataEntry_manage/chartSetting.vue
  12. 10 2
      src/views/dataEntry_manage/components/chartSourceEditDialog.vue
  13. 7 0
      src/views/dataEntry_manage/components/markersSection.vue
  14. 19 11
      src/views/dataEntry_manage/editChart.vue
  15. 1 1
      src/views/datasheet_manage/customSheetEdit.vue
  16. 1 1
      src/views/datasheet_manage/mixedSheetEdit.vue
  17. 14 2
      src/views/intervalAnalysis/components/chartSetWrap.vue
  18. 1 1
      src/views/ppt_manage/mixins/layerMixins.js
  19. 4 0
      src/views/ppt_manage/mixins/pptEditorMixins.js
  20. 22 5
      src/views/ppt_manage/mixins/pptMixins.js
  21. 50 3
      src/views/ppt_manage/newVersion/components/catalog/addPptBaseDia.vue
  22. 21 2
      src/views/ppt_manage/newVersion/components/catalog/mergePPTDialog.vue
  23. 21 6
      src/views/ppt_manage/newVersion/components/editor/ChooseCoverNew.vue
  24. 44 18
      src/views/ppt_manage/newVersion/components/formatEl/ChartEl.vue
  25. 13 9
      src/views/ppt_manage/newVersion/components/formatEl/SheetEl.vue
  26. 227 0
      src/views/ppt_manage/newVersion/components/layer/VersionRecord.vue
  27. 242 0
      src/views/ppt_manage/newVersion/components/selectImage.vue
  28. 117 17
      src/views/ppt_manage/newVersion/pptEditor.vue
  29. 7 7
      src/views/ppt_manage/newVersion/pptPresent.vue
  30. 11 10
      src/views/ppt_manage/newVersion/pptPublish.vue
  31. 8 1
      src/views/ppt_manage/newVersion/utils/tinymceSetting.js
  32. 2 0
      src/views/ppt_manage/newVersion/utils/untils.js
  33. 8 0
      src/views/report_manage/reportV2/components/reportEditHeader.vue
  34. 233 0
      src/views/report_manage/reportV2/normalReport/components/VersionRecord.vue
  35. 15 2
      src/views/report_manage/reportV2/normalReport/components/insertContent.vue
  36. 49 12
      src/views/report_manage/reportV2/normalReport/editReport.vue
  37. 24 11
      src/views/report_manage/reportV2/normalReport/reportdtl.vue
  38. 233 0
      src/views/report_manage/reportV2/smartReport/components/VersionRecord.vue
  39. 59 14
      src/views/report_manage/reportV2/smartReport/editReport.vue
  40. 41 1
      src/views/report_manage/reportV2/smartReport/reportDetail.vue
  41. 221 51
      src/views/system_manage/components/smartReportImgSet.vue
  42. 11 4
      src/views/system_manage/etaBaseConfig.vue

+ 38 - 2
src/api/modules/pptApi.js

@@ -316,8 +316,44 @@ export default{
      */
     getAuthPPtList: params => {
         return http.get('pptv2/report/auth_list',params)
-    }
-
+    },
 
+    /**
+     * 获取版本列表
+     * @param {*} params 
+     * PptId
+     * @returns 
+     */
+    getPptHistoryList: params => {
+        return http.get('ppt_history/list',params)
+    },
 
+    /**
+     * 获取版本详情
+     * @param {*} params 
+     * Id
+     * @returns 
+     */
+    getPptHistoryDetail: params => {
+        return http.get('ppt_history/detail',params)
+    },
+    /**
+     * 恢复到版本
+     * @param {*} params 
+     * Id
+     * @returns 
+     */
+    getPptHistoryRevert: params => {
+        return http.post('ppt_history/revert',params)
+    },
+    
+    /**
+     * 删除版本
+     * @param {*} params 
+     * Id
+     * @returns 
+     */
+    getPptHistoryDel: params => {
+        return http.post('ppt_history/del',params)
+    },
 }

+ 38 - 3
src/api/modules/reportV2.js

@@ -124,10 +124,45 @@ export const reportV2Interface = {
 	 */
 	readReportNotice: params => {
 		return http.post('/report/message/read',params)
-	}
-
-
+	},
 
+	/**
+	 * * 获取报告记录列表
+	 * @param {*ReportId} params 
+	 * @param {*ReportChapterId} params 
+	 * @returns 
+	 * */
+	reportHistoryList: params => {
+		return http.get('/report_history/list',params)
+	},
+	/**
+	 * * 获取报告记录详情
+	 * @param {*ReportId} params 
+	 * @param {*id} params 
+	 * @returns 
+	 * */
+	reportHistoryDetail: params => {
+		return http.get('/report_history/detail',params)
+	},
+	
+	/**
+	 * * 删除报告记录
+	 * @param {*ReportId} params 
+	 * @param {*Id} params 
+	 * @returns 
+	 * */
+	reportHistoryDel: params => {
+		return http.post('/report_history/del',params)
+	},
+	/**
+	 * * 恢复报告记录
+	 * @param {*ReportId} params 
+	 * @param {*Id} params 
+	 * @returns
+	 * */
+	reportHistoryRevert: params => {
+		return http.post('/report_history/revert',params)
+	},
 }
 
 

+ 21 - 0
src/api/modules/smartReport.js

@@ -82,12 +82,33 @@ const apiSmartReport={
     imgReourceList:params=>{
         return http.get('/smart_report/resource/list',params)
     },
+    
 
     //新增资源库图片
     imgReourceAdd:params=>{
         return http.post('/smart_report/resource/add',params)
     },
 
+    //根据条件查询ppt图片素材
+    pptMaterialList:params=>{
+        return http.get('/image_conf/get/image/material',params)
+    },
+
+    //新增图片素材
+    pptAddMaterial:params=>{
+        return http.post('/image_conf/add/image/material',params)
+    },
+
+    //删除图片素材
+    pptDeleteMaterial:params=>{
+        return http.post('/image_conf/delete/image/material',params)
+    },
+
+    //修改图片素材
+    pptEditMaterial:params=>{
+        return http.post('/image_conf/edit/image/material',params)
+    },
+
     // //资源库图片重命名
     // imgReourceRename:params=>{
     //     return http.post('/smart_report/resource/rename',params)

BIN
src/assets/img/version_record.png


+ 2 - 0
src/lang/modules/ReportManagement/ReportList.js

@@ -38,6 +38,7 @@ export const ReportListEn = {
   last_save_time: "Last save time",
   click_clear_btn: "Clear Content",
   click_refresh_btn: "Rfrsh",
+  version_record: "Version record",
   preview_btn: "Preview",
   save_draft_btn: "Draft",
   scheduled_publish_btn: "Schedule",
@@ -210,6 +211,7 @@ export const ReportListZh = {
   last_save_time: "最近保存时间",
   click_clear_btn: "一键清空内容",
   click_refresh_btn: "一键刷新",
+  version_record: "版本记录",
   preview_btn: "预览",
   save_draft_btn: "存草稿",
   scheduled_publish_btn: "定时发布",

+ 10 - 0
src/lang/modules/Slides/pptPresent.js

@@ -11,11 +11,16 @@ export const presentEn = {
   return_to_list: "Return to list",
   default_publish: " Publish",
   select_cover_page: "Select cover page",
+  select_ground_page: "Replace background image",
+  select_back_page: "Replace the back cover image",
+  more_cover_page: "More templates for cover images",
+  more_templates:'More templates',
   operating_instructions: "Operating instructions",
   click_to_input_title: "Click to input title",
   update_chart_btn: "Update chart",
   paste_element_btn: "Paste element",
   layer_editing: "Layer editing",
+  version_history: "Version history",
   keyword_search: "Keyword search",
   eta_chart_gallery: "Chart Gallery",
   commodity_price_curve: "Commodity Price Curve",
@@ -116,11 +121,16 @@ export const presentZh = {
   return_to_list: "返回列表",
   default_publish: "(默认)发布",
   select_cover_page: "选择封面页",
+  select_ground_page: "更换背景图",
+  select_back_page: "更换封底图",
+  more_cover_page: "封面图更多模板",
+  more_templates: "更多模板",
   operating_instructions: "操作说明",
   click_to_input_title: "单击输入标题",
   update_chart_btn: "更新图表",
   paste_element_btn: "粘贴元素",
   layer_editing: "图层编辑",
+  version_history: "版本记录",
   keyword_search: "关键字查找",
   eta_chart_gallery: "图库",
   commodity_price_curve: "商品价格曲线",

+ 14 - 2
src/lang/modules/systemManage/BaseConfig.js

@@ -57,6 +57,10 @@ export const BaseConfigEn = {
     resource_placeholder03:'Please upload Image',
     resource_type01:'Header',
     resource_type02:'Footer',
+    ppt_type01:'Cover Image',
+    ppt_type02:'Background Image',
+    ppt_type03:'Back Cover Image',
+    ppt_btn02:'Edit Image',
     resource_btn01:'Upload Image',
     resource_btn02:'Rename',
     resource_btn03:'Deselect/Deselect All',
@@ -73,13 +77,15 @@ export const BaseConfigEn = {
     edit_layout:"Edit Layout",
     completed_step:"Completed Step",
     text_style:"Text Style",
-    smart_layout_resource_library:"Intelligent Research Report Template Library",
+    smart_layout_resource_library:"Intelligent Research Report Layout",
+    ppt_resource_library:"PPT Material Library",
     style_font_w_normal:'normal',
     style_font_w_bold:'body',
     style_text_align_left:'left',
     style_text_align_center:'center',
     style_text_align_right:'right',
     upload_suggest:'Supports formats like jpg, jpeg, png, etc. It is recommended to upload headers of 800*200 and footers of 800*80',
+    upload_ppt_suggest:'Supports formats like jpg, jpeg, png, etc.',
     resource_del_msg:'Are you sure to delete the selected image?',
 
     tip_msg01:'Save successful, please check the corresponding page/project later',
@@ -162,6 +168,10 @@ export const BaseConfigZh = {
     resource_placeholder03:'请上传图片',
     resource_type01:'版头',
     resource_type02:'版尾',
+    ppt_type01:'封面图',
+    ppt_type02:'背景图',
+    ppt_type03:'封底图',
+    ppt_btn02:'编辑图片',
     resource_btn01:'上传图片',
     resource_btn02:'重命名',
     resource_btn03:'取消选择',
@@ -178,7 +188,8 @@ export const BaseConfigZh = {
     edit_layout:"编辑版图",
     completed_step:"已完成步骤",
     text_style:"文字样式",
-    smart_layout_resource_library:"智能研报版图资源库",
+    smart_layout_resource_library:"智能研报版图",
+    ppt_resource_library:"PPT素材库",
     // 样式
     style_font_w_normal:'常规体',
     style_font_w_bold:'加粗体',
@@ -186,6 +197,7 @@ export const BaseConfigZh = {
     style_text_align_center:'居中',
     style_text_align_right:'居右',
     upload_suggest:'支持jpg、jpeg、png等格式,建议上传版头800*200,版尾800*80',
+    upload_ppt_suggest:'支持jpg、jpeg、png等格式',
     resource_del_msg:'是否确认删除选中图片?',
 
     tip_msg01:'保存成功,请稍后到对应页面/项目查看',

+ 14 - 1
src/utils/buttonConfig.js

@@ -42,6 +42,7 @@ export const reportManageBtn={
     reportMange_chapter_sort: 'reportMange:chapter:sort',//章节排序
     reportMange_chapter_share: 'reportMange:chapter:share',//章节分享
     reportMange_chapter_editTag: 'reportMange:chapter:editTag',//章节添加标签
+    reportMange_history: 'reportManage:history',//历史记录
 }
 /*
  *--------智能研报列表----------- 
@@ -195,6 +196,7 @@ export const pptPermission ={
     ppt_addCatalog:'ppt:addCatalog',//添加我的目录
     ppt_setShare:'ppt:setShare',//设置共享
     ppt_visible:'ppt:visible',//可见权限
+    ppt_history:'ppt:history',//添加我的目录
 }
 /*
 *--------英文PPT---------- 
@@ -431,6 +433,7 @@ export const chartLibPermission = {
     chartLib_uploadToForum:'chartLib:uploadToForum',//上传至社区
     chartLib_updateToForum:'chartLib:updateToForum',//同步至社区
     chartLib_withdrawfromForum:'chartLib:withdrawfromForum',//从社区撤回
+    chartLib_sourceEdit:'chartLib:sourceEdit',//编辑数据来源
 }
 
 /*
@@ -495,6 +498,7 @@ export const etaTablePermission = {
     etaTable_customize_mix_download:'etaTable:customize:mix:download',//下载
     etaTable_customize_mix_save:'etaTable:customize:mix:save',//保存
     etaTable_customize_mix_del:'etaTable:customize:mix:del',//删除
+    etaTable_customize_mix_source_edit:'etaTable:customize:mix:classifyOpt:sourceEdit',//编辑数据来源
 
     //数据表格页面
     etaTable_customize_data_sheetAdd: 'etaTable:customize:data:sheetAdd',//添加数据表格按钮
@@ -506,6 +510,7 @@ export const etaTablePermission = {
     etaTable_customize_data_download:'etaTable:customize:data:download',//下载
     etaTable_customize_data_del:'etaTable:customize:data:del',//删除
     etaTable_customize_data_save:'etaTable:customize:data:save',//保存
+    etaTable_customize_data_sourceEdit:'etaTable:customize:data:classifyOpt:sourceEdit',//编辑数据来源
 
     /*-----------excel表格页面--------- */
     etaTable_excel:'etaTable:excel',//添加Excel表格这个按钮显示不显示
@@ -621,6 +626,7 @@ export const statisticPermission = {
     corrAnalysis_classifyOpt_edit:'corrAnalysis:classifyOpt:edit',//添加/编辑分类
     corrAnalysis_classifyOpt_delete:'corrAnalysis:classifyOpt:delete',//删除分类
     corrAnalysis_classifyOpt_move:'corrAnalysis:classifyOpt:move',//移动分类
+    corrAnalysis_source_edit:'corrAnalysis:sourceEdit',//编辑数据来源
         /*---图表操作栏--- */
     corrAnalysis_del:'corrAnalysis:del',
     corrAnalysis_enNameSetting:'corrAnalysis:enNameSetting',
@@ -688,6 +694,7 @@ export const statisticPermission = {
     rangeAnalysis_classifyOpt_edit:'rangeAnalysis:classifyOpt:edit',//添加编辑分类
     rangeAnalysis_classifyOpt_delete:'rangeAnalysis:classifyOpt:delete',//删除分类
     rangeAnalysis_classifyOpt_move:'rangeAnalysis:classifyOpt:move',//删除分类
+    rangeAnalysis_source_edit:'rangeAnalysis:sourceEdit',//编辑数据来源
     /*---图表操作栏--- */
     rangeAnalysis_del:'rangeAnalysis:del',
     rangeAnalysis_copyWechat:'rangeAnalysis:copyWechat',
@@ -827,8 +834,14 @@ export const baseConfigPermission = {
     etaBaseConfig_biApprove:'etaBaseConfig:biApprove',//BI看板审批
     etaBaseConfig_login:'baseSetting:loginSetting',//登录
     etaBaseConfig_watermark_ybShare:'etaBaseConfig:watermark:ybShare',//如果没权限,表单不显示也不校验
-    etaBaseConfig_source_see:'baseSetting:sourceSetting:see',//资源库查看
+    etaBaseConfig_source_see:'baseSetting:sourceSetting:see',//资源库版图查看
     etaBaseConfig_source_upload:'baseSetting:sourceSetting:upload',//资源库上传
+    etaBaseConfig_source_edit:'baseSetting:sourceSetting:edit',//资源库编辑
+    etaBaseConfig_source_del:'baseSetting:sourceSetting:del',//资源库删除
+    etaBaseConfig_source_ppt_upload:'pptMaterial:upload',//资源库ppt上传
+    etaBaseConfig_source_ppt_see:'pptMaterial:find',//资源库ppt查看
+    etaBaseConfig_source_ppt_edit:'pptMaterial:edit',//资源库ppt编辑
+    etaBaseConfig_source_ppt_del:'pptMaterial:delete',//资源库ppt删除
     // 登录设置
     etaBaseConfig_login_systemLogo_mobile:'baseSetting:loginSetting:systemLogo:mobile',//系统logo移动端
     etaBaseConfig_login_systemLogo_pc:'baseSetting:loginSetting:systemLogo:pc',//系统logoPC端

+ 13 - 4
src/views/chartRelevance_manage/components/saveChartSetting.vue

@@ -15,7 +15,7 @@
                 label-width="100px"
                 ref="settingForm">
                 <el-form-item label="图表名称">
-                    <el-input v-model="settingData.chartName"></el-input>
+                    <el-input style="width: 250px;" v-model="settingData.chartName"></el-input>
                 </el-form-item>
                 <el-form-item label="图例名称" style="margin-bottom: 0;">
                 </el-form-item>
@@ -27,13 +27,15 @@
                                 size="mini"
                                 show-alpha
                                 :predefine="predefineColors"/>
-                            <el-input v-model="data.Name"></el-input>
+                            <el-input style="width: 250px;" v-model="data.Name"></el-input>
                         </div>
                     </div>
                 </el-form-item>
                 <el-form-item label="数据来源">
-                    <el-input v-model="settingData.SourcesFrom.text"></el-input>
-                    <el-switch v-model="settingData.SourcesFrom.isShow"></el-switch>
+                    <div class="flex-align">
+                        <el-input :disabled="!permissionBtn.checkPermissionBtn(permissionBtn.statisticPermission.corrAnalysis_source_edit)" :autosize="{ minRows: 2, maxRows: 4}" style="width: 250px;margin-right: 5px;" type="textarea" maxlength="50" show-word-limit v-model="settingData.SourcesFrom.text"></el-input>
+                        <el-switch v-model="settingData.SourcesFrom.isShow"></el-switch>
+                    </div>
                 </el-form-item>
             </el-form>
         </div>
@@ -107,5 +109,12 @@ export default {
         text-align:center;
         margin:30px 0 20px 0;
     }
+    .flex-align{
+        display: flex;
+        align-items: center;
+        .el-textarea .el-input__count{
+            background: transparent;
+        }
+    }
 }
 </style>

+ 19 - 13
src/views/dataEntry_manage/addChart.vue

@@ -549,7 +549,17 @@
 						</div>
 
 						<div class="chart-bottom-insruction-info">
-
+							
+							<!-- 图表说明 -->
+							<div 
+								class="chart-instruction" 
+								v-if="chartInfo.Instructions&&JSON.parse(chartInfo.Instructions).isShow"
+								v-text="JSON.parse(chartInfo.Instructions).text"
+								:style="`
+									color: ${JSON.parse(chartInfo.Instructions).color};
+									fontSize: ${ JSON.parse(chartInfo.Instructions).fontSize }px
+								`"
+							></div>
 							<div class="chart-source">
 								<span
 									v-if="chartInfo.SourcesFrom"
@@ -568,7 +578,7 @@
 									style="margin:0 15px;"
 									@change="changeSourceVisable"
 								/>
-								<span class="editsty" @click="isShowSourceDialog=true"><!-- 编辑 -->{{$t('Chart.chart_edit_btn')}}</span>
+								<span class="editsty" v-if="permissionBtn.checkPermissionBtn(permissionBtn.chartLibPermission.chartLib_sourceEdit)" @click="isShowSourceDialog=true"><!-- 编辑 -->{{$t('Chart.chart_edit_btn')}}</span>
 							</div>
 
 							<!-- 是否堆积 -->
@@ -599,17 +609,6 @@
 								<el-radio-button label="公历">{{$t('Chart.calendar_gre')}}</el-radio-button>
 								<el-radio-button label="农历">{{$t('Chart.calendar_lunar_text')}}</el-radio-button>
 							</el-radio-group>
-
-							<!-- 图表说明 -->
-							<div 
-								class="chart-instruction" 
-								v-if="chartInfo.Instructions&&JSON.parse(chartInfo.Instructions).isShow"
-								v-text="JSON.parse(chartInfo.Instructions).text"
-								:style="`
-									color: ${JSON.parse(chartInfo.Instructions).color};
-									fontSize: ${ JSON.parse(chartInfo.Instructions).fontSize }px
-								`"
-							></div>
 						</div>
 
 
@@ -1342,6 +1341,13 @@ export default {
 			}
 		}
 	}
+	.chart-bottom-insruction-info{
+		display:block;
+		.chart-instruction{
+			margin-bottom:16px;
+			width:auto;
+		}
+	}
 }
 </style>
 <style lang="scss">

+ 18 - 10
src/views/dataEntry_manage/chartSetting.vue

@@ -510,6 +510,17 @@
                       ><!-- 作者 -->{{$t('Chart.Detail.author')}}:{{ chartInfo.SysUserRealName || '' }}</span
                     >
 
+                    <!-- 图表说明 -->
+                    <div 
+                        class="chart-instruction" 
+                        v-if="chartInfo.Instructions&&JSON.parse(chartInfo.Instructions).isShow"
+                        v-text="JSON.parse(chartInfo.Instructions).text"
+                        :style="`
+                          color: ${JSON.parse(chartInfo.Instructions).color};
+                          fontSize: ${ JSON.parse(chartInfo.Instructions).fontSize }px
+                        `"
+                      ></div>
+
                     <div class="chart-bottom-insruction-info">
 
                       <div class="chart-source" >
@@ -533,16 +544,6 @@
                         <el-radio-button label="农历">{{$t('Chart.calendar_lunar_text')}}</el-radio-button>
                       </el-radio-group>
 
-                      <!-- 图表说明 -->
-                      <div 
-                        class="chart-instruction" 
-                        v-if="chartInfo.Instructions&&JSON.parse(chartInfo.Instructions).isShow"
-                        v-text="JSON.parse(chartInfo.Instructions).text"
-                        :style="`
-                          color: ${JSON.parse(chartInfo.Instructions).color};
-                          fontSize: ${ JSON.parse(chartInfo.Instructions).fontSize }px
-                        `"
-                      ></div>
                     </div>
                     
                   </div>
@@ -3128,6 +3129,13 @@ export default {
       z-index: -100;
     }
   }
+  .chart-bottom-insruction-info{
+		display:block;
+		.chart-instruction{
+			margin-bottom:16px;
+			width:auto;
+		}
+	}
 
 }
 </style>

+ 10 - 2
src/views/dataEntry_manage/components/chartSourceEditDialog.vue

@@ -19,6 +19,10 @@
       >
         <el-form-item :label="$t('Edb.Detail.source')">
           <el-input
+            :autosize="{ minRows: 2, maxRows: 4}"
+            type="textarea"
+            maxlength="50"
+            show-word-limit
             v-model="chartSourceForm.text"
             :placeholder="$t('Chart.InputHolderAll.input_content')"
           />
@@ -100,6 +104,10 @@ export default {
   },
 }
 </script>
-<style scoped lang='scss'>
-
+<style lang='scss'>
+.marker-edit-dialog{
+  .el-textarea .el-input__count{
+    background: transparent;
+  }
+}
 </style>

+ 7 - 0
src/views/dataEntry_manage/components/markersSection.vue

@@ -202,6 +202,10 @@
         >
           <el-form-item :label="$t('Chart.Detail.chart_intru')">
             <el-input
+              :autosize="{ minRows: 2, maxRows: 5}"
+              type="textarea"
+              maxlength="100"
+              show-word-limit
               v-model="chartInductionDiaForm.text"
               :placeholder="$t('Chart.InputHolderAll.input_content')"
             />
@@ -541,5 +545,8 @@ export default {
       align-items: center;
     }
   }
+  .marker-edit-dialog .el-textarea .el-input__count{
+    background: transparent;
+  }
 }
 </style>

+ 19 - 11
src/views/dataEntry_manage/editChart.vue

@@ -556,6 +556,17 @@
 
 						<div class="chart-bottom-insruction-info">
 
+							<!-- 图表说明 -->
+							<div 
+								class="chart-instruction" 
+								v-if="chartInfo.Instructions&&JSON.parse(chartInfo.Instructions).isShow"
+								v-text="JSON.parse(chartInfo.Instructions).text"
+								:style="`
+									color: ${JSON.parse(chartInfo.Instructions).color};
+									fontSize: ${ JSON.parse(chartInfo.Instructions).fontSize }px
+								`"
+							></div>
+
 							<div class="chart-source">
 									<span
 										v-if="chartInfo.SourcesFrom"
@@ -572,7 +583,7 @@
 									style="margin:0 15px;"
 									@change="changeSourceVisable"
 								/>
-								<span class="editsty" @click="isShowSourceDialog=true"><!-- 编辑 -->{{$t('Chart.chart_edit_btn')}}</span>
+								<span class="editsty" v-if="permissionBtn.checkPermissionBtn(permissionBtn.chartLibPermission.chartLib_sourceEdit)" @click="isShowSourceDialog=true"><!-- 编辑 -->{{$t('Chart.chart_edit_btn')}}</span>
 							</div>
 
 							<!-- 是否堆积 -->
@@ -603,16 +614,6 @@
 								<el-radio-button label="农历">{{$t('Chart.calendar_lunar_text')}}</el-radio-button>
 							</el-radio-group>
 
-							<!-- 图表说明 -->
-							<div 
-								class="chart-instruction" 
-								v-if="chartInfo.Instructions&&JSON.parse(chartInfo.Instructions).isShow"
-								v-text="JSON.parse(chartInfo.Instructions).text"
-								:style="`
-									color: ${JSON.parse(chartInfo.Instructions).color};
-									fontSize: ${ JSON.parse(chartInfo.Instructions).fontSize }px
-								`"
-							></div>
 						</div>
 
 						<span class="chart-author"><!-- 作者 -->{{$t('Chart.Detail.author')}}:{{ chartInfo.SysUserRealName }}</span>
@@ -1471,6 +1472,13 @@ export default {
 			}
 		}
 	}
+	.chart-bottom-insruction-info{
+		display:block;
+		.chart-instruction{
+			margin-bottom:16px;
+			width:auto;
+		}
+	}
 }
 </style>
 <style lang="scss">

+ 1 - 1
src/views/datasheet_manage/customSheetEdit.vue

@@ -98,7 +98,7 @@
         style="margin:0 15px;"
         @change="(e) => {sheetSourceFrom.isShow=e,sheetForm.SourcesFrom=JSON.stringify(sheetSourceFrom)}"
       />
-      <span class="editsty" @click="isShowSourceDialog=true"><!-- 编辑 -->{{$t('Common.edit_btn')}}</span>
+      <span class="editsty" v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_customize_data_sourceEdit)" @click="isShowSourceDialog=true"><!-- 编辑 -->{{$t('Common.edit_btn')}}</span>
     </div>
 
     <!-- 数据来源编辑弹窗 -->

+ 1 - 1
src/views/datasheet_manage/mixedSheetEdit.vue

@@ -67,7 +67,7 @@
         style="margin:0 15px;"
         @change="(e) => {sheetSourceFrom.isShow=e,sheetForm.SourcesFrom=JSON.stringify(sheetSourceFrom)}"
       />
-      <span class="editsty" @click="isShowSourceDialog=true"><!-- 编辑 -->{{$t('Common.edit_btn')}}</span>
+      <span class="editsty" v-if="permissionBtn.checkPermissionBtn(permissionBtn.etaTablePermission.etaTable_customize_mix_source_edit)" @click="isShowSourceDialog=true"><!-- 编辑 -->{{$t('Common.edit_btn')}}</span>
     </div>
 
     <!-- 数据来源编辑弹窗 -->

+ 14 - 2
src/views/intervalAnalysis/components/chartSetWrap.vue

@@ -82,8 +82,10 @@
           </div>
         </div>
         <el-form-item :label="$t('Edb.Detail.source')" prop="source">
-          <el-input v-model="formData.source" style="width:80%"></el-input>
-          <el-switch v-model="formData.showSource"></el-switch>
+          <div class="flex-align">
+            <el-input :disabled="!permissionBtn.checkPermissionBtn(permissionBtn.statisticPermission.rangeAnalysis_source_edit)" :autosize="{ minRows: 2, maxRows: 4}" type="textarea" maxlength="50" show-word-limit v-model="formData.source" style="width:80%;margin-right: 5px;"></el-input>
+            <el-switch v-model="formData.showSource"></el-switch>
+          </div>
         </el-form-item>
       </el-form>
       <div class="dia-bot">
@@ -238,4 +240,14 @@ div{
     text-align: center;
   }
 }
+</style>
+
+<style lang="scss">
+.flex-align{
+  display: flex;
+  align-items: center;
+  .el-textarea .el-input__count{
+      background: transparent;
+  }
+}
 </style>

+ 1 - 1
src/views/ppt_manage/mixins/layerMixins.js

@@ -21,6 +21,7 @@ export default {
   methods:{
     //改变编辑模式
     handleChangeEditModal(){
+      this.isVersionHistory = false
       //判断当前ppt是否添加了页面
       if(this.pageList.length===0){
         this.$message.warning(this.$t('Slides.msg_page_at_least_one'))
@@ -33,7 +34,6 @@ export default {
       if(this.isEditLayer){
         //进入图层编辑模式,需要退出其他模式
         this.isEditTitle = false
-        
         //如果当前活跃图层没有layers,加上
         if(!this.currentItem.layers){
           this.refleshLayerEl([])

+ 4 - 0
src/views/ppt_manage/mixins/pptEditorMixins.js

@@ -112,6 +112,7 @@ export default{
     },
     exitEditTitle(e){
         this.isEditTitle = false
+        this.isVersionHistory = false
     },
     //切换标题编辑模式
     handleEditTitle(item){
@@ -126,6 +127,7 @@ export default{
             this.isEditLayer = false
             this.activeLayerEl = {}
             this.isEditTitle = false
+            this.isVersionHistory = false
             
             this.pageList.map((item,index)=>{
                 if(item.id===id){
@@ -143,10 +145,12 @@ export default{
             })
         }
         this.isEditTitle = true
+        this.isVersionHistory = false
         if(this.isEditTitle){
             //进入标题编辑模式,需要退出其他模式
             this.isEditLayer = false
             this.activeLayerEl = {}
+            this.isVersionHistory = false
             
             //初始化该页标题的数据
             if(!this.currentItem.titleDetail){

+ 22 - 5
src/views/ppt_manage/mixins/pptMixins.js

@@ -182,7 +182,7 @@ export default {
                EnPptCoverImgs,EnPptBackgroundImg,EnPptBottomImg,PptCompanyNameEn,PptTeamNameEn,PptFontColorEn,EnPptSheetSize
               } = res.Data
         if(this.currentLang==='en'){
-            this.pptCoverList = EnPptCoverImgs.split(',')
+            // this.pptCoverList = EnPptCoverImgs.split(',')
             this.pptBgImage = EnPptBackgroundImg
             this.pptBackImage = EnPptBottomImg
             this.pptCoverCompenyName = PptCompanyNameEn
@@ -190,7 +190,7 @@ export default {
             this.pptCoverTextColor = PptFontColorEn
             this.pptSheetSize = EnPptSheetSize
         }else{
-            this.pptCoverList = CnPptCoverImgs.split(',')
+            // this.pptCoverList = CnPptCoverImgs.split(',')
             this.pptBgImage = CnPptBackgroundImg
             this.pptBackImage = CnPptBottomImg
             this.pptCoverCompenyName = PptCompanyName
@@ -201,15 +201,27 @@ export default {
     },
     //获取ppt详情
     async getpptDataById(id){
-      const res = this.currentLang!=='en'?await pptInterface.getpptDetail({
-        PptId:id
-      }):await pptEnInterface.getpptDetail({PptId:id})
+      let res = null
+      if (this.$route.query.isVersionRecord === 'true') {
+        res = await pptInterface.getPptHistoryDetail({
+          Id:id
+        })
+      } else {
+        res = this.currentLang!=='en'?await pptInterface.getpptDetail({
+          PptId:id
+        }):await pptEnInterface.getpptDetail({PptId:id})
+      }
       if(res.Ret===200){
         const {
             Content,
             Title,
             ReportType,
             BackgroundImg,
+            CurrentBackgroundImg,
+            BackCoverImg,
+            BackCoverImgId,
+            BackgroundImgId,
+            CurrentBackgroundImgId,
             PptDate,
             TemplateType,
             ReportId,
@@ -244,7 +256,12 @@ export default {
                 ReportType,
                 BackgroundImg,
                 PptDate: pptDate,
+                CurrentBackgroundImg,
+                BackCoverImg,
                 TemplateType,
+                BackCoverImgId,
+                BackgroundImgId,
+                CurrentBackgroundImgId,
             },
             ReportId,
             ModifyTime,

+ 50 - 3
src/views/ppt_manage/newVersion/components/catalog/addPptBaseDia.vue

@@ -131,6 +131,7 @@
 import { pptInterface } from '@/api/api.js';
 import chooseCooperaUserDia from '@/views/report_manage/reportV2/components/chooseCooperaUserDia.vue';
 import chooseInherReportDia from '@/views/report_manage/reportV2/components/chooseInherReportDia.vue';
+import { apiSmartReport } from '@/api/modules/smartReport'
 export default {
   name: "BaseInfo",
   components: { chooseCooperaUserDia,chooseInherReportDia },
@@ -156,6 +157,8 @@ export default {
       if (!n) return
       
       this.getclassifylist();
+      this.getBackCoverList()
+      this.getBackGroundList()
       
       if (this.reportInfo) {
           this.formData = {
@@ -183,7 +186,13 @@ export default {
         classify: 0,
         title: "",
         cooperationType: 1,//协作方式
-        cooperationUsers: []
+        cooperationUsers: [],
+        FirstPage:{
+          CurrentBackgroundImg: "", 
+          BackCoverImg: "", 
+          CurrentBackgroundImgId: 0, 
+          BackCoverImgId: 0, 
+        }
       },
 
       classifyArr: [],
@@ -232,7 +241,13 @@ export default {
         classify: 0,
         title: "",
         cooperationType: 1,//协作方式
-        cooperationUsers: []
+        cooperationUsers: [],
+        FirstPage:{
+          CurrentBackgroundImg: "", 
+          BackCoverImg: "", 
+          CurrentBackgroundImgId: 0, 
+          BackCoverImgId: 0, 
+        }
       }
 
       this.$emit("update:show", false);
@@ -247,7 +262,8 @@ export default {
         Title: this.formData.title,
         CollaborateType: this.formData.cooperationType,
         InheritPptId: this.formData.inheritId,
-        CollaborateUserIds: this.formData.cooperationUsers.map(_ => _.NodeId)
+        CollaborateUserIds: this.formData.cooperationUsers.map(_ => _.NodeId),
+        FirstPage:this.formData.FirstPage
       };
 
       // 编辑
@@ -374,6 +390,37 @@ export default {
       });
     },
 
+    // 获取封底列表
+    getBackCoverList(){
+      apiSmartReport.pptMaterialList({
+          CurrentIndex: 1,
+          PageSize: 1000,
+          ImageType: 3,
+          ImageName: '',
+          ConfType: 1
+      }).then(res => {
+        if(res.Data.List){
+          this.formData.FirstPage.BackCoverImg=res.Data.List[0].Url
+          this.formData.FirstPage.BackCoverImgId=res.Data.List[0].ImageConfId
+        }
+      })
+    },
+    // 获取背景列表
+    getBackGroundList(){
+      apiSmartReport.pptMaterialList({
+          CurrentIndex: 1,
+          PageSize: 1000,
+          ImageType: 2,
+          ImageName: '',
+          ConfType: 1
+      }).then(res => {
+        if(res.Data.List){
+          this.formData.FirstPage.CurrentBackgroundImg=res.Data.List[0].Url
+          this.formData.FirstPage.CurrentBackgroundImgId=res.Data.List[0].ImageConfId
+        }
+      })
+    },
+
     filterNodes(arr) {
 			arr.length && arr.forEach(item => {
 				if(item.Child && item.Child.length) {

+ 21 - 2
src/views/ppt_manage/newVersion/components/catalog/mergePPTDialog.vue

@@ -209,7 +209,7 @@ export default {
         this.init()
         this.getCatalogsList('init')
         this.getPPtList()
-        this.getBaseConfig()
+        // this.getBaseConfig()
       }
       if(!newValue){
         if(this.saveLoading){
@@ -301,6 +301,15 @@ export default {
 
       if(res_font.Ret===200){
         content_font = JSON.parse(res_font.Data.Content)
+        this.pptInfo={
+          ...this.pptInfo,
+          ImgUrl:res_font.Data.BackgroundImg,
+          BackgroundImgId:res_font.Data.BackgroundImgId,
+          BackCoverImg:res_font.Data.BackCoverImg,
+          BackCoverImgId:res_font.Data.BackCoverImgId,
+          CurrentBackgroundImg:res_font.Data.CurrentBackgroundImg,
+          CurrentBackgroundImgId:res_font.Data.CurrentBackgroundImgId
+        }
       } 
       const res_back = await pptInterface.getpptDetail({
         PptId:this.choosedIdArr[1]
@@ -324,12 +333,22 @@ export default {
         ImgUrl,
         BackIndex,
         TemplateType, 
+        CurrentBackgroundImgId,
+        CurrentBackgroundImg,
+        BackCoverImg,
+        BackCoverImgId,
+        BackgroundImgId
       } = this.pptInfo
-
+      console.log(this.pptInfo)
       const res = await pptInterface.addpptV2({
           FirstPage:{
             Title,
             ImgUrl,
+            CurrentBackgroundImgId,
+            CurrentBackgroundImg,
+            BackCoverImg,
+            BackCoverImgId,
+            BackgroundImgId,
             BackIndex,
             TemplateType 
           },

+ 21 - 6
src/views/ppt_manage/newVersion/components/editor/ChooseCoverNew.vue

@@ -13,7 +13,7 @@
             <div class="edit-cover-wrap" @mousedown.stop="clickOutside">
                 <div class="cover">
                     <!-- 封面图 -->
-                    <div class="editor-area" :style="`background-image:url(${pptCoverList[choosedIndex]});`">
+                    <div class="editor-area" :style="`background-image:url(${pptCoverList[choosedIndex].Url});`">
                         <!-- 封面内文本元素 -->
                         <TextEl v-for="el in coverElList" :key="el.id"
                             :element-info="el"
@@ -39,6 +39,7 @@
                         <div class="cover-text-toolbar" @mousedown.stop></div>
                     </div>
                     <div class="dialog-btn">
+                        <el-button @click="chooseCoverImg">{{$t('Slides.more_templates')}}</el-button>
                         <el-button @click="changeBg">{{$t('Slides.change_the_template_cover')}}</el-button>
                         <el-button @click="saveCover">{{$t('Dialog.confirm_save_btn')}}</el-button>
                     </div>
@@ -97,15 +98,24 @@ export default {
             if(newVal){
                 this.setCoverInfo()
             }
-        }
+        },
     },
     methods: {
+        showDialog(){
+            this.changeActEl({})
+            this.setCoverInfo()
+        },
         setCoverInfo() {
             this.pageData.Title = this.firstPage.Title||''
-            this.searchIndex = this.pptCoverList.findIndex(i=>i===this.firstPage.BackgroundImg)
+            this.searchIndex = this.pptCoverList.findIndex(i=>i.Url===this.firstPage.BackgroundImg)
             //如果基本配置-封面图,没有当前ppt的封面图,则默认第一个
             if(this.searchIndex===-1){
-                this.pageData.BackgroundImg = this.pptCoverList[0]
+                this.pageData.BackgroundImg = this.pptCoverList[0].Url
+                this.pageData.BackgroundImgId = this.pptCoverList[0].ImageConfId
+            }else{
+                this.pageData.BackgroundImg = this.pptCoverList[this.searchIndex].Url
+                this.pageData.BackgroundImgId = this.pptCoverList[this.searchIndex].ImageConfId
+                this.choosedIndex=this.searchIndex
             }
             //如果封面页内容不是合法的json,置空
             try{
@@ -163,7 +173,7 @@ export default {
             const url = canvas.toDataURL("image/png")
             this.checkImg(url)
             //转换完成后,将背景图设置回来
-            cover.style.backgroundImage = `url(${this.pptCoverList[this.choosedIndex]})`
+            cover.style.backgroundImage = `url(${this.pptCoverList[this.choosedIndex].Url})`
             return url
         },
             //测试用
@@ -179,13 +189,18 @@ export default {
         clickOutside(){
             this.changeActEl({})
         },
+        //选择更多封面图
+        chooseCoverImg(){
+            this.$emit('chooseMoreCover')  
+        },
         changeBg(){
             if(this.choosedIndex<this.pptCoverList.length-1){
                 this.choosedIndex++
             }else{
                 this.choosedIndex=0
             }
-            this.pageData.BackgroundImg = this.pptCoverList[this.choosedIndex]
+            this.pageData.BackgroundImg = this.pptCoverList[this.choosedIndex].Url
+            this.pageData.BackgroundImgId = this.pptCoverList[this.choosedIndex].ImageConfId
         },
         addTextEl(options={}){
             let el = _.cloneDeep(BaseTextShape)

+ 44 - 18
src/views/ppt_manage/newVersion/components/formatEl/ChartEl.vue

@@ -41,25 +41,28 @@
   <!-- 底部来源,图表说明 -->
   <div class="chart-bottom-insruction-info"
   v-if="((chartSourcesFrom&&chartSourcesFrom.isShow) || (chartInstructions&&chartInstructions.isShow)) &&!this.$parent.isHintShow(position)">
-
-    <div class="chart-source text_oneLine" v-if="chartSourcesFrom&&chartSourcesFrom.isShow">
-        <span
-          :style="`
-          color: ${ chartSourcesFrom.color };
-          fontSize: ${ chartSourcesFrom.fontSize }px;
-        `"
-        >{{$t('Slides.source_info')}}:{{ chartSourcesFrom.text}}</span>
-    </div>
+    <el-tooltip  v-if="showSource()" popper-class="tooltip-width" :offset="50" effect="dark" :content="chartSourcesFrom.text" placement="top-start">
+      <div class="chart-source text_oneLine" :class="{'show-width':!showInstruction()}">
+          <span
+            :style="`
+            color: ${ chartSourcesFrom.color };
+            fontSize: ${ chartSourcesFrom.fontSize }px;
+          `"
+          >{{$t('Slides.source_info')}}:{{ chartSourcesFrom.text}}</span>
+      </div>
+    </el-tooltip>
     <!-- 图表说明 -->
-    <div 
-      class="chart-instruction text_oneLine"
-      v-if="chartInstructions&&chartInstructions.isShow&&chartInstructions.text.length"
-      v-text="chartInstructions.text"
-      :style="`
-        color: ${chartInstructions.color};
-        fontSize: ${ chartInstructions.fontSize }px
-      `"
-    ></div>
+    <el-tooltip  v-if="showInstruction()" popper-class="tooltip-width" :offset="-40" effect="dark" :content="chartInstructions.text" :placement="!showSource()?'top-start':'top-end'">
+      <div 
+        class="chart-instruction text_oneLine"
+        :class="{'show-width':!showSource()}"
+        v-text="chartInstructions.text"
+        :style="`
+          color: ${chartInstructions.color};
+          fontSize: ${ chartInstructions.fontSize }px
+        `"
+      ></div>
+    </el-tooltip>
   </div>
  
 </div>
@@ -97,6 +100,12 @@ export default {
     };
   },
   methods:{
+    showSource(){
+      return this.chartSourcesFrom&&this.chartSourcesFrom.isShow
+    },
+    showInstruction(){
+      return this.chartInstructions&&this.chartInstructions.isShow&&this.chartInstructions.text.length
+    },
     copyChartName(position){
         console.log(this.chartInfoMap[this.item.chartId])
       this.$parent.copyChartName(position)
@@ -138,4 +147,21 @@ export default {
   align-items: center;
   justify-content: space-between;
 }
+.chart-source{
+  width: 35%;
+  flex: none;
+}
+.chart-instruction{
+  width: 60%;
+  text-align: right;
+}
+.show-width{
+  width:100%;
+}
 </style>
+
+<style lang="scss">
+.tooltip-width {
+  max-width: 300px;
+}
+</style>

+ 13 - 9
src/views/ppt_manage/newVersion/components/formatEl/SheetEl.vue

@@ -52,15 +52,16 @@
       @click.stop="delChart(position)"
       v-if="isBtnShow"
     ></div>
-  <div class="chart-source">
-    <span
-      v-if="sheetSourceFrom && sheetSourceFrom.isShow"
-      :style="`
-      color: ${sheetSourceFrom.isShow ? sheetSourceFrom.color : '#999'};
-      font-size: ${ sheetSourceFrom.fontSize }px;
-    `"
-    ><!-- 来源 -->{{$t('ETable.Common.source')}}:{{ sheetSourceFrom.text}}</span>
-  </div>
+  <el-tooltip v-if="sheetSourceFrom && sheetSourceFrom.isShow" popper-class="tooltip-width" :offset="50" effect="dark" :content="sheetSourceFrom.text" placement="top-start">
+    <div class="chart-source">
+      <span
+        :style="`
+        color: ${sheetSourceFrom.isShow ? sheetSourceFrom.color : '#999'};
+        font-size: ${ sheetSourceFrom.fontSize }px;
+      `"
+      ><!-- 来源 -->{{$t('ETable.Common.source')}}:{{ sheetSourceFrom.text}}</span>
+    </div>
+  </el-tooltip>
 </div>
   
 </template>
@@ -124,5 +125,8 @@ export default {
   width: 95%;
   position: absolute;
   left: 2%;
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
 }
 </style>

+ 227 - 0
src/views/ppt_manage/newVersion/components/layer/VersionRecord.vue

@@ -0,0 +1,227 @@
+<template>
+  <div class="statistic-analysis-wrap">
+      <div class="top-box">
+          <div class="right">
+            版本记录
+          </div>
+          <div class="left">
+              <div class="search-box">
+                  <el-switch
+                    v-model="OnlyMine"
+                    @change="handleChangeIsOnlyMine"
+                    active-text="仅显示我保存的版本">
+                  </el-switch>
+              </div>
+          </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.Id"  @mouseenter="showOperation(item.Id)"
+              @mouseleave="hideOperation">
+              <div class="item-img">
+                <img src="~@/assets/img/version_record.png"/>
+              </div>
+                  <div class="top">
+                    <el-tooltip class="item" effect="light" :content="item.Title" placement="top">
+                      <div class="title">{{ item.Title }}</div>
+                    </el-tooltip>
+                    <div class="time">{{ item.CreateTime }}</div>
+                  </div>
+                  <div class="bottom">
+                    <div class="name">{{item.AdminRealName}}</div>
+                    <div class="operation" v-show="item.showOperations">
+                      <span @click="preview(item.Id)">预览</span>
+                      <span @click="$emit('handleRestore', item.Id)">恢复</span>
+                      <span class="delete" @click="deleteVersionRecord(item.Id)">删除</span>
+                    </div>
+                  </div>
+              </div>
+              <tableNoData :text="$t('Table.prompt_slogan')" style="width: 100%;" size="mini" v-if="list.length===0&&finished"/>
+          </div>
+      </div>
+  </div>
+</template>
+
+<script>
+import {pptInterface} from '@/api/api.js';
+export default {
+  data() {
+      return {
+          list:[],
+          page:1,
+          pageSize:10,
+          finished:false,
+          loading:false,
+          OnlyMine:false,      
+      }
+  },
+  created(){
+      this.getSandBoxList()
+  },
+  methods: {
+      /* 搜索版本记录分页 */
+      async getSandBoxList() {
+        const {id} = this.$route.query
+          let params = {
+              CurrentIndex: this.page,
+              PageSize: this.pageSize,
+              PptId:id,
+              IsShowMe: this.OnlyMine,
+          };
+          this.loading=true
+          let res = await pptInterface.getPptHistoryList(params);
+          this.loading=false
+          if (res.Ret !== 200) return;
+          const arr = (res.Data.List || []).map(item => ({
+            ...item,
+            showOperations: false, // 初始时隐藏操作栏
+          }));
+          this.list =
+              this.page === 1
+              ? arr
+              : [...this.list, ...arr];
+          this.finished =  res.Data.Paging.IsEnd;
+      },
+      // 是否仅显示我保存的版本
+      handleChangeIsOnlyMine(val) {
+          this.page = 1;
+          this.list = [];
+          this.getSandBoxList();
+      },
+      handleLoadMore(){
+          if(this.finished||this.loading) return
+          this.page++
+          this.getSandBoxList()
+      },
+      // 预览
+      preview(id){
+        // this.$router.push({path:'/pptpublish', query:{id, isVersionRecord:'true'}})
+        let { href } = this.$router.resolve({ 
+          path: '/pptpublish',
+          query:{
+            id,
+            isVersionRecord:'true'
+          }
+        });
+        window.open(href, '_blank');
+      },
+      // 删除弹窗
+      deleteVersionRecord(Id){
+          this.$confirm('删除后不可恢复,是否确认删除该版本?', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          }).then(() => {
+              this.deleteItem(Id)
+          }).catch(() => {
+          });
+      },
+      deleteItem(Id) {
+          pptInterface.getPptHistoryDel({
+              Id
+          }).then((res) => {
+              if(res.Ret !== 200) return
+              this.$message.success('删除成功!');
+              this.handleChangeIsOnlyMine()
+          });
+      },
+      showOperation(itemId) {
+        const item = this.list.find(i => i.Id === itemId);
+        if (item) {
+          this.$set(item, 'showOperations', true); // 使用 $set 以确保响应性
+        }
+      },
+      hideOperation() {
+        this.list.forEach(item => {
+          this.$set(item, 'showOperations', false); // 隐藏所有操作栏
+        });
+      },
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+  box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+  margin-top: 10px;
+  border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+  background: #FFF;
+  .top-box{
+      padding: 20px 20px 0 20px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+  }
+  .main-box{
+      padding: 20px;
+      height: calc(100vh - 340px);
+      border-radius: 4px;
+      display: flex;
+      flex-direction: column;
+      .list-wrap{
+          flex: 1;
+          overflow-y: auto;
+          // display: flex;
+          // flex-wrap: wrap;
+          gap: 0 20px;
+
+      }
+  }
+}
+.chart-item {
+  position: relative;
+  width: 100%;
+  max-height: 100px;
+  margin: 10px 0;
+  padding: 10px;
+  border-radius: 10px;
+  font-size: 14px;
+  text-align: center;
+  padding-left: 20px;
+  .item-img {
+    position: absolute;
+    top: 10px;
+    left: 0;
+    width: 8px;
+    height: 54px;
+    img {
+      width: 8px;
+      height: 54px;
+    }
+  }
+  .top {
+    display: flex;
+    justify-content: space-between;
+    .title {
+      max-width: 100px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      line-height: 20px;
+      font-size: 16px;
+      color: #333333;
+    }
+    .time {
+      line-height: 20px;
+      color: #666666;
+    }
+  }
+  .bottom {
+    margin-top: 10px;
+    display: flex;
+    justify-content: space-between;
+    .name {
+      color: #333333;
+    }
+    .operation {
+      cursor: pointer;
+      color: #0052D9;
+      .delete {
+        color: #D54941;
+      }
+    }
+  }
+}
+</style>

+ 242 - 0
src/views/ppt_manage/newVersion/components/selectImage.vue

@@ -0,0 +1,242 @@
+<template>
+    <div class="select-image">
+        <el-dialog :visible.sync="showDialog" :title="titleObj[imgType]" :close-on-click-modal="false"
+            :modal-append-to-body="false" @close="cancelHandle" custom-class="select-image-dialog" center width="820px"
+            v-dialogDrag>
+            <el-input v-model="keyword"
+                :placeholder="$t('OnlineExcelPage.please_input') + inputName[imgType] + $t('ETable.BalanceSheetTable.name')"
+                clearable style="width:200px;" @input="handleSearch"></el-input>
+            <div class="image-list">
+                <div class="image-item" v-for="item in list" :key="item.ImageConfId">
+                    <div class="img-box">
+                        <div class="opt-box">
+                            <div class="item full-fix" @click="handleShowImgFull(item)">
+                                <img src="~@/assets/img/icons/fullsreen.png" alt="">
+                            </div>
+                            <div class="radio-fix">
+                                <el-radio size="medium" v-model="momentChooseId" @change="changeRadio"
+                                    :label="item.ImageConfId"></el-radio>
+                            </div>
+                        </div>
+                        <img class="img" :src="item.Url" alt="">
+                    </div>
+                    <p class="name">{{ item.ImgName || item.ImageName }}</p>
+                </div>
+            </div>
+            <div style="margin-top: 20px;display: flex;justify-content:flex-end;padding-right: 40px;">
+                <el-pagination  @current-change="handleCurrentChange"
+                    :current-page="page" :page-size="pageSize" layout="total, prev, pager, next, jumper" :total="total">
+                </el-pagination>
+            </div>
+            <div style="text-align:center;padding: 30px 0;margin-top: 60px;">
+                <el-button style="width:120px;" @click="cancelHandle()">{{ $t('Dialog.cancel_btn') }}</el-button>
+                <el-button type="primary" style="margin-left:20px;width:120px;" @click="handleSave">{{
+                    $t('Dialog.confirm_save_btn') }}</el-button>
+            </div>
+            <el-image-viewer :zIndex="9999" v-if="showPptViewer"
+                :on-close="() => { this.picShowList = []; this.showPptViewer = false }" :url-list="picShowList" />
+        </el-dialog>
+    </div>
+</template>
+<script>
+import ElImageViewer from 'element-ui/packages/image/src/image-viewer';
+import { apiSmartReport } from '@/api/modules/smartReport'
+export default {
+    components: { ElImageViewer },
+    props: {
+    },
+    data() {
+        return {
+            momentChooseId: '',
+            momentChooseUrl: '',
+            total: 0,
+            list: [],
+            pageSize: 8,
+            page: 1,
+            keyword: '',
+            showPptViewer: false,
+            picShowList: [],
+            imgType: 1,
+            showDialog: false,
+            inputName: {
+                1: this.$t('SystemManage.BaseConfig.ppt_type01'),
+                2: this.$t('SystemManage.BaseConfig.ppt_type02'),
+                3: this.$t('SystemManage.BaseConfig.ppt_type03')
+            },
+            titleObj: {
+                1: this.$t('Slides.more_cover_page'),
+                2: this.$t('Slides.select_ground_page'),
+                3: this.$t('Slides.select_back_page')
+            }
+        }
+    },
+    mounted() {
+    },
+    methods: {
+        handleShowImgFull(e) {
+            console.log(e);
+            this.picShowList = [e.Url]
+            this.showPptViewer = true
+        },
+        handleCurrentChange(val) {
+            this.page = val
+            this.getImgList()
+        },
+        // 保存
+        handleSave() {
+            const obj = {
+                url: this.momentChooseUrl,
+                type: this.imgType,
+                id: this.momentChooseId
+            }
+            this.cancelHandle()
+            this.$emit('saveChoose', obj)
+        },
+        // 选择图片
+        changeRadio(val) {
+            const index = this.list.findIndex(el => el.ImageConfId == val)
+            if (index > -1) {
+                this.momentChooseUrl = this.list[index].Url
+            }
+        },
+        //资源库列表
+        getImgList() {
+            apiSmartReport.pptMaterialList({
+                CurrentIndex: this.page,
+                PageSize: this.pageSize,
+                ImageType: this.imgType,
+                ImageName: this.keyword,
+                ConfType: 1
+            }).then(res => {
+                this.list = res.Data ? res.Data.List : []
+                this.total = res.Data ? res.Data.Paging.Totals : 0
+                if (!this.momentChooseId) {
+                    if (this.list.length) {
+                        this.momentChooseId = this.list[0].ImageConfId
+                        this.momentChooseUrl = this.list[0].Url
+                    }
+                }
+            })
+        },
+        // 搜索图片
+        handleSearch() {
+            this.page = 1
+            this.getImgList()
+        },
+        // 打开弹框
+        showHandle(type, id, url) {
+            this.showDialog = true
+            this.momentChoose = ''
+            this.momentChooseUrl = ''
+            this.imgType = type
+            this.keyword = ''
+            this.momentChooseId = id
+            this.momentChooseUrl = url
+            this.handleSearch()
+        },
+        // 关闭弹窗
+        cancelHandle() {
+            this.showDialog = false
+        }
+    }
+}
+</script>
+
+<style lang="scss">
+.select-image-dialog {
+    .el-dialog__body {
+        padding: 40px 60px !important;
+    }
+
+    .image-list {
+        margin-top: 20px;
+        display: flex;
+        flex-wrap: wrap;
+        gap: 20px;
+
+        .image-item {
+            width: 160px;
+
+            .img-box {
+                position: relative;
+                cursor: pointer;
+                width: 160px;
+
+                .img {
+                    display: block;
+                    width: 100%;
+                    height: 160px;
+                    background-color: var(--gary-gy-3-disabled, #EBEFF6);
+                    object-fit: contain !important;
+                    box-sizing: border-box;
+
+                    &:hover {
+                        border: 1px solid #3375e1;
+                    }
+                }
+
+                .opt-box {
+                    position: absolute;
+                    z-index: 5;
+                    width: 100%;
+                    height: 100%;
+
+                    .item {
+                        width: 24px;
+                        height: 24px;
+                        display: flex;
+                        align-items: center;
+                        justify-content: center;
+                        background-color: #fff;
+                        border-radius: 50%;
+                        margin-left: 10px;
+
+                        img {
+                            width: 16px;
+                            height: 16px;
+                        }
+                    }
+
+                    .full-fix {
+                        position: absolute;
+                        top: 12px;
+                        right: 12px;
+                    }
+
+                    .radio-fix {
+                        position: absolute;
+                        top: 12px;
+                        left: 12px;
+                    }
+                }
+
+                &:hover {
+                    .opt-box {
+                        display: flex;
+                    }
+
+                    .select-box {
+                        display: block;
+                    }
+                }
+            }
+
+            .name {
+                padding-top: 5px;
+                display: -webkit-box;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                -webkit-line-clamp: 2;
+                line-break: anywhere;
+                -webkit-box-orient: vertical;
+            }
+        }
+    }
+
+    .el-radio {
+        .el-radio__label {
+            display: none;
+        }
+    }
+}
+</style>

+ 117 - 17
src/views/ppt_manage/newVersion/pptEditor.vue

@@ -1,11 +1,15 @@
 <template>
   <div class="page-wrap">
     <div class="index-wrap ppt-page-wrap flex-column">
-        <div class="cover-wrap" @click="openChooseCover">
-            <div class="cover" :style="`background: no-repeat center/cover url(${firstPage.BackgroundImg||''});background-color:#F2F6FA;background-size:100% 100%;`">
+        <div class="cover-wrap">
+            <div class="flex-align">
+              <p class="hint-text" @click="openSelectImage(2,firstPage.CurrentBackgroundImgId,firstPage.CurrentBackgroundImg)">{{$t('Slides.select_ground_page')}}</p>
+              <p class="hint-text" style="margin-left:37px" @click="openSelectImage(3,firstPage.BackCoverImgId,firstPage.BackCoverImg)">{{$t('Slides.select_back_page')}}</p>
+            </div>
+            <div class="flex-align" style="margin:8px 0"><p class="hint-text"  @click="openChooseCover">{{$t('Slides.select_cover_page')}}</p></div>
+            <div class="cover" @click="openChooseCover" :style="`background: no-repeat center/cover url(${firstPage.BackgroundImg||''});background-color:#F2F6FA;background-size:100% 100%;`">
                 <img src="~@/assets/img/ppt_m/add_first.png" />
             </div>
-            <p class="hint-text">{{$t('Slides.select_cover_page')}}</p>
         </div>
         <div class="hint-box"><div class="hint"  @click="showHint"><span class="el-icon-info" style="margin-right:5px;"></span>{{$t('Slides.operating_instructions')}}</div></div>
         <div style="display:flex;justify-content: space-between;">
@@ -160,10 +164,11 @@
                  type="primary" @click="handlePublish">{{ result.ReportSource===1?'去发布':'去提交' }}</el-button>
                 <el-button @click="handleSave('save')">{{$t('Slides.operations_save')}}</el-button>
                 <el-button type="text" @click="handleChangeEditModal"><i class="el-icon-sort" style="transform: rotate(90deg);margin-right:5px;"></i>{{isEditLayer? $t('Slides.ppt_edit_btn'):$t('Slides.layer_editing')}}</el-button>
+                <el-button type="text" v-permission="permissionBtn.pptPermission.ppt_history" @click="handleVersionHistory"><i class="el-icon-time" style="margin-right:5px;"></i>{{$t('Slides.version_history')}}</el-button>
             </div>
-            <div class="richtext-tool"></div>
+            <div class="richtext-tool" v-if="!isVersionHistory"></div>
             <!-- 防止el-tabs未渲染时触发scrollToActiveTab 报错,v-if改为v-show-->
-            <div class="addppt-right-box" v-show="!isEditLayer&&!isEditTitle">
+            <div class="addppt-right-box" v-show="!isEditLayer&&!isEditTitle && !isVersionHistory">
               <el-tabs v-model="tabsactive">
                 <el-tab-pane :label="tab.label" :name="tab.val" v-for="tab in panelTabs" :key="tab.val"></el-tab-pane>
               </el-tabs>
@@ -229,7 +234,7 @@
               </div>
             </div>
             <!-- 图层编辑 -->
-            <div class="layer-edit-box" v-if="isEditLayer">
+            <div class="layer-edit-box" v-if="isEditLayer && !isVersionHistory">
               	<el-collapse v-model="activeNames" class="tool-list">
                   <el-collapse-item :title="$t('Slides.layer_element')" name="el">
                     <div class="el-wrap">
@@ -278,11 +283,17 @@
                     @textChange="handleTextChange"
                     @applyToAll="changeSettingAll"/>
             </div>
+            <!-- 历史记录编辑 -->
+             <div class="history-edit-box" v-if="isVersionHistory">
+                <VersionRecord ref="version" :PptId="PptId" @handleRestore="handleRestore"/>
+             </div>
           </div>
     </div>
 
     <!-- 选择封面弹窗 -->
-    <ChooseCoverNew 
+    <ChooseCoverNew
+        ref="ChooseCoverNewRef"
+        v-if="isShowChooseCover" 
         :isShowChooseCover="isShowChooseCover"
         :firstPage="firstPage"
         :pptCoverList="pptCoverList"
@@ -290,6 +301,7 @@
         :CoverContent="CoverContent"
         @saveCover="saveCover2"
         @close="isShowChooseCover=false"
+        @chooseMoreCover="coverChooseImage()"
     />
     <!-- 批量删除弹窗 -->
     <delete-page-dialog 
@@ -321,6 +333,7 @@
       @cancel="addMyChartShow = false"
       @addSuccess="addChartToGallery"
     />
+    <selectImage @saveChoose='saveChooseImage' ref="selectImageRef"/>
   </div>
 </template>
 
@@ -347,6 +360,7 @@ import {pptInterface} from '@/api/api.js';
 import * as sheetInterface from '@/api/modules/sheetApi.js';
 import ShapePreview from './components/layer/shapePreview.vue';
 import LayerEditTool from './components/layer/layerEditTool.vue';
+import VersionRecord from './components/layer/VersionRecord.vue';
 import DeletePageDialog from './components/editor/DeletePageDialog.vue';
 import ChangeFormatDialog from './components/editor/ChangeFormatDialog.vue';
 import InsertPageDialog from './components/editor/InsertPageDialog.vue';
@@ -356,6 +370,8 @@ import ContextMenu from './components/ContextMenu.vue';
 import InsertSemantics from './components/editor/InsertSemantics.vue';
 import ChooseCoverNew from './components/editor/ChooseCoverNew.vue';
 import TitleEditorTool from './components/editor/TitleEditorTool';
+import selectImage from './components/selectImage.vue';
+import { apiSmartReport } from '@/api/modules/smartReport'
 export default {
   mixins:[pptmixin,//ppt页面共同逻辑
           mixins,//图表加载逻辑
@@ -365,7 +381,7 @@ export default {
   components: {
     IndexItem, ChooseCover, AddFormat, ShapePreview,
     LayerEditTool, DeletePageDialog, ChangeFormatDialog, InsertPageDialog, addMyClassifyDia, InsertCharts, ContextMenu, InsertSemantics,
-    ChooseCoverNew,TitleEditorTool
+    ChooseCoverNew, TitleEditorTool,selectImage, VersionRecord
 },
   data() {
     return {
@@ -423,7 +439,8 @@ export default {
         search_have_more: true,
 
         chart_source: 1,//图表来源 1 eta 2 商品价格
-        isShowMe: false
+        isShowMe: false,
+        isVersionHistory: false,//是否显示版本历史
     };
   },
   computed:{
@@ -508,7 +525,7 @@ export default {
         i.isUpdating = false
       })
       this.dataLoading.close();
-      $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
+      // $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
       //开启自动保存
       this.autoSave()
     },
@@ -526,6 +543,9 @@ export default {
           this.ReportId=ReportId
           this.CoverContent = this.result.CoverContent
           this.titleSetting = TitleSetting||null
+          if(this.firstPage.CurrentBackgroundImg){
+            $('.ppt-item').css('background-image',`url(${this.firstPage.CurrentBackgroundImg})`);
+          }
           /* //开启自动保存
           this.autoSave() */
         }else{
@@ -539,9 +559,58 @@ export default {
       }
       this.currentIndex = 0
     },
+    // 选择图片保存
+    saveChooseImage(item){
+        console.log(item)
+        const key={
+            1:'BackgroundImg',
+            2:'CurrentBackgroundImg',
+            3:'BackCoverImg'
+        }
+        const idKey={
+            1:'BackgroundImgId',
+            2:'CurrentBackgroundImgId',
+            3:'BackCoverImgId'
+        }
+        if(item.type==1){
+            const searchIndex = this.pptCoverList.findIndex(i=>i.Url===item.url)
+            //如果基本配置-封面图,没有当前ppt的封面图,则默认第一个
+            if(searchIndex>-1){
+                this.$refs.ChooseCoverNewRef.pageData.BackgroundImg = item.url
+                this.$refs.ChooseCoverNewRef.pageData.BackgroundImgId = item.id
+                this.$refs.ChooseCoverNewRef.choosedIndex=searchIndex
+            }
+        }else{
+          this.$set(this.firstPage,key[item.type],item.url)
+          this.$set(this.firstPage,idKey[item.type],item.id)
+          if(item.type==2){
+              $('.ppt-item').css('background-image',`url(${item.url})`);
+          }
+        }
+    },
+    // 选择封面弹框选择更多模板
+    coverChooseImage(){
+        this.openSelectImage(1,this.$refs.ChooseCoverNewRef.pageData.BackgroundImgId,this.$refs.ChooseCoverNewRef.pageData.BackgroundImg)
+    },
+    // 打开选择背景图、封底图、封面图
+    openSelectImage(type,id,url){
+        this.$refs.selectImageRef.showHandle(type,id,url)
+    },
     //打开选择封面页弹窗
     openChooseCover(){
-        this.isShowChooseCover = true
+        apiSmartReport.pptMaterialList({
+            CurrentIndex: 1,
+            PageSize: 1000,
+            ImageType: 1,
+            ImageName: '',
+            ConfType: 1
+        }).then(res => {
+            this.pptCoverList=res.Data ? res.Data.List : []
+            this.isShowChooseCover = true
+            this.$nextTick(()=>{
+              this.$refs.ChooseCoverNewRef.showDialog()
+            })
+        })
     },
     //关闭选择封面页弹窗
     closeChooseCover(){
@@ -778,10 +847,12 @@ export default {
           this.activeLayerEl = {}
           
           this.isEditTitle = false
+          this.isVersionHistory = false
         }
         //点击当前页时,退出标题编辑模式
         if(this.currentItem&&this.currentItem.id===id){
             this.isEditTitle = false
+            this.isVersionHistory = false
             return 
         }
         this.pageList.map((item,index)=>{
@@ -1032,6 +1103,28 @@ export default {
       el.push(temp);
       return el;
     },
+    // 版本记录列表
+    handleVersionHistory(item) {
+      this.isEditLayer = false
+      this.isVersionHistory = true;
+    },
+    // 
+    handleRestore(Id) {
+      this.$confirm('确认将报告恢复到该版本吗?', '提示', {
+          confirmButtonText: '确定',
+          cancelButtonText: '取消',
+          type: 'warning'
+      }).then(() => {
+        this.reportHistoryRevert(Id)
+      }).catch(() => {
+      });
+    },
+    async reportHistoryRevert(Id) {
+      let res = await pptInterface.getPptHistoryRevert({Id});
+      if (res.Ret !== 200) return;
+      this.$message.success('恢复成功!');
+      this.init()
+    },
     //更新ppt页元素(数据)
     refleshElements(els){
         this.currentItem.elements = els;
@@ -1052,15 +1145,18 @@ export default {
         return checkResult
       }
       let Content = JSON.stringify(this.pageList)
-      const {Title,ReportType,PptDate,BackgroundImg,BackIndex} = this.firstPage
+      const {Title,ReportType,PptDate,BackgroundImg,BackIndex,CurrentBackgroundImg,BackCoverImg, BackCoverImgId,BackgroundImgId,CurrentBackgroundImgId} = this.firstPage
       const FirstPage = {
-        Title,ReportType,PptDate,BackIndex,
+        Title,ReportType,PptDate,BackIndex,BackCoverImg,CurrentBackgroundImg,BackCoverImgId,BackgroundImgId,CurrentBackgroundImgId,
         ImgUrl:BackgroundImg,
         TemplateType:BackIndex+1
       }
       this.isSaved = true
       if(this.$route.query.id||this.pptId){
         await this.editPPT(FirstPage,Content,type)
+        if (this.isVersionHistory) {
+          this.$refs.version.handleChangeIsOnlyMine() // 刷新版本列表
+        }
       }else{
         // await this.addPPT(FirstPage,Content)
       }
@@ -1113,9 +1209,9 @@ export default {
         //如果当前在刷新图表,则不进行自动保存
         if(this.refreshBtnLoading) return
         const ppt_id = this.$route.query.id||this.pptId
-        const {Title,ReportType,PptDate,BackgroundImg,BackIndex} = this.firstPage
+        const {Title,ReportType,PptDate,BackgroundImg,BackIndex,CurrentBackgroundImg,BackCoverImg,BackCoverImgId,BackgroundImgId,CurrentBackgroundImgId} = this.firstPage
         const FirstPage = {
-          Title,ReportType,PptDate,BackIndex,
+          Title,ReportType,PptDate,BackIndex,CurrentBackgroundImg,BackCoverImg,CurrentBackgroundImg,BackCoverImgId,BackgroundImgId,CurrentBackgroundImgId,
           ImgUrl:BackgroundImg,
           TemplateType:BackIndex+1
         }
@@ -1324,7 +1420,7 @@ export default {
   },
   updated(){
     $('.ppt-item').css('height',$('.ppt-item').width()*0.7);
-    $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
+    $('.ppt-item').css('background-image',`url(${this.firstPage.CurrentBackgroundImg})`);
     window.onresize = ()=>{
       $('.ppt-item').css('height',$('.ppt-item').width()*0.7);
     }
@@ -1432,7 +1528,7 @@ $titleColor:#333333;
                 .ppt-item {
                     //padding 两边 40 减掉边框两边 8 max-width:100% - 32px
                     width:calc(100% - 64px);
-                    background: url('~@/assets/img/pptnextimg.png') no-repeat top;
+                    background: transparent;
                     background-size: 100% 100%;
                     /* margin-bottom: 30px; */
                     position: relative;
@@ -1610,5 +1706,9 @@ $titleColor:#333333;
             }
        }
     }
+    .flex-align{
+      display:flex;
+      align-items: center;
+    }
 }
 </style>

+ 7 - 7
src/views/ppt_manage/newVersion/pptPresent.vue

@@ -45,7 +45,7 @@
             </div>
             <!-- 封底 -->
             <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1" style="background-size:20%;">
-              <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
+              <img :src="coverInfo.page.BackCoverImg" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
             </div>
             <!-- PPT内容 -->
               <div class="ppt-item" v-else>
@@ -113,7 +113,7 @@
             </div>
             <!-- 封底 -->
             <div class="ppt-item" id="back" v-else-if="currentIndex===pageList.length+1" style="background-size:20%;">
-              <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
+              <img :src="coverInfo.page.BackCoverImg" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
             </div>
             <!-- PPT内容 -->
               <div class="ppt-item" v-else>
@@ -251,7 +251,7 @@ export default {
         return this.LayoutType===2?2:3
     },
     isShowBack(){
-        return Boolean(this.pptBackImage)
+        return Boolean(this.coverInfo.page.BackCoverImg)
     },
     pptSlidePages(){
       let str = this.$i18n.locale == 'zh'? 
@@ -291,7 +291,7 @@ export default {
           $('.editor-content').css('transform',`scale(${this.contentScale})`)
         }
         this.changeLayersSize()
-        $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
+        $('.ppt-item').css('background-image',`url(${this.coverInfo.page.CurrentBackgroundImg})`);
       })
     },
     async init(){
@@ -323,7 +323,7 @@ export default {
         this.sheetListHandle(sheetElements);
       }
       this.currentKey = 1
-      this.pptBgImage&&$('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
+      this.coverInfo.page.CurrentBackgroundImg&&$('.ppt-item').css('background-image',`url(${this.coverInfo.page.CurrentBackgroundImg})`);
       this.dataLoading.close();
     },
     //根据id获取ppt数据
@@ -575,7 +575,7 @@ export default {
           $('.fullscreen .ppt-wrap').css('width','1100px')
           $('.ppt-item').css('transform',`scale(1)`)
           this.changeCurrentItem(this.currentItem)
-          $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
+          $('.ppt-item').css('background-image',`url(${this.coverInfo.page.CurrentBackgroundImg})`);
         })
       }else{
         this.$nextTick(()=>{
@@ -875,7 +875,7 @@ $titleColor:#333333;
     .ppt-item{
       width: 100%;
       height: 100%;
-      background: url('~@/assets/img/pptnextimg.png') no-repeat top;
+      background: transparent;
       background-size: 100% 100%;
       position:relative;
       border: 4px solid transparent;

+ 11 - 10
src/views/ppt_manage/newVersion/pptPublish.vue

@@ -1,6 +1,6 @@
 <template>
   <div class="publish-page-wrap page-wrap">
-      <div class="pub-btn-list">
+      <div class="pub-btn-list" v-if="this.$route.query.isVersionRecord !== 'true'">
         <el-button  type="primary" plain style="width:182px;height:40px;" @click="$router.push({path:'/pptlist'})">{{$t('Slides.return_to_list')}}</el-button>
 
         <!-- 下载配置 -->
@@ -32,7 +32,7 @@
           <!-- 内容 -->
           <div class="ppt-item" v-for="(item,index) in pageList" :key="item.id">
             <!-- 自定义标题 -->
-            <div class="custom-title-wrap content" 
+            <div class="custom-title-wrap content"
                 :style="item.titleDetail?{
                     left:(item.titleDetail.baseLeft||90)*contentScale+'px',
                     top:(item.titleDetail.baseTop||40.9)*contentScale+'px',
@@ -58,8 +58,8 @@
             </component>
           </div>
           <!-- 封底 -->
-          <div class="ppt-item" id="back" v-if="pptBackImage.length" style="background-size:20%;">
-            <img :src="pptBackImage" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
+          <div class="ppt-item" id="back" v-if="coverInfo.page&&coverInfo.page.BackCoverImg" style="background-size:20%;">
+            <img :src="coverInfo.page.BackCoverImg" class="pptbg" style="width:100%;height:100%;object-fit: fill !important;"/>
           </div>
         </div>
       </template>
@@ -223,7 +223,7 @@ export default {
         this.$store.commit('SET_CHART_INFO_MAP',chartInfoMap)
 
         this.dataLoading.close();
-        $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
+        $('.ppt-item').css('background-image',`url(${this.coverInfo.page.CurrentBackgroundImg})`);
       }
     },
     async getpptData(){
@@ -232,6 +232,7 @@ export default {
         await this.getpptDataById(id)
         const {status} = this.result
         if(status===200){
+          console.log(this.result)
           const {content,FirstPage,ReportId} = this.result
           this.pageList = content
           this.coverInfo.page = FirstPage
@@ -290,8 +291,8 @@ export default {
       //开始计时
       const start = Date.now()
       const SlideMaster = _.cloneDeep(pptSlideMaster) 
-      SlideMaster.objects[1] = {image: {x:0,y:0,w:10,h:7,path: this.isTestLocal?require('@/assets/img/pptnextimg.png'):this.pptBgImage}}
-      let pptx = pptConfigInit(new pptxgen(),this.LayoutType,'ch',SlideMaster,this.isTestLocal?require('@/assets/img/pptnextimg.png'):this.pptBgImage)
+      SlideMaster.objects[1] = {image: {x:0,y:0,w:10,h:7,path: this.isTestLocal?require('@/assets/img/pptnextimg.png'):this.coverInfo.page.CurrentBackgroundImg}}
+      let pptx = pptConfigInit(new pptxgen(),this.LayoutType,'ch',SlideMaster,this.isTestLocal?require('@/assets/img/pptnextimg.png'):this.coverInfo.page.CurrentBackgroundImg)
       //添加封面
       let cover = pptx.addSlide()
       let coverId = 'cover'
@@ -391,7 +392,7 @@ export default {
             })
           }else if(sheetData.list){
             slide.addTable(sheetData.list,{
-              x:x,y:y,w:width,h:height,border:{type:'solid',pt:1}
+              x:x,y:y,w:width,h:height,border:{type:'solid',pt:1},fontSize:this.pptSheetSize
             })
             //追加生成表格底部文字
             this.transBottomInfo(slide,{x,y,width,height},sheetData.otherParams)
@@ -431,7 +432,7 @@ export default {
         }
       }
       //添加封底 如果有
-      if(this.pptBackImage.length){
+      if(this.coverInfo.page&&this.coverInfo.page.BackCoverImg){
         let back = pptx.addSlide()
         let backId = 'back'
         let backImg = $(`#${backId} img`)[0].src
@@ -745,7 +746,7 @@ $titleColor:#333333;
       /* height: 628.594px; */
       background-color: pink;
       margin-bottom: 20px;
-      background: url('~@/assets/img/pptnextimg.png') no-repeat top;
+      background: transparent;
       background-size: 100% 100%;
       position:relative;
       border: 4px solid transparent;

+ 8 - 1
src/views/ppt_manage/newVersion/utils/tinymceSetting.js

@@ -23,8 +23,9 @@ export const setting = {
     setup:function(editor){
         editor.on('ExecCommand',function(evt) {
             let cmd = evt.command; 
+            console.log(cmd)
             //设置ul/ol li的字体大小,颜色
-            if (cmd === 'FontSize' || cmd === 'FontName' /* || cmd === 'mceApplyTextcolor' */) {
+            if (cmd === 'FontSize' || cmd === 'FontName'  || cmd === 'mceApplyTextcolor' ) {
                 let val = evt.value; 
                 let node = evt.target.selection.getNode(); 
                 let nodeParent = node.parentNode; 
@@ -35,6 +36,9 @@ export const setting = {
                     if (cmd === 'FontName') { 
                         editor.dom.setStyle(nodeParent, 'font-family', val); 
                     } 
+                    if (cmd === 'mceApplyTextcolor') { 
+                        editor.dom.setStyle(nodeParent, 'color', val); 
+                    }
                 } else if (node.nodeName === 'UL' || node.nodeName === 'OL') { 
                     let li = editor.dom.select('li', node); 
                     if (cmd === 'FontSize') { 
@@ -43,6 +47,9 @@ export const setting = {
                     if (cmd === 'FontName') { 
                         editor.dom.setStyle(li, 'font-family', val); 
                     }
+                    if (cmd === 'mceApplyTextcolor') { 
+                        editor.dom.setStyle(li, 'color', val); 
+                    }
                 } 
             }
         });

+ 2 - 0
src/views/ppt_manage/newVersion/utils/untils.js

@@ -188,11 +188,13 @@ export const toTextProps = (json) => {
             }
             if (bulletFlag && styleObj['list-type'] === 'ol') {
               options.bullet = { type: 'number', indent: 20 * 0.75 }
+              options.breakLine=true
               options.paraSpaceBefore = 0.1
               bulletFlag = false
             }
             if (bulletFlag && styleObj['list-type'] === 'ul') {
               options.bullet = { indent: 20 * 0.75 }
+              options.breakLine=true
               options.paraSpaceBefore = 0.1
               bulletFlag = false
             }

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

@@ -12,6 +12,14 @@
               <img src="~@/assets/img/smartReport/back.png" alt="">
               <span>返回列表</span>
           </li>
+          <li 
+            class="action-item" 
+            @click="$emit('handleVersionRecord')"
+            v-permission="permissionBtn.reportManageBtn.reportMange_history"
+            >
+              <img src="~@/assets/img/smartReport/icon01.png" alt="">
+              <span>{{$t('ReportManage.ReportList.version_record')}}</span>
+          </li>
           <li v-if="!reportInfo.ReportChapterId" class="action-item" @click="$emit('openBaseInfo')">
               <img src="~@/assets/img/smartReport/icon01.png" alt="">
               <span>{{$t('ReportManage.ReportList.information_title')}}</span>

+ 233 - 0
src/views/report_manage/reportV2/normalReport/components/VersionRecord.vue

@@ -0,0 +1,233 @@
+<template>
+  <div class="statistic-analysis-wrap">
+      <div class="top-box">
+          <div class="right">
+            版本记录
+          </div>
+          <div class="left">
+              <div class="search-box">
+                  <el-switch
+                    v-model="OnlyMine"
+                    @change="handleChangeIsOnlyMine"
+                    active-text="仅显示我保存的版本">
+                  </el-switch>
+              </div>
+          </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" @mouseenter="showOperation(item.Id)" @mouseleave="hideOperation">
+                <div class="item-img">
+                  <img src="~@/assets/img/version_record.png"/>
+                </div>
+                <div class="top">
+                  <el-tooltip class="item" effect="light" :content="item.Title" placement="top">
+                    <div class="title">{{ item.Title }}</div>
+                  </el-tooltip>
+                  <div class="time">{{ item.CreateTime }}</div>
+                </div>
+                <div class="bottom">
+                  <div class="name">{{item.AdminName}}</div>
+                  <div class="operation" v-show="item.showOperations">
+                    <span @click="preview(item.Id)">预览</span>
+                    <span @click="$emit('handleRestore', item.Id)">恢复</span>
+                    <span class="delete" @click="deleteVersionRecord(item.Id)">删除</span>
+                  </div>
+                </div>
+              </div>
+              <tableNoData :text="$t('Table.prompt_slogan')" style="width: 100%;" size="mini" v-if="list.length===0&&finished"/>
+          </div>
+      </div>
+  </div>
+</template>
+
+<script>
+import { reportV2Interface } from '@/api/modules/reportV2';
+export default {
+  props:{
+    selectChapterId:{
+        type:Number,
+        default:0
+    }
+  },
+  data() {
+      return {
+          list:[],
+          page:1,
+          pageSize:10,
+          finished:false,
+          loading:false,
+          OnlyMine:false,      
+      }
+  },
+  created(){
+      this.getSandBoxList()
+  },
+  methods: {
+      /* 搜索版本记录分页 */
+      async getSandBoxList(word) {
+           this.$route.query.coopType
+          let params = {
+              CurrentIndex: this.page,
+              PageSize: this.pageSize,
+              IsShowMe: this.OnlyMine,
+          };
+          if (this.$route.query.coopType == '1') {
+              params.ReportId = this.$route.query.id;
+          } else {
+              params.ReportChapterId = this.selectChapterId + '';
+          }
+          this.loading=true
+          let res = await reportV2Interface.reportHistoryList(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;
+      },
+      // 是否仅显示我保存的版本
+      handleChangeIsOnlyMine(val) {
+          this.page = 1;
+          this.list = [];
+          this.getSandBoxList();
+      },
+      handleLoadMore(){
+          if(this.finished||this.loading) return
+          this.page++
+          this.getSandBoxList()
+      },
+      // 预览
+      preview(id){
+        let { href } = this.$router.resolve({ 
+            path: '/reportdtlV2',
+            query:{
+                id,
+                isVersionRecord:'true'
+            }
+            
+        });
+        window.open(href, '_blank');
+      },
+      // 删除弹窗
+      deleteVersionRecord(Id){
+          this.$confirm('删除后不可恢复,是否确认删除该版本?', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          }).then(() => {
+              this.deleteItem(Id)
+          }).catch(() => {
+          });
+      },
+      deleteItem(Id) {
+          reportV2Interface.reportHistoryDel({
+              Id
+          }).then((res) => {
+              if(res.Ret !== 200) return
+              this.$message.success('删除成功!');
+              this.handleChangeIsOnlyMine()
+          });
+      },
+      showOperation(itemId) {
+        const item = this.list.find(i => i.Id === itemId);
+        if (item) {
+          this.$set(item, 'showOperations', true); // 使用 $set 以确保响应性
+        }
+      },
+      hideOperation() {
+        this.list.forEach(item => {
+          this.$set(item, 'showOperations', false); // 隐藏所有操作栏
+        });
+      },
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+  box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+  margin-top: 10px;
+  border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+  background: #FFF;
+  .top-box{
+      padding: 20px 20px 0 20px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+  }
+  .main-box{
+      padding: 20px;
+      height: calc(100vh - 180px);
+      border-radius: 4px;
+      display: flex;
+      flex-direction: column;
+      .list-wrap{
+          flex: 1;
+          overflow-y: auto;
+          // display: flex;
+          // flex-wrap: wrap;
+          gap: 0 20px;
+
+      }
+  }
+}
+.chart-item {
+  position: relative;
+  width: 100%;
+  max-height: 100px;
+  margin: 10px 0;
+  padding: 10px;
+  border-radius: 10px;
+  font-size: 14px;
+  text-align: center;
+  padding-left: 20px;
+  .item-img {
+    position: absolute;
+    top: 10px;
+    left: 0;
+    width: 8px;
+    height: 54px;
+    img {
+      width: 8px;
+      height: 54px;
+    }
+  }
+  .top {
+    display: flex;
+    justify-content: space-between;
+    .title {
+      max-width: 250px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      line-height: 20px;
+      font-size: 16px;
+      color: #333333;
+    }
+    .time {
+      line-height: 20px;
+      color: #666666;
+    }
+  }
+  .bottom {
+    margin-top: 10px;
+    display: flex;
+    justify-content: space-between;
+    .name {
+      color: #333333;
+    }
+    .operation {
+      cursor: pointer;
+      color: #0052D9;
+      .delete {
+        color: #D54941;
+      }
+    }
+  }
+}
+</style>

+ 15 - 2
src/views/report_manage/reportV2/normalReport/components/insertContent.vue

@@ -19,7 +19,8 @@
     <ETASandBox v-if="actTab==='etaSandBox'" @insertHtml="item=>{$emit('insertHtml',{item,type:'image'})}"/>
     <!-- 语义分析 -->
     <SemanticAnalysis v-if="actTab==='semanticAnalysis'" @insertHtml="item => {$emit('insertHtml',{item,type:'image'})}"/>
-
+    <!-- 版本记录 -->
+    <VersionRecord v-if="actTab==='versionRecord'" ref="version" :selectChapterId="selectChapterId" @handleRestore="handleRestore"/>
   </div>
 </template>
 <script>
@@ -29,13 +30,17 @@ import StatisticAnalysis from './StatisticAnalysis.vue'
 import ETAPriceChart from './ETAPriceChart.vue'
 import ETASandBox from './ETASandBox.vue'
 import SemanticAnalysis from './SemanticAnalysis.vue'
+import VersionRecord from './VersionRecord.vue'
 export default {
   props: {
     actTab: {
       type: String
+    },
+    selectChapterId: {
+      type: Number
     }
   },
-  components: {ETAChart,ETASheet,StatisticAnalysis,ETAPriceChart,ETASandBox,SemanticAnalysis  },
+  components: {ETAChart,ETASheet,StatisticAnalysis,ETAPriceChart,ETASandBox,SemanticAnalysis,VersionRecord},
   data() {
     return {
     }
@@ -43,6 +48,14 @@ export default {
   methods: {
       handleImportMyChart(list){
           this.$emit('handleImportMyChart',list)
+      },
+      handleRestore(data){
+          this.$emit('handleRestore',data)
+      },
+      getSandBoxList(){
+        if (this.$refs.version) {
+          this.$refs.version.handleChangeIsOnlyMine() // 刷新版本列表
+        }
       }
   }
 }

+ 49 - 12
src/views/report_manage/reportV2/normalReport/editReport.vue

@@ -50,7 +50,8 @@
 						@openBaseInfo="showReportBaseInfo=true"
 						@handleRefreshAllChart="refreshReport"
 						@handlePreviewReport="reportInfo.ReportChapterId?handlePreviewChapter():handlePreviewReport()"
-						@handleSaveContent="reportInfo.ReportChapterId?handleAutoSaveChapter('save'):handleAutoSave('save')"
+						@handleVersionRecord="handleVersionRecord()"
+						@handleSaveContent="reportInfo.ReportChapterId?handleAutoSaveChapter('save'):handleAutoSave('save',true)"
 						@handlePublishOpt="(type) =>{reportInfo.ReportChapterId?handlePublishChapter():handlePublishReport(type)}"
 						@update="()=>{$refs.chapterContRef&&$refs.chapterContRef.getChapterList()}"
 					/>
@@ -73,11 +74,14 @@
 
 						<!-- 可插入内容 -->
 						<insertContent
+							ref="insertContRef"
 							v-show="activeTab"
 							:actTab="activeTab"
+							:selectChapterId="selectChapterId"
 							@slide="activeTab=''"
 							@insertHtml="insertHtml"
 							@handleImportMyChart="handleImportMyChart"
+							@handleRestore="handleRestore"
 						/>
 						
 					</div>
@@ -192,7 +196,7 @@ export default {
 		if(this.reportCoopType===1) {	
 			this.getreportdetail();
 			this.timer = setInterval(() => {
-				this.handleAutoSave();
+				this.handleAutoSave('', false);
 			}, 6000);
 		}
 
@@ -234,13 +238,13 @@ export default {
 			$('.editor-wrapper')[0].scrollTop = 0;
 			if(this.editChapterId) {
 				this.timer = setInterval(() => {
-					this.handleAutoSaveChapter();
+					this.handleAutoSaveChapter('');
 				}, 6000);
 			}
 		},
 
 		/* 章节自动保存 存草稿*/
-		async handleAutoSaveChapter(type='auto') {
+		async handleAutoSaveChapter(type) {
 			
 			if(!this.reportInfo.ReportChapterId||!this.editChapterId) return
 
@@ -256,14 +260,16 @@ export default {
 				const res = await saveChapterReport({
 					ReportChapterId: this.reportInfo.ReportChapterId,
 					// Title: this.reportInfo.Title,
-					Content: $('.fr-element').html()
+					Content: $('.fr-element').html(),
+					IsManualSave: type === '' ? false : true    //是否手动保存
 				})
 				if(res.Ret !== 200) return
 				resolve(true)
-	
 				this.lastsavetime = http.dateFormatter(new Date(), true);
 				type==='save' && this.$message.success(res.Msg);
-
+				if(type !== '')  {
+					this.$refs.insertContRef.getSandBoxList() // 刷新版本列表
+				}
 			})
 		},
 
@@ -365,7 +371,7 @@ export default {
 		},
 
 		// 每十秒自动保存 存草稿
-		handleAutoSave(type='auto') {
+		handleAutoSave(type='auto', IsManualSave) {
 
 			if(!this.autoSaveFlag) return
 			//如果富文本中有未上传完成的图片,去除这个dom
@@ -374,13 +380,16 @@ export default {
 				autosave({
 					ReportId: Number(this.$route.query.id),
 					Content: $('.fr-element').html(),
-					NoChange:this.ischange?0:1
+					NoChange:this.ischange?0:1,
+					IsManualSave
 				}).then((res) => {
 					if (res.Ret === 200) {
 						resolve(true)
-
 						this.lastsavetime = http.dateFormatter(new Date(), true);
 						type==='save' && this.$message.success(res.Msg);
+						if(IsManualSave)  {
+                            this.$refs.insertContRef.getSandBoxList() // 刷新版本列表
+                        }
 					}
 				});
 				this.ischange = false;
@@ -389,7 +398,7 @@ export default {
 
 		/* 报告详情 */
 		async getreportdetail() {
-			
+
 			const res = await reportdetail({ ReportId: parseInt(this.report_id) })
 
 			if (res.Ret !== 200) return
@@ -409,7 +418,7 @@ export default {
 		/* 发布报告 */
 		async handlePublishReport(tp) {
 
-			const saveRes = await this.handleAutoSave('auto');
+			const saveRes = await this.handleAutoSave('auto', true);
 			if(!saveRes) return
 
 			if(tp==='dsfb'){
@@ -567,6 +576,34 @@ export default {
 				
 				this.$store.commit('SET_DYNAMIC_LINK',res.Data)
 		},
+		async handleVersionRecord() {
+			this.showRight=true 
+            this.activeTab = 'versionRecord';
+		},
+		/* 恢复版本 */
+		handleRestore(Id) {
+            this.$confirm('确认将报告恢复到该版本吗?', '提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning'
+            }).then(() => {
+                this.reportHistoryRevert(Id)
+            }).catch(() => {
+            });
+        },
+        /* 恢复版本报告请求 */
+        async reportHistoryRevert(Id) {
+            const res = await reportV2Interface.reportHistoryRevert({Id})
+			if(res.Ret !== 200) return
+			this.$message.success('恢复成功!');
+			if (this.$route.query.coopType == '1') {
+				this.getreportdetail()
+				console.log(44555);
+			} else {
+				this.getChapterDetail()
+			}
+        },
+
 	},
 };
 </script>

+ 24 - 11
src/views/report_manage/reportV2/normalReport/reportdtl.vue

@@ -35,7 +35,7 @@
 			<div v-html="configInfo.Disclaimer"></div>
 		</div>
 
-		<div v-if="linkUrl" style="width:100px;height30px;position:absolute;right:-100px;top:100px;cursor:pointer;">
+		<div v-if="linkUrl" style="width:100px;height:30px;position:absolute;right:-100px;top:100px;cursor:pointer;">
 			<div v-permission="$route.query.fromPage==='en'
                 ?permissionBtn.enReportManageBtn.enReport_reportView_copyWechat
                 :permissionBtn.reportManageBtn.reportManage_reportView_copyWechat"
@@ -58,6 +58,7 @@
 	import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
 	import * as reportEnInterface from '@/api/modules/reportEnApi';
 	import {strategyReportInterence} from '@/api/api.js'
+	import { reportV2Interface } from '@/api/modules/reportV2';
 	import vueQr from 'vue-qr'
 	export default {
 		computed: {
@@ -117,17 +118,19 @@
 				this.isshow=true;
 				return 
 			}
-
-			if(this.$route.query.id||this.reportId) {
-				this.getreportdetail();
-			}else {
-				let reportdtl=sessionStorage.getItem('reportdtl') || false;
-				this.reportInfo=JSON.parse(reportdtl);
-				console.info("reportInfo");
-				console.log(this.reportInfo);
-				this.isshow=true;
+			if(this.$route.query.isVersionRecord === 'true') {
+				this.getReportHistoryDetail()
+			} else {
+				if(this.$route.query.id||this.reportId) {
+					this.getreportdetail();
+				}else {
+					let reportdtl=sessionStorage.getItem('reportdtl') || false;
+					this.reportInfo=JSON.parse(reportdtl);
+					console.info("reportInfo");
+					console.log(this.reportInfo);
+					this.isshow=true;
+				}
 			}
-			
 			this.getConfigSet()
 		},
 		updated(){
@@ -166,6 +169,16 @@
 				this.reportInfo=res.Data;
 				this.isshow=true;
 			},
+
+			// 获取报告详情
+			async getReportHistoryDetail(){
+				const id=this.$route.query.id||this.reportId||0
+				if(!id) return
+				this.$emit("reportStartLoading")
+				const res = await reportV2Interface.reportHistoryDetail({Id:id})
+				this.reportInfo=res.Data;
+				this.isshow=true;
+			},
 			/* 复制链接 */
 			copyHandle() {
 				var clipboard = new this.Clipboard('.copy')

+ 233 - 0
src/views/report_manage/reportV2/smartReport/components/VersionRecord.vue

@@ -0,0 +1,233 @@
+<template>
+  <div class="statistic-analysis-wrap">
+      <div class="top-box">
+          <div class="right">
+            版本记录
+          </div>
+          <div class="left">
+              <div class="search-box">
+                  <el-switch
+                    v-model="OnlyMine"
+                    @change="handleChangeIsOnlyMine"
+                    active-text="仅显示我保存的版本">
+                  </el-switch>
+              </div>
+          </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" @mouseenter="showOperation(item.Id)" @mouseleave="hideOperation">
+                  <div class="item-img">
+                    <img src="~@/assets/img/version_record.png"/>
+                  </div>
+                  <div class="top">
+                    <el-tooltip class="item" effect="light" :content="item.Title" placement="top">
+                      <div class="title">{{ item.Title }}</div>
+                    </el-tooltip>
+                    <!-- <div class="title">{{ item.Title }}</div> -->
+                    <div class="time">{{ item.CreateTime }}</div>
+                  </div>
+                  <div class="bottom">
+                    <div class="name">{{item.AdminName}}</div>
+                    <div class="operation" v-show="item.showOperations">
+                      <span @click="preview(item.Id)">预览</span>
+                      <span @click="$emit('handleRestore', item.Id)">恢复</span>
+                      <span class="delete" @click="deleteVersionRecord(item.Id)">删除</span>
+                    </div>
+                  </div>
+              </div>
+              <tableNoData :text="$t('Table.prompt_slogan')" style="width: 100%;" size="mini" v-if="list.length===0&&finished"/>
+          </div>
+      </div>
+  </div>
+</template>
+
+<script>
+import { reportV2Interface } from '@/api/modules/reportV2';
+export default {
+  props:{
+    selectChapterId:{
+        type:Number,
+        default:0
+    }
+  },
+  data() {
+      return {
+          list:[],
+          page:1,
+          pageSize:10,
+          finished:false,
+          loading:false,
+          OnlyMine:false,      
+      }
+  },
+  created(){
+      this.getSandBoxList()
+  },
+  methods: {
+      /* 搜索版本记录分页 */
+      async getSandBoxList(word) {
+           this.$route.query.coopType
+          let params = {
+              CurrentIndex: this.page,
+              PageSize: this.pageSize,
+              IsShowMe: this.OnlyMine,
+          };
+          if (this.$route.query.coopType == '1') {
+              params.ReportId = this.$route.query.id;
+          } else {
+              params.ReportChapterId = this.selectChapterId + '';
+          }
+          this.loading=true
+          let res = await reportV2Interface.reportHistoryList(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;
+      },
+      // 是否仅显示我保存的版本
+      handleChangeIsOnlyMine(val) {
+          this.page = 1;
+          this.list = [];
+          this.getSandBoxList();
+      },
+      handleLoadMore(){
+          if(this.finished||this.loading) return
+          this.page++
+          this.getSandBoxList()
+      },
+      // 预览
+      preview(id){
+        let { href } = this.$router.resolve({ 
+            path: '/smartReportDetail',
+            query:{
+                id,
+                isVersionRecord:'true'
+            }
+        });
+        window.open(href, '_blank');
+      },
+      // 删除弹窗
+      deleteVersionRecord(Id){
+          this.$confirm('删除后不可恢复,是否确认删除该版本?', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          }).then(() => {
+              this.deleteItem(Id)
+          }).catch(() => {
+          });
+      },
+      deleteItem(Id) {
+          reportV2Interface.reportHistoryDel({
+              Id
+          }).then((res) => {
+              if(res.Ret !== 200) return
+              this.$message.success('删除成功!');
+              this.handleChangeIsOnlyMine()
+          });
+      },
+      showOperation(itemId) {
+        const item = this.list.find(i => i.Id === itemId);
+        if (item) {
+          this.$set(item, 'showOperations', true); // 使用 $set 以确保响应性
+        }
+      },
+      hideOperation() {
+        this.list.forEach(item => {
+          this.$set(item, 'showOperations', false); // 隐藏所有操作栏
+        });
+      },
+  },
+}
+</script>
+
+<style lang="scss" scoped>
+div{
+  box-sizing: border-box;
+}
+.statistic-analysis-wrap{
+  margin-top: 10px;
+  border: 1px solid var(--gary-gy-5-line, #C8CDD9);
+  background: #FFF;
+  .top-box{
+      padding: 20px 20px 0 20px;
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+  }
+  .main-box{
+      padding: 20px;
+      height: calc(100vh - 170px);
+      border-radius: 4px;
+      display: flex;
+      flex-direction: column;
+      .list-wrap{
+          flex: 1;
+          overflow-y: auto;
+          // display: flex;
+          // flex-wrap: wrap;
+          gap: 0 20px;
+
+      }
+  }
+}
+.chart-item {
+  position: relative;
+  width: 100%;
+  max-height: 100px;
+  margin: 10px 0;
+  padding: 10px;
+  border-radius: 10px;
+  font-size: 14px;
+  text-align: center;
+  padding-left: 20px;
+  .item-img {
+    position: absolute;
+    top: 10px;
+    left: 0;
+    width: 8px;
+    height: 54px;
+    img {
+      width: 8px;
+      height: 54px;
+    }
+  }
+  .top {
+    display: flex;
+    justify-content: space-between;
+    .title {
+      max-width: 250px;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      line-height: 20px;
+      font-size: 16px;
+      color: #333333;
+    }
+    .time {
+      line-height: 20px;
+      color: #666666;
+    }
+  }
+  .bottom {
+    margin-top: 10px;
+    display: flex;
+    justify-content: space-between;
+    .name {
+      color: #333333;
+    }
+    .operation {
+      cursor: pointer;
+      color: #0052D9;
+      .delete {
+        color: #D54941;
+      }
+    }
+  }
+}
+</style>

+ 59 - 14
src/views/report_manage/reportV2/smartReport/editReport.vue

@@ -29,7 +29,6 @@
                     <tableNoData :text="$t('Common.no_cont_msg')"/>
                 </div>
 			</template>
-
 			<!-- 章节报告预览 -->
 			<template v-else-if="reportCoopType===2&&selectChapterId&&!editChapterId">
 				<div style="max-height:100vh;overflow-y:auto;">
@@ -49,11 +48,11 @@
                     @openBaseInfo="showReportBaseInfo=true"
                     @handleRefreshAllChart="handleRefreshAllChart"
                     @handlePreviewReport="reportInfo.ReportChapterId?handlePreviewChapter():handlePreviewReport()"
-                    @handleSaveContent="reportInfo.ReportChapterId?handleAutoSaveChapter('save'):handleSaveContent({isAutoSave:false})"
+                    @handleSaveContent="reportInfo.ReportChapterId?handleAutoSaveChapter('save'):handleSaveContent({isAutoSave:false,IsManualSave:true})"
                     @handlePublishOpt="(type) =>{reportInfo.ReportChapterId?handlePublishChapter():handlePublishOpt(type)}"
                     @update="()=>{$refs.chapterContRef&&$refs.chapterContRef.getChapterList()}"
+                    @handleVersionRecord="handleVersionRecord()"
                 />
-                
                 <div class="main-wrap">
                     <div class="report-action-wrap">
                         <ul class="top-type-list">
@@ -176,7 +175,7 @@
                                 :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] }}
+                                    {{ layoutBaseInfo[item.value] }}111
                                 </div>
                             </div>
                         </div>
@@ -186,8 +185,8 @@
                         <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="height: 100%;">
+                        <div :style="rightType !=='versionRecord' ? 'overflow-x:auto;height:calc(100% + 12px);' : 'overflow-x:auto;'">
+                        <div :style="rightType !=='versionRecord' ? 'height: 100%;' : 'height: 100%;'">
                         <TextEdit 
                             v-if="rightType==='text'"
                             :key="activeId"
@@ -215,6 +214,8 @@
                         <ETASandBox v-if="rightType==='etaSandBox'"/>
                         <!-- 语义分析 -->
                         <SemanticAnalysis v-if="rightType==='semanticAnalysis'"/>
+                        <!-- 版本记录 -->
+                        <VersionRecord v-if="rightType==='versionRecord'" ref="version" :selectChapterId="selectChapterId" @handleRestore="handleRestore"/>
                         <!-- 版图资源库 -->
                         <ImgSource v-if="rightType==='imgSource'" @change="handleInsertImgSource" @close="handleCloseRight"/>
                         </div>
@@ -293,6 +294,7 @@ import reportBaseInfo from '../components/reportBaseInfoDia.vue'
 import StatisticAnalysis from './components/StatisticAnalysis.vue'
 import ETAPriceChart from './components/ETAPriceChart.vue'
 import ETASandBox from './components/ETASandBox.vue'
+import VersionRecord from './components/VersionRecord.vue'
 import SemanticAnalysis from './components/SemanticAnalysis.vue'
 import { getUrlParams } from '@/utils/common'
 import reportApproveConfig from "@/mixins/reportApproveConfig.js"
@@ -301,6 +303,7 @@ import editHeader from '../components/reportEditHeader.vue';
 import chapterWrapper from '../components/chapterEditWrapper.vue';
 import smartReportDetail from './reportDetail.vue'
 import { GetQueryString } from '@/utils/common'
+import { reportV2Interface } from '@/api/modules/reportV2';
 export default {
     mixins:[reportApproveConfig],
     name:"smartReportEditV2",
@@ -318,6 +321,7 @@ export default {
         StatisticAnalysis,
         ETAPriceChart,
         ETASandBox,
+        VersionRecord,
         SemanticAnalysis,
         ImgSource,
         editHeader,
@@ -422,6 +426,38 @@ export default {
 			this.getChapterDetail()
 		},
 
+        /* 版本记录 */
+        async handleVersionRecord() {
+            this.showRight=true 
+            this.rightType = 'versionRecord';
+		},
+
+        /* 恢复版本 */
+        handleRestore(Id) {
+            this.$confirm('确认将报告恢复到该版本吗?', '提示', {
+                confirmButtonText: '确定',
+                cancelButtonText: '取消',
+                type: 'warning'
+            }).then(() => {
+                this.reportHistoryRevert(Id)
+            }).catch(() => {
+            });
+        },
+        /* 恢复版本报告请求 */
+        async reportHistoryRevert(Id) {
+            reportV2Interface.reportHistoryRevert({
+                Id
+            }).then((res) => {
+                if(res.Ret !== 200) return
+                this.$message.success('恢复成功!');
+                if (this.$route.query.coopType == '1') {
+                    this.getReportDetail()
+                } else {
+                    this.getChapterDetail()
+                }
+            });
+        },
+
 		/* 获取章节报告详情 */
 		async getChapterDetail() {
             if(!this.selectChapterId) return
@@ -438,14 +474,13 @@ export default {
 			$('.edit-smart-report-page')[0].scrollTop = 0;
 			if(this.editChapterId) {
 				this.timer = setInterval(() => {
-					this.handleAutoSaveChapter();
+					this.handleAutoSaveChapter('');
 				}, 6000);
 			}
 		},
 
 		/* 章节自动保存 存草稿*/
-		async handleAutoSaveChapter(type='auto') {
-			
+		async handleAutoSaveChapter(type) {
 			if(!this.reportInfo.ReportChapterId||!this.editChapterId) return
             if(!document.getElementById('report-html-content')){
                 this.timer && clearInterval(this.timer);
@@ -458,11 +493,14 @@ export default {
                     ReportChapterId: this.reportInfo.ReportChapterId,
                     Content: htmlStr,
                     ContentStruct:this.formatContentListElData(),
+                    IsManualSave: type === '' ? false : true    //是否手动保存
                 })
                 if(res.Ret !== 200) return 
                 resolve(true)
-
                 type==='save' && this.$message.success(res.Msg);
+                if(type !== '' && this.$refs.version)  {
+					this.$refs.version.handleChangeIsOnlyMine() // 刷新版本列表
+				}
             })
 		},
 
@@ -673,7 +711,8 @@ export default {
                 path: '/smartReportDetail',
                 query:{
                     id:this.$route.query.id,
-                    type:'preview'
+                    type:'preview',
+                    isVersionRecord:'false'
                 }
             });
 			window.open(href, '_blank');
@@ -1011,6 +1050,8 @@ export default {
 
         // 获取报告详情
         getReportDetail(){
+            console.log('获取报告详情------------------->');
+            
             const id=this.$route.query.id||0
             if(!id) return
 
@@ -1125,7 +1166,7 @@ export default {
         },1000),
         
         // 自动/存草稿保存内容
-        handleSaveContent({isAutoSave}){
+        handleSaveContent({isAutoSave, IsManualSave}){
             const html=document.getElementById('report-html-content').outerHTML.replace(/contenteditable="true"/g,'contenteditable="false"');
             return new Promise((resolve,reject)=>{
                 const id=this.$route.query.id||0
@@ -1144,6 +1185,7 @@ export default {
                     Content:html,
                     ContentStruct:this.formatContentListElData(),
                     NoChange:this.contentChange?2:1,
+                    IsManualSave,
                     ...imgParams
                 }).then(res=>{
                     if(res.Ret===200){
@@ -1151,6 +1193,9 @@ export default {
                         if(!isAutoSave){
                             this.$message.success(this.$t('MsgPrompt.saved_msg'))
                         }
+                        if(IsManualSave && this.$refs.version)  {
+                            this.$refs.version.handleChangeIsOnlyMine() // 刷新版本列表
+                        }
                     }
                 })
             })
@@ -1160,7 +1205,7 @@ export default {
         async handlePublishOpt(type){
             if(document.getElementById('report-html-content')) { 
                 // 存一次草稿
-                const saveRes=await this.handleSaveContent({isAutoSave:true})
+                const saveRes=await this.handleSaveContent({isAutoSave:true,IsManualSave:true})
                 if(!saveRes) return
             }
 
@@ -1382,7 +1427,7 @@ export default {
         window.addEventListener('message',this.setSheetIframeStyle)
         if(this.reportCoopType===1) {
             this.timer = setInterval(() => {
-                this.handleSaveContent({isAutoSave:true});
+                this.handleSaveContent({isAutoSave:true,IsManualSave:false});
             }, 6000);
         }
     },

+ 41 - 1
src/views/report_manage/reportV2/smartReport/reportDetail.vue

@@ -104,6 +104,7 @@
 <script>
 import {apiSmartReport}  from '@/api/modules/smartReport'
 import {etaBaseConfigInterence} from '@/api/modules/etaBaseConfigApi.js';
+import { reportV2Interface } from '@/api/modules/reportV2';
 import {
 	reportdetail,
 } from '@/api/modules/reportV2';
@@ -166,7 +167,11 @@ export default {
             this.content=this.reportInfo.Content
             return 
         }
-        this.getReportDetail()
+        if(this.$route.query.isVersionRecord === 'true') {
+            this.getReportHistoryDetail()
+        } else {
+            this.getReportDetail()
+        }
         this.getConfigSet()
     },
     methods: {
@@ -215,6 +220,41 @@ export default {
                 }
             })
         },
+        // 获取报告详情
+        async getReportHistoryDetail(){
+            const id=this.$route.query.id||this.reportId||0
+            if(!id) return
+            this.$emit("reportStartLoading")
+            await reportV2Interface.reportHistoryDetail({
+                Id: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['创建时间']=[2,6].includes(this.reportInfo.State)?this.reportInfo.PublishTime:''
+                    if(['preview','previewChapter'].includes(this.$route.query.type)){
+                       this.content=sessionStorage.getItem('smartReportContent')||res.Data.Content;
+                       this.reportInfo.Abstract = this.$route.query.type==='preview'?this.reportInfo.Abstract : ''; 
+                       this.bgColor=this.$route.query.type==='preview'?(sessionStorage.getItem('smartReportContentBg')||res.Data.CanvasColor):''
+                    }else{
+                        this.content=res.Data.Content
+                        this.bgColor=res.Data.CanvasColor
+                    }
+                }else{
+                    this.$emit("reportError")
+                }
+            })
+        },
 
         /* 复制链接 */
 		copyHandle() {

+ 221 - 51
src/views/system_manage/components/smartReportImgSet.vue

@@ -2,11 +2,12 @@
     <div class="smart-report-img-set-page">
         <div class="top-wrap">
             <el-input v-model="keyword" :placeholder="$t('SystemManage.BaseConfig.resource_placeholder01')" clearable style="width:200px;margin-right:20px" @input="handleSearch"></el-input>
-            <el-select :placeholder="$t('SystemManage.BaseConfig.resource_placeholder02')" v-model="type" clearable style="width:200px" @change="handleSearch">
-                <el-option :label="$t('SystemManage.BaseConfig.resource_type01')" :value="1"></el-option>
-                <el-option :label="$t('SystemManage.BaseConfig.resource_type02')" :value="2"></el-option>
+            <el-select  :placeholder="$t('SystemManage.BaseConfig.resource_placeholder02')" v-model="type" clearable style="width:200px" @change="handleSearch">
+                <el-option :label="libraryType==2?$t('SystemManage.BaseConfig.ppt_type01'):$t('SystemManage.BaseConfig.resource_type01')" :value="1"></el-option>
+                <el-option :label="libraryType==2?$t('SystemManage.BaseConfig.ppt_type02'):$t('SystemManage.BaseConfig.resource_type02')" :value="2"></el-option>
+                <el-option v-if="libraryType==2" :label="$t('SystemManage.BaseConfig.ppt_type03')" :value="3"></el-option>
             </el-select>
-            <el-button type="primary" style="float:right" @click="handleShowUploadPop" v-permission="permissionBtn.baseConfigPermission.etaBaseConfig_source_upload">{{$t('SystemManage.BaseConfig.resource_btn04')}}</el-button>
+            <el-button type="primary" style="float:right" @click="handleShowUploadPop" v-if="(libraryType==1&&permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_upload)) || (libraryType==2&&permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_ppt_upload))">{{libraryType==1?$t('SystemManage.BaseConfig.resource_btn04'):$t('SystemManage.BaseConfig.resource_btn01')}}</el-button>
         </div>
 
         <div class="select-status-box" v-if="selectIds.length>0">
@@ -22,24 +23,24 @@
 
 
         <ul class="img-list-wrap">
-            <li class="img-item" v-for="item in list" :key="item.ResourceId">
-                <div :class="['select-box',selectIds.includes(item.ResourceId)?'select-box-active':'']" @click="handleSelectItem(item)"></div>
+            <li class="img-item" v-for="item in list" :key="item.ResourceId || item.ImageConfId">
+                <div :class="['select-box',selectIds.includes(item.ResourceId || item.ImageConfId)?'select-box-active':'']" @click="handleSelectItem(item)"></div>
                 <div class="opt-box">
                     <div class="item" @click="handleShowImgFull(item)">
                         <img src="~@/assets/img/icons/fullsreen.png" alt="">
                     </div>
-                    <el-dropdown @command="handleClickOpt">
+                    <el-dropdown @command="handleClickOpt" v-if="(libraryType==1&&(permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_edit)|| permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_del))) || (libraryType==2&&(permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_ppt_edit) || permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_ppt_del)))">
                     <div class="item">
                         <img src="~@/assets/img/icons/more.png" alt="">
                     </div>
                     <el-dropdown-menu slot="dropdown">
-                        <el-dropdown-item :command="{type:'edit',data:item}">{{$t('Dialog.title_prefix_edit')}}</el-dropdown-item>
-                        <el-dropdown-item :command="{type:'del',data:item}" style="color: #AD352F;">{{$t('Table.delete_btn')}}</el-dropdown-item>
+                        <el-dropdown-item v-if="(libraryType==1&&permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_edit)) || (libraryType==2&&permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_ppt_edit))" :command="{type:'edit',data:item}">{{$t('Dialog.title_prefix_edit')}}</el-dropdown-item>
+                        <el-dropdown-item v-if="(libraryType==1&&permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_del)) || (libraryType==2&&permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_ppt_del))" :command="{type:'del',data:item}" style="color: #AD352F;">{{$t('Table.delete_btn')}}</el-dropdown-item>
                     </el-dropdown-menu>
                     </el-dropdown>
                 </div>
-                <img class="img" :src="item.ImgUrl" alt="">
-                <p class="name">{{item.ImgName}}</p>
+                <img class="img" :src="item.ImgUrl || item.Url" alt="">
+                <p class="name">{{item.ImgName || item.ImageName}}</p>
             </li>
         </ul>
         <tableNoData :text="$t('Table.prompt_slogan')" v-if="list.length===0"/>
@@ -165,7 +166,75 @@
             </el-form>
             
         </el-dialog>
-        <el-image-viewer 
+
+        <!-- ppt上传图片弹窗 -->
+        <el-dialog
+            :visible.sync="uploadImgPpt"
+            :title="ruleForm.ImageConfId?$t('SystemManage.BaseConfig.ppt_btn02'):$t('SystemManage.BaseConfig.resource_btn01')"
+            :close-on-click-modal="false"
+            :append-to-body="true"
+            @close="cancelPpt"
+            custom-class="classify-dialog"
+            center
+            width="550px"
+            v-dialogDrag
+        >
+            <el-form 
+                :model="ruleForm" 
+                :rules="formRules" 
+                ref="ruleForms" 
+                label-width="120px" 
+                class="upload-img-form"
+            >   
+                <el-form-item :label="$t('SystemManage.BaseConfig.resource_label01')" prop="ImageName">
+                    <el-input v-model="ruleForm.ImageName" :placeholder="$t('SystemManage.BaseConfig.resource_placeholder01')"></el-input>
+                </el-form-item>
+                <el-form-item :label="$t('SystemManage.BaseConfig.resource_label02')" prop="ImageType">
+                    <el-radio-group :disabled="ruleForm.ImageConfId" v-model="ruleForm.ImageType">
+                        <el-radio :label="1">{{$t('SystemManage.BaseConfig.ppt_type01')}}</el-radio>
+                        <el-radio :label="2">{{$t('SystemManage.BaseConfig.ppt_type02')}}</el-radio>
+                        <el-radio :label="3">{{$t('SystemManage.BaseConfig.ppt_type03')}}</el-radio>
+                    </el-radio-group>
+                </el-form-item>
+                <el-form-item
+                    :label="$t('SystemManage.BaseConfig.resource_btn01')" 
+                    prop="Url"
+                >
+                    <el-upload
+                        :disabled="ruleForm.ImageConfId" 
+                        action="" 
+                        accept="image/*" 
+                        :http-request="handleUploadImg" 
+                        :show-file-list="false"
+                    >
+                        <div class="upload-box">
+                            <template v-if="!ruleForm.Url">
+                                <i class="el-icon-plus" style="font-size: 24px;"></i>
+                            </template>
+                            <template v-else>
+                                <img class="upload-img" :src="ruleForm.Url" alt="">
+                                <div class="upload-mask">
+                                    <i class="el-icon-zoom-in" @click.stop="handleShowImgPpt()"></i>
+                                    <i class="el-icon-delete" v-if="!ruleForm.ImageConfId" @click.stop="ruleForm.Url=''"></i>
+                                </div>
+                            </template>
+                        </div>
+                    </el-upload>
+                    <p>{{$t('SystemManage.BaseConfig.upload_ppt_suggest')}}</p>
+                </el-form-item>
+                <div style="text-align: center;padding: 30px 0;margin-top: 60px;">
+                    <el-button style="width:120px;" @click="cancelPpt()" >{{$t('Dialog.cancel_btn')}}</el-button>
+                    <el-button type="primary" style="margin-left:20px;width:120px;" @click="handlePptSave">{{$t('Dialog.confirm_save_btn')}}</el-button>
+                </div>
+            </el-form>
+            <el-image-viewer
+                :zIndex="9999"
+                v-if="showPptViewer" 
+                :on-close="()=>{this.picShowList=[];this.showPptViewer = false}" 
+                :url-list="picShowList" 
+            />
+        </el-dialog>
+        <el-image-viewer
             v-if="showViewer" 
             :on-close="()=>{this.picShowList=[];this.showViewer = false}" 
             :url-list="picShowList" 
@@ -181,6 +250,24 @@ import draggable from 'vuedraggable'
 import VueDragResize from 'vue-drag-resize'
 export default {
     components:{ElImageViewer,draggable,VueDragResize},
+    props:{
+        libraryType:{
+            type:Number,
+            default:1
+        }
+    },
+    watch:{
+        libraryType:{
+            handler(newval){
+                this.page = 1;
+                this.keyword=''
+                this.type=''
+                this.list=[]
+                this.getImgList()
+            },
+            deep:true
+        }
+    },
     data() {
         return {
             keyword:'',
@@ -191,6 +278,7 @@ export default {
             total:0,
 
             uploadImgPop:false,
+            uploadImgPpt:false,
             formData:{
                 id:0,
                 name:'',
@@ -198,10 +286,19 @@ export default {
                 imgUrl:'',
                 layout:''
             },
+            ruleForm:{
+                ImageName:'',
+                Url:"",
+                ConfType:1,
+                ImageType:''
+            },
             formRules:{
                 name:[{ required: true, message: this.$t('SystemManage.BaseConfig.resource_placeholder01')||'请输入图片名称', trigger: 'blur' }],
                 type:[{ required: true, message: this.$t('SystemManage.BaseConfig.resource_placeholder02')||'请选择图片类型', trigger: 'change' }],
-                imgUrl:[{ required: true, message: this.$t('SystemManage.BaseConfig.resource_placeholder03')||'请上传图片', trigger: 'change' }]
+                imgUrl:[{ required: true, message: this.$t('SystemManage.BaseConfig.resource_placeholder03')||'请上传图片', trigger: 'change' }],
+                ImageName:[{ required: true, message: this.$t('SystemManage.BaseConfig.resource_placeholder01')||'请输入图片名称', trigger: 'blur' }],
+                ImageType:[{ required: true, message: this.$t('SystemManage.BaseConfig.resource_placeholder02')||'请选择图片类型', trigger: 'change' }],
+                Url:[{ required: true, message: this.$t('SystemManage.BaseConfig.resource_placeholder03')||'请上传图片', trigger: 'change' }]
             },
             step:1,
             steps:[this.$t('SystemManage.BaseConfig.select_layout'),this.$t('SystemManage.BaseConfig.edit_layout')],
@@ -236,6 +333,7 @@ export default {
                             {value:'center',label:this.$t('SystemManage.BaseConfig.style_text_align_center')},
                             {value:'right',label:this.$t('SystemManage.BaseConfig.style_text_align_right')}],
             showViewer:false,
+            showPptViewer:false,
             picShowList:[],
             rigtMenuHideTimer:null,
             delIds:[],//要删除的id集合
@@ -253,19 +351,22 @@ export default {
     },
     methods: {
         handleSelectItem(e){
-            const index=this.selectIds.indexOf(e.ResourceId)
+            const key=this.libraryType==1?'ResourceId':'ImageConfId'
+            console.log(e[key])
+            const index=this.selectIds.indexOf(e[key])
             if(index>-1){
                 this.selectIds.splice(index,1)
             }else{
-                this.selectIds.push(e.ResourceId)
+                this.selectIds.push(e[key])
             }
 
             this.checkAll=this.selectIds.length===this.list.length?true:false
             this.isIndeterminate=this.selectIds.length>0&&this.selectIds.length<this.list.length
         },
         handleCheckAllChange(val){
+            const key=this.libraryType==1?'ResourceId':'ImageConfId'
             if(val){
-                this.selectIds=this.list.map(item=>item.ResourceId)
+                this.selectIds=this.list.map(item=>item[key])
             }else{
                 this.selectIds=[]
             }
@@ -285,16 +386,26 @@ export default {
             this.isIndeterminate=false
             this.checkAll=false
             this.delIds=[]
-            
-            const res=await apiSmartReport.imgReourceList({
-                CurrentIndex:this.page,
-                PageSize:this.pageSize,
-                Type:this.type,
-                Keyword:this.keyword
-            })
-            if(res.Ret===200){
-                this.list=res.Data.List||[]
-                this.total=res.Data.Paging.Totals
+            let res='' 
+            if(this.libraryType==1){
+                res=await apiSmartReport.imgReourceList({
+                    CurrentIndex:this.page,
+                    PageSize:this.pageSize,
+                    Type:this.type,
+                    Keyword:this.keyword
+                })
+            }else{
+                res=await apiSmartReport.pptMaterialList({
+                    CurrentIndex:this.page,
+                    PageSize:this.pageSize,
+                    ImageType:this.type?this.type:null,
+                    ImageName:this.keyword,
+                    ConfType:1
+                })
+            }
+            if(res&&res.Ret===200){
+                this.list=res.Data?res.Data.List:[]
+                this.total=res.Data?res.Data.Paging.Totals:0
             }
         },
 
@@ -310,8 +421,13 @@ export default {
             form.append('file',file.file);
             bannerupload(form).then(res=>{
                 // console.log(res);
-                if(res.Ret!==200) return 
-                this.formData.imgUrl=res.Data.ResourceUrl
+                if(res.Ret!==200) return
+                if(this.libraryType==1){
+                    this.formData.imgUrl=res.Data.ResourceUrl
+                }else{
+                    this.ruleForm.Url=res.Data.ResourceUrl
+                    this.$refs.ruleForms.clearValidate('Url');
+                }
             })
         
         },
@@ -375,6 +491,33 @@ export default {
         handleCloseImgUpload(){
             this.uploadImgPop=false
         },
+        handlePptSave(){
+            this.$refs.ruleForms.validate(async (valid)=>{
+                if(valid){
+                    const params={
+                        ...this.ruleForm
+                    }
+                    let res=''
+                    if(this.ruleForm.ImageConfId){
+                        res=await apiSmartReport.pptEditMaterial(params)
+                    }else{
+                        res=await apiSmartReport.pptAddMaterial([params])
+                    }
+                    if(res&&res.Ret===200){
+                        this.$message.success(this.ruleForm.ImageConfId?this.$t('MsgPrompt.edit_msg'):this.$t('MsgPrompt.add_msg'))
+                        this.cancelPpt()
+                        this.page=1
+                        this.getImgList()
+                    }
+                }
+            })   
+        },
+        cancelPpt(){
+            this.uploadImgPpt=false
+            this.$nextTick(()=>{
+                this.$refs.ruleForms.clearValidate()
+            })        
+        },
         cancelHandle(){
             this.step=1
             this.formData.id=0
@@ -400,34 +543,57 @@ export default {
                 this.$refs.ruleForm.clearValidate()
             })
         },
+        handleShowImgPpt(){
+            this.showPptViewer=true
+            this.picShowList=[this.ruleForm.Url]
+        },
         handleShowImgFull(e){
             console.log(e);
-            this.picShowList=[e.ImgUrl]
+            this.picShowList=[this.libraryType==1?e.ImgUrl:e.Url]
             this.showViewer=true
         },
 
         handleClickOpt(e){
             if(e.type==='del'){
-                this.delIds=[e.data.ResourceId]
+                this.delIds=[this.libraryType==1?e.data.ResourceId:e.data.ImageConfId]
                 this.handleImgDel()
             }
             if(e.type==='edit'){
-                this.formData.id=e.data.ResourceId
-                this.formData.name=e.data.ImgName
-                this.formData.type=e.data.Type
-                this.formData.imgUrl=e.data.ImgUrl
-                this.formData.layout=e.data.Style
+                if(this.libraryType==1){
+                    this.formData.id=e.data.ResourceId
+                    this.formData.name=e.data.ImgName
+                    this.formData.type=e.data.Type
+                    this.formData.imgUrl=e.data.ImgUrl
+                    this.formData.layout=e.data.Style
 
-                this.uploadImgPop=true
+                    this.uploadImgPop=true
+                }else{
+                    this.ruleForm=JSON.parse(JSON.stringify(e.data))
+
+                    this.uploadImgPpt=true
+                }
             }
         },
         handleShowUploadPop(){
-            this.formData.id=0
-            this.formData.name=''
-            this.formData.type=''
-            this.formData.imgUrl=''
-            this.formData.layout=''
-            this.uploadImgPop=true
+            if(this.libraryType==1){
+                this.formData.id=0
+                this.formData.name=''
+                this.formData.type=''
+                this.formData.imgUrl=''
+                this.formData.layout=''
+                this.uploadImgPop=true
+            }else{
+                this.ruleForm={
+                    ImageName:'',
+                    Url:"",
+                    ConfType:1,
+                    ImageType:''
+                }
+                this.uploadImgPpt=true
+                this.$nextTick(()=>{
+                    this.$refs.ruleForms.clearValidate()
+                }) 
+            }
         },
 
         handleBatchDel(){
@@ -438,14 +604,18 @@ export default {
         handleImgDel(){
             this.$confirm(this.$t('SystemManage.BaseConfig.resource_del_msg'),this.$t('Confirm.prompt'),{
                 type: 'warning'
-            }).then(()=>{
-                apiSmartReport.imgReourceDel({ResourceIds:this.delIds.join(',')}).then(res=>{
-                    if(res.Ret===200){
-                        this.$message.success(this.$t('MsgPrompt.delete_msg'))
-                        this.page=1
-                        this.getImgList()
-                    }
-                })
+            }).then(async ()=>{
+                let res=''
+                if(this.libraryType==1){
+                    res=await apiSmartReport.imgReourceDel({ResourceIds:this.delIds.join(',')})
+                }else{
+                    res=await apiSmartReport.pptDeleteMaterial(this.delIds.map(el=>{return {ImageConfId:el}}))
+                }
+                if(res&&res.Ret===200){
+                    this.$message.success(this.$t('MsgPrompt.delete_msg'))
+                    this.page=1
+                    this.getImgList()
+                }
             })
         },
         // 切换步骤
@@ -563,7 +733,7 @@ export default {
     display: none;
 }
 .smart-report-img-set-page{
-    padding: 30px;
+    padding:11px 30px 30px;
     padding-bottom: 100px;
     .select-status-box{
         background-color: #F8F8F8;

+ 11 - 4
src/views/system_manage/etaBaseConfig.vue

@@ -304,7 +304,7 @@
                     <div v-if="isShowPPT&&pptLang === 'cn'" class="ppt-form-item-wrap">
                         
                         
-                        <el-form-item :label="$t('SystemManage.BaseConfig.ppt_type01')" prop="CnPptCoverImgs" style="min-width:400px;">
+                        <!-- <el-form-item :label="$t('SystemManage.BaseConfig.ppt_type01')" prop="CnPptCoverImgs" style="min-width:400px;">
                             <div class="input-line" style="display:flex;">
                                 <ImgUpload 
                                     :imgUrl="formData.CnPptCoverImgs.length===3?formData.CnPptCoverImgs[2]:''"
@@ -342,7 +342,7 @@
                             <ConfigAnnotation picName="pptBackPic" @showImage="previewImage"
                                 :picHintText="$t('SystemManage.BaseConfig.ppt_tip03')"
                                 :buttonText="$t('SystemManage.BaseConfig.view_example_text')"/>
-                        </el-form-item>
+                        </el-form-item> -->
                         <el-form-item label="PPT表格" prop="CnPptSheetSize">
                             <template slot="label">
                                 <span>
@@ -428,9 +428,12 @@
         
         </template>
         <template v-if="sectionType==2&&isShowSource">
-            <div class="smart-report-title">{{$t('SystemManage.BaseConfig.smart_layout_resource_library')}}</div>
+            <el-radio-group v-model="libraryType" style="margin:16px 0 0 30px;">
+                <el-radio-button label="1" v-if="permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_see)">{{$t('SystemManage.BaseConfig.smart_layout_resource_library')}}</el-radio-button>
+                <el-radio-button label="2" v-if="permissionBtn.checkPermissionBtn(permissionBtn.baseConfigPermission.etaBaseConfig_source_ppt_see)">{{$t('SystemManage.BaseConfig.ppt_resource_library')}}</el-radio-button>
+            </el-radio-group>
             <!-- 资源库 -->
-            <smartReportImgSet />
+            <smartReportImgSet :libraryType="libraryType" />
         </template>
 
 
@@ -462,6 +465,7 @@ export default {
         }
         return {
             /* base config */
+            libraryType:'1',
             checkList:[],//水印应用
             Iflytek:false,//是否启用科大讯飞服务
             approve:false,//是否开启研报审批
@@ -700,6 +704,8 @@ export default {
         isShowSource(){
             return this.permissionBtn.checkPermissionBtn(
                 this.permissionBtn.baseConfigPermission.etaBaseConfig_source_see
+            ) || this.permissionBtn.checkPermissionBtn(
+                this.permissionBtn.baseConfigPermission.etaBaseConfig_source_ppt_see
             )
         },
 
@@ -886,6 +892,7 @@ export default {
     },
     mounted(){
         this.getBaseConfig()
+        this.libraryType=this.permissionBtn.checkPermissionBtn(this.permissionBtn.baseConfigPermission.etaBaseConfig_source_see)?'1':'2'
     }
 };
 </script>