pptEditor.vue 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740
  1. <template>
  2. <div class="page-wrap">
  3. <div class="index-wrap ppt-page-wrap flex-column">
  4. <div class="cover-wrap">
  5. <div class="flex-align">
  6. <p class="hint-text" @click="openSelectImage(2,firstPage.CurrentBackgroundImgId,firstPage.CurrentBackgroundImg)">{{$t('Slides.select_ground_page')}}</p>
  7. <p class="hint-text" style="margin-left:37px" @click="openSelectImage(3,firstPage.BackCoverImgId,firstPage.BackCoverImg)">{{$t('Slides.select_back_page')}}</p>
  8. </div>
  9. <div class="flex-align" style="margin:8px 0"><p class="hint-text" @click="openChooseCover">{{$t('Slides.select_cover_page')}}</p></div>
  10. <div class="cover" @click="openChooseCover" :style="`background: no-repeat center/cover url(${firstPage.BackgroundImg||''});background-color:#F2F6FA;background-size:100% 100%;`">
  11. <img src="~@/assets/img/ppt_m/add_first.png" />
  12. </div>
  13. </div>
  14. <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>
  15. <div style="display:flex;justify-content: space-between;">
  16. <p style="text-align:start;color:#999999;">
  17. {{$i18n.locale == 'zh' ? `已添加${pageList.length}页`:`${pageList.length}slides added successfully`}}
  18. </p>
  19. <p class="hint-text" style="cursor: pointer;" @click="saveCopyPages('cut')">{{$t('Slides.operations_cut')}}</p>
  20. <p class="hint-text" style="cursor: pointer;" @click="saveCopyPages('copy')">{{$t('Slides.operations_copy')}}</p>
  21. <p style="color:#B72E18;cursor: pointer;" @click="openDeletePageDialog">{{$t('Slides.operations_batch_delete')}}</p>
  22. </div>
  23. <div class="index-list" ref="pptList" v-click-outside="resetCopyPages">
  24. <div class="empty" v-if="pageList.length===0">
  25. <img src="~@/assets/img/ppt_m/ppt-empty.png" alt="">
  26. <p>{{$t('Slides.add_main_text_empty')}}</p>
  27. </div>
  28. <transition-group name="flip-list">
  29. <index-item
  30. v-for="(item,index) in pageList" :key="item.id"
  31. :pageItem="item"
  32. :pageIndex="index"
  33. :currentItem="currentItem"
  34. :pageLength="pageList.length"
  35. :copyPagesMap="copyPagesMap"
  36. :ctrlKeyActive="ctrlKeyActive"
  37. :savePagesArrLength="savePagesArr.length"
  38. @deletePage="delPage"
  39. @click.native="handleClickItem(item)"
  40. @dragstart.native="(e)=>{dragstart(e,item)}"
  41. @dragenter.native="(e)=>{dragenter(e,item)}"
  42. @dragend.native="dragend(item)"
  43. @dragover.native="(e)=>{e.preventDefault()}"
  44. @changePage="changePageIndex"
  45. @operatePpt="handleOperate"
  46. />
  47. </transition-group>
  48. </div>
  49. </div>
  50. <div class="ppt-editor-wrap ppt-page-wrap" v-loading="isChartLoading" :element-loading-text="chartLoadingText">
  51. <div class="ppt-editor" id="pptEditor" ref="pptEditor" @paste="handlePasteOutSide">
  52. <!-- 显示全部ppt -->
  53. <template v-if="pageList.length">
  54. <div class="ppt-editor-item flex-column" v-for="(item,index) in pageList" :key="item.id">
  55. <AddFormat @addPage="addPage($event,index)" :chooseModalId="chooseModalId"/>
  56. <div class="ppt-item" :class="{'choose':currentItem.id===item.id}"
  57. v-loading="item.isUpdating" :element-loading-text="$t('Slides.updating_chart_loading')"
  58. @click.stop="changeCurrentItem(item)">
  59. <!-- 标题 -->
  60. <!-- <div class="title-wrap" style="background-color: #999999;">
  61. <input type="text" placeholder="单击输入标题" v-model="item.title"/>
  62. </div> -->
  63. <!-- 自定义标题 -->
  64. <div @click.stop
  65. :class="[
  66. 'ppt-editor-title',
  67. 'custom-title-wrap',
  68. currentItem.id===item.id&&isEditTitle?'editor-model':''
  69. ]"
  70. :style="item.titleDetail?{
  71. left:item.titleDetail.left+'%',
  72. top:item.titleDetail.top+'%',
  73. width:item.titleDetail.width+'%',
  74. height:item.titleDetail.height+'%',
  75. }:{
  76. left:'10%',top:'6.6%',width:'68%',height:'5%',
  77. }">
  78. <!-- <div class="title" v-html="item.title"></div> -->
  79. <!-- <el-input type="textarea" placeholder="单击输入标题" v-model="item.title"
  80. autosize resize="none"
  81. spellcheck="false"
  82. :style="item.titleDetail?{
  83. color:item.titleDetail.color,
  84. fontSize:item.titleDetail.fontSize+'px',
  85. fontFamily:item.titleDetail.fontFamily,
  86. '--titleColor':item.titleDetail.color,
  87. '--fontSize':item.titleDetail.fontSize,
  88. '--fontFamily':item.titleDetail.fontFamily,
  89. }:{ color:'#333',fontSize:'22px',fontFamily:'helvetica' }"
  90. @focus="handleEditTitle(item)"
  91. v-click-title-outside="exitEditTitle"></el-input> -->
  92. <div contenteditable="true" spellcheck="false"
  93. :id="`page_title__${index}`"
  94. class="title-editor"
  95. :style="item.titleDetail?{
  96. color:item.titleDetail.color||'#333',
  97. fontSize:(item.titleDetail.fontSize||22)+'px',
  98. fontFamily:(item.titleDetail.fontFamily||'helvetica'),
  99. outline:0,
  100. }:{ color:'#333',fontSize:'22px',fontFamily:'helvetica',outline:0}"
  101. v-click-title-outside="exitEditTitle"
  102. @click.stop="handleEditTitle(item)"
  103. @paste.stop="(e)=>handlePaste(e,item)"
  104. @input="(e)=>handleInput(e,item)"></div>
  105. </div>
  106. <!-- 内容 -->
  107. <component :is="getComponentName(item.modelId)"
  108. :ref="`pptPage_${index}`"
  109. :pageIndex="index"
  110. :pageItem="item"
  111. :key="item.key"
  112. :isCopy="true"
  113. :isAdd="true"
  114. :isEditLayer="isEditLayer"
  115. :isEditTitle="isEditTitle"
  116. :choosedId="currentItem.id"
  117. :activeLayerEl="activeLayerEl"
  118. :amendatoryPositionInfo="item.positionInfo"
  119. @delChart="handleDelChart"
  120. @pasteImg="handlePasteImg"
  121. @changeText="handleChangeText"
  122. @changeActEl="changeActLayerEl"
  123. @deleteLayer="deleteLayerEl"
  124. @copyShape="getCopyItem"
  125. @reload="reloadPage"
  126. @addChart="handleAddChartToGallery"
  127. ></component>
  128. <!-- 删除按钮 -->
  129. <el-popconfirm
  130. @onConfirm="delPage(item)"
  131. :confirmButtonText="$t('Slides.operations_delete')"
  132. :cancelButtonText="$t('Slides.operations_cancel')"
  133. confirmButtonType="text"
  134. icon="el-icon-info"
  135. iconColor="red"
  136. :title="$t('Slides.is_delete_ppt_msg')">
  137. <span class="close-btn" @click.stop slot="reference"></span>
  138. </el-popconfirm>
  139. <!-- 页码 -->
  140. <span class="page-num"> {{$i18n.locale == 'zh' ?`第${index+1}页`:` Slide${index+1}`}}</span>
  141. <!-- 更新图表 -->
  142. <span class="update-btn" v-show="item.modelId!==6&&item.elements.find((i)=>i.type==='chart'||i.type==='sheet')" @click.stop="updatePage(item)"><span class="update-ico"></span> {{$t('Slides.update_chart_btn')}}</span>
  143. </div>
  144. <AddFormat v-if="index===pageList.length-1" @addPage="addPage($event,index+1)" :chooseModalId="chooseModalId"/>
  145. </div>
  146. <!-- 自定义右键菜单 -->
  147. <context-menu :menu="[{id:1,text:$t('Slides.paste_element_btn'),eventName:'paste',canClick:Boolean(copyShape.id)}]" @paste="pasteLayerEl"/>
  148. <!-- </transition-group> -->
  149. </template>
  150. <template v-else>
  151. <div class="ppt-editor-item flex-column">
  152. <add-format @addPage="addPage($event,0)"/>
  153. </div>
  154. </template>
  155. </div>
  156. <div class="ppt-tool flex-column">
  157. <div class="save-hint" v-show="showLastSaveTime"
  158. style="color: #666; margin-bottom: 15px"
  159. >{{$t('Slides.last_save_time')}}:{{lastSaveTime}}</div>
  160. <div class="tool-btn">
  161. <el-button type="primary" :loading="refreshBtnLoading" @click="refleshFormatEl">{{$t('Slides.operations_refresh')}}</el-button>
  162. <el-button v-permission="permissionBtn.pptPermission.ppt_publish"
  163. type="primary" @click="handlePublish">{{ result.ReportSource===1?'去发布':'去提交' }}</el-button>
  164. <el-button @click="handleSave('save')">{{$t('Slides.operations_save')}}</el-button>
  165. <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>
  166. <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>
  167. </div>
  168. <div class="richtext-tool"></div>
  169. <!-- 防止el-tabs未渲染时触发scrollToActiveTab 报错,v-if改为v-show-->
  170. <div class="addppt-right-box" v-show="!isEditLayer&&!isEditTitle">
  171. <el-tabs v-model="tabsactive">
  172. <el-tab-pane :label="tab.label" :name="tab.val" v-for="tab in panelTabs" :key="tab.val"></el-tab-pane>
  173. </el-tabs>
  174. <div class="chart-tool flex-column" v-show="tabsactive == '图表'">
  175. <div class="chart-search">
  176. <el-input :placeholder="$t('Slides.keyword_search')" v-model="key_word" size="medium" prefix-icon="el-icon-search" @input="() => {search_page=1;$refs.chartListRef.scrollTop = 0;getreportlist()}" style="max-width:420px;"></el-input>
  177. </div>
  178. <el-radio-group v-model="chart_source" @change="() => {search_page=1;$refs.chartListRef.scrollTop = 0;getreportlist()}" style="margin: 10px 0;">
  179. <el-radio :label="1" style="margin-bottom:5px">{{$t('Slides.eta_chart_gallery')}}</el-radio>
  180. <!-- <el-radio :label="2" style="margin-bottom:5px">{{$t('Slides.commodity_price_curve')}}</el-radio> -->
  181. <el-radio :label="3" style="margin-bottom:5px">{{$t('Slides.correlation_charts')}}</el-radio>
  182. <el-radio :label="6" style="margin-bottom:5px">{{$t('Slides.fitted_equation_curves')}}</el-radio>
  183. <el-radio :label="7" style="margin-bottom:5px">{{$t('Slides.statistical_features')}}</el-radio>
  184. <el-radio :label="10">{{$t('Slides.intercommodity_analysis')}}</el-radio>
  185. </el-radio-group>
  186. <div style="margin: 10px 0">
  187. <el-checkbox v-model="isShowMe" @change="() => {search_page=1;$refs.chartListRef.scrollTop = 0;getreportlist()}">{{$t('Slides.show_only_mine')}}</el-checkbox>
  188. </div>
  189. <div class="chart-list" v-infinite-scroll="loadReportHandle" :infinite-scroll-immediate="false" ref="chartListRef">
  190. <template v-if="chartList.length">
  191. <div v-for="(item, index) in chartList" :key="index" @click="chooseChart(item,'chart')" class="chart-item" :style="item.Disabled && 'cursor: not-allowed;'">
  192. <p class="chart_tit" style="word-break: break-all;">{{ item.ChartName }}</p>
  193. <img :src="!item.HaveOperaAuth?$icons.lock_big:item.ChartImage" ref="insert_img" style="-webkit-user-drag:none;"/>
  194. </div>
  195. </template>
  196. <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-else/>
  197. </div>
  198. </div>
  199. <div v-show="tabsactive == '沙盘'" class="chart-tool flex-column">
  200. <div class="chart-search">
  201. <el-input :placeholder="$t('Slides.sandbox_name_category')" v-model="sandTabelQuery.Keyword" size="medium" prefix-icon="el-icon-search" style="max-width:420px;"></el-input>
  202. </div>
  203. <div class="chart-list" id="sandTable" @scroll="sandTableHandleScroll">
  204. <template v-if="sandTableList.length">
  205. <div v-for="(item,index) in sandTableList" :key="index" class="sandTable-item" >
  206. <p class="chart_tit">{{item.Name}}</p>
  207. <img :src="item.PicUrl" style="width:100%;-webkit-user-drag:none;" @click="chooseChart(item,'sandImage')"/>
  208. </div>
  209. <div v-loading = "sandTableLoading" class="loaded-text">{{loadedText}}</div>
  210. </template>
  211. <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-else/>
  212. </div>
  213. </div>
  214. <div v-show="tabsactive == '表格'" class="chart-tool flex-column">
  215. <div class="chart-search">
  216. <el-input :placeholder="$t('Slides.table_name_input')" v-model="sheetSearchObj.Keyword" size="medium" prefix-icon="el-icon-search" style="max-width:420px;" @input="getSheetList"></el-input>
  217. </div>
  218. <div class="chart-list" id="sandTable">
  219. <template v-if="sheetSearchList.length">
  220. <div v-for="(item,index) in sheetSearchList" :key="index" class="sandTable-item" >
  221. <p class="chart_tit">{{item.ExcelName}}</p>
  222. <img :src="!item.HaveOperaAuth?$icons.lock_big:item.ExcelImage" style="width:100%;object-fit: contain;height: 250px;-webkit-user-drag:none;" @click="chooseChart(item,'sheet')"/>
  223. </div>
  224. </template>
  225. <tableNoData :text="$t('Table.prompt_slogan')" size="mini" v-else/>
  226. </div>
  227. </div>
  228. <div v-show="tabsactive == 'MyETA批量'" class="chart-tool flex-column">
  229. <insert-charts @handleImportMyChart="handleImportMyChart"/>
  230. </div>
  231. <div v-show="tabsactive == '语义分析插入'" class="chart-tool flex-column">
  232. <InsertSemantics />
  233. </div>
  234. <div v-show="tabsactive == '知识资源'" class="chart-tool flex-column">
  235. <insert-knowledge />
  236. </div>
  237. </div>
  238. <!-- 图层编辑 -->
  239. <div class="layer-edit-box" v-if="isEditLayer">
  240. <el-collapse v-model="activeNames" class="tool-list">
  241. <el-collapse-item :title="$t('Slides.layer_element')" name="el">
  242. <div class="el-wrap">
  243. <div class="el-item"
  244. v-for="(shape,index) in layerElArr" :key="index" @click="addLayerEl(shape)">
  245. <el-tooltip class="item" effect="dark" :content="shape.name" placement="top">
  246. <ShapePreview :shape="shape" />
  247. </el-tooltip>
  248. </div>
  249. </div>
  250. </el-collapse-item>
  251. <el-collapse-item name="line"
  252. :title="$t('Slides.line_settings')" >
  253. <LayerEditTool
  254. :isActiveEl="activeLayerEl.type==='line'?true:false"
  255. :elInfo="activeLayerEl.type==='line'?activeLayerEl:BaseLineShape"
  256. baseType="line"/>
  257. </el-collapse-item>
  258. <el-collapse-item name="shape"
  259. :title="$t('Slides.outline_element')" >
  260. <LayerEditTool
  261. :isActiveEl="activeLayerEl.type==='shape'?true:false"
  262. :elInfo="activeLayerEl.type==='shape'?activeLayerEl:BaseRectShape"
  263. baseType="shape"/>
  264. </el-collapse-item>
  265. <el-collapse-item name="text"
  266. :title="$t('Slides.text_element')" >
  267. <LayerEditTool
  268. :isActiveEl="activeLayerEl.type==='text'?true:false"
  269. :elInfo="activeLayerEl.type==='text'?activeLayerEl:BaseTextShape"
  270. baseType="text"/>
  271. </el-collapse-item>
  272. </el-collapse>
  273. </div>
  274. <!-- 标题编辑 -->
  275. <div class="title-edit-box" v-if="isEditTitle">
  276. <p>
  277. {{$t('Slides.page_title_style_setting')}}
  278. </p>
  279. <TitleEditorTool
  280. ref="titleEditor"
  281. :currentItem="currentItem"
  282. @changeSizeAll="changeSizeAll"
  283. @changePositionAll="changePositionAll"
  284. @styleChange="handleTitelStyleChange"
  285. @textChange="handleTextChange"
  286. @applyToAll="changeSettingAll"/>
  287. </div>
  288. <!-- 历史记录编辑 -->
  289. <div class="history-edit-box" v-if="isVersionHistory">
  290. <VersionRecord :PptId="PptId" @handleRestore="handleRestore"/>
  291. </div>
  292. </div>
  293. </div>
  294. <!-- 选择封面弹窗 -->
  295. <ChooseCoverNew
  296. ref="ChooseCoverNewRef"
  297. v-if="isShowChooseCover"
  298. :isShowChooseCover="isShowChooseCover"
  299. :firstPage="firstPage"
  300. :pptCoverList="pptCoverList"
  301. :PptId="pptId"
  302. :CoverContent="CoverContent"
  303. @saveCover="saveCover2"
  304. @close="isShowChooseCover=false"
  305. @chooseMoreCover="coverChooseImage()"
  306. />
  307. <!-- 批量删除弹窗 -->
  308. <delete-page-dialog
  309. :deletePageShow="deletePageShow"
  310. :pageList="pageList"
  311. :optionMap="optionMap"
  312. ref="deletePage"
  313. @cancel="deletePageShow=false"
  314. @delete="handleDeletePages"
  315. />
  316. <!-- 一键改版弹窗 -->
  317. <change-format-dialog
  318. :changeFormatPageShow="changeFormatPageShow"
  319. :pptModelId="choosedItem?choosedItem.modelId:0"
  320. @cancel="changeFormatPageShow=false"
  321. @changeModel="changeFormatPage"
  322. />
  323. <!-- 插入PPT弹窗 -->
  324. <insert-page-dialog
  325. :insertPageShow="insertPageShow"
  326. @cancel="insertPageShow=false"
  327. @insert="handleInsert"
  328. />
  329. <!-- 添加到 我的图库 弹窗 -->
  330. <addMyClassifyDia
  331. :isAddMyDialog="addMyChartShow"
  332. :add_id="addChartInfoId"
  333. :add_ids="addChartClassifyIds"
  334. @cancel="addMyChartShow = false"
  335. @addSuccess="addChartToGallery"
  336. />
  337. <selectImage @saveChoose='saveChooseImage' ref="selectImageRef"/>
  338. </div>
  339. </template>
  340. <script>
  341. import {countComponentName,checkClipboardItems,createRandomCode,checkPPTpageElemant,getChartInfo,getPlainText} from './utils/untils';
  342. import {modelInfo,defaultPosition} from './utils/config'
  343. import http from '@/api/http.js';
  344. import { dataBaseInterface ,sandInterface } from "@/api/api.js";
  345. import futuresInterface from '@/api/modules/futuresBaseApi';
  346. import chartRelevanceApi from '@/api/modules/chartRelevanceApi';
  347. import { fittingEquationInterface,statisticFeatureInterface,crossVarietyInterface } from '@/api/modules/chartRelevanceApi';
  348. import { eventInterface } from "@/api/modules/knowledge";
  349. import pptmixin from '../mixins/pptMixins';
  350. import {uploadFileDirect} from "@/utils/common.js"
  351. import mixins from '../mixins/mixins';
  352. import layerMixins from '../mixins/layerMixins';
  353. import pptEditorMixins from '../mixins/pptEditorMixins';
  354. import Highcharts from "highcharts/highstock";
  355. import HighchartszhCN from '@/utils/highcahrts-zh_CN'
  356. HighchartszhCN(Highcharts)
  357. import IndexItem from './components/IndexItem.vue';
  358. import ChooseCover from './components/editor/ChooseCover.vue';
  359. import AddFormat from './components/editor/AddFormat.vue';
  360. import {pptInterface} from '@/api/api.js';
  361. import * as sheetInterface from '@/api/modules/sheetApi.js';
  362. import ShapePreview from './components/layer/shapePreview.vue';
  363. import LayerEditTool from './components/layer/layerEditTool.vue';
  364. import VersionRecord from './components/layer/VersionRecord.vue';
  365. import DeletePageDialog from './components/editor/DeletePageDialog.vue';
  366. import ChangeFormatDialog from './components/editor/ChangeFormatDialog.vue';
  367. import InsertPageDialog from './components/editor/InsertPageDialog.vue';
  368. import addMyClassifyDia from '@/views/dataEntry_manage/components/addMyClassifyDia';
  369. import InsertCharts from './components/editor/InsertCharts.vue';
  370. import ContextMenu from './components/ContextMenu.vue';
  371. import InsertSemantics from './components/editor/InsertSemantics.vue';
  372. import InsertKnowledge from './components/editor/InsertKnowledge.vue'
  373. import ChooseCoverNew from './components/editor/ChooseCoverNew.vue';
  374. import TitleEditorTool from './components/editor/TitleEditorTool';
  375. import selectImage from './components/selectImage.vue';
  376. import { apiSmartReport } from '@/api/modules/smartReport'
  377. export default {
  378. mixins:[pptmixin,//ppt页面共同逻辑
  379. mixins,//图表加载逻辑
  380. layerMixins,//图层操作逻辑
  381. pptEditorMixins,//编辑页共同逻辑
  382. ],
  383. components: {
  384. IndexItem, ChooseCover, AddFormat, ShapePreview,
  385. LayerEditTool, DeletePageDialog, ChangeFormatDialog, InsertPageDialog, addMyClassifyDia, InsertCharts, ContextMenu, InsertSemantics,
  386. ChooseCoverNew, TitleEditorTool,selectImage, VersionRecord,InsertKnowledge
  387. },
  388. data() {
  389. return {
  390. pageList:[],//ppt数组
  391. currentItem:null,//当前活跃的page
  392. currentIndex:0,//当前活跃的pageIndex
  393. oldNum:null,//拖动相关
  394. newNum:null,//拖动相关
  395. chooseModalId:1,//上一次选择的版式Id
  396. firstPage:{
  397. Title:'',
  398. ReportType:'',//ETA1.4.9不用了
  399. BackgroundImg:'',
  400. PptDate:(new Date().getFullYear())+'年'+(new Date().getMonth()+1)+'月',//ETA1.4.9不用了
  401. BackIndex:0,//ETA基本配置上线后不用了
  402. TemplateType:1,//ETA基本配置上线后不用了
  403. },//封面信息
  404. key_word:'',//搜索图表关键字
  405. chartList:[],//图表数组
  406. imgUrl:'',//黏贴图片上传后的地址
  407. isShowChooseCover:false,
  408. getDataLoading:null,//获取动态图表数据/上传图片的loading,
  409. isSave:false,//是否已手动保存过
  410. pptId:null,//新增后获得的pptid
  411. maxPageNum:0,//可以添加的最大页数
  412. maxPageChart:0,//可以添加的最大图表数
  413. chartNum:0,//当前PPT的总图表数
  414. tabsactive:'图表', //右侧区域显示内容 图表 | 沙盘
  415. // 沙盘图查询参数
  416. sandTabelQuery:{
  417. PageSize: 20,
  418. CurrentIndex: 1,
  419. Keyword: '',
  420. },
  421. sandTableLoading:false,
  422. sandTableTotal:0,//沙盘总共条数
  423. sandTableList:[],
  424. loadedText:'',
  425. // 沙盘图分页加载 是否在加载中
  426. isRequesting:false,
  427. catalogId:0,//ppt目录id,添加ppt时需要
  428. ReportId:0,//ppt对应的双周报id,如果没转过,则为0
  429. isChartLoading:false,//是否正在加载图表/图片
  430. sheetSearchList:[],
  431. sheetSearchObj: {
  432. Keyword:''
  433. },
  434. deletePageShow:false,//控制批量删除弹窗是否显示
  435. chartLoadingText:`${this.$t('Slides.loading_urgently')}...`,
  436. loopTimer:null,//自动保存标识
  437. search_page: 1,
  438. search_page_sizes: 20,
  439. search_have_more: true,
  440. chart_source: 1,//图表来源 1 eta 2 商品价格
  441. isShowMe: false,
  442. isVersionHistory: false,//是否显示版本历史
  443. };
  444. },
  445. computed:{
  446. panelTabs(){
  447. return [
  448. {val:'图表',label:this.$t('Slides.table_chart') },
  449. {val:'沙盘', label:this.$t('Slides.sandbox_name')},
  450. {val:'表格', label:this.$t('Slides.table_name')},
  451. {val:'知识资源',label:'知识资源'}
  452. ]
  453. },
  454. },
  455. created() {
  456. //获取图表,沙盘,表格数据
  457. this.getreportlist()
  458. this.getSandTable()
  459. this.getSheetList()
  460. //获取PPT限制
  461. this.getPPTLimit()
  462. },
  463. mounted(){
  464. if(Highcharts.charts){
  465. Highcharts.charts.length=0
  466. }
  467. this.init()
  468. window.addEventListener('message',this.reInitIframe)
  469. },
  470. watch:{
  471. 'sandTabelQuery.Keyword'(newval,oldval){
  472. $('#sandTable').animate({scrollTop:0},100);
  473. this.sandTabelQuery.CurrentIndex = 1
  474. this.getSandTable()
  475. }
  476. },
  477. methods: {
  478. getPPTLimit(){
  479. pptInterface.getConfig().then(res=>{
  480. if(res.Ret===200){
  481. this.maxPageNum = res.Data.ppt_num
  482. this.maxPageChart = res.Data.chart_num
  483. }
  484. })
  485. },
  486. async init(){
  487. this.dataLoading = this.$loading({
  488. lock: true,
  489. text: `${this.$t('Slides.retrieving_ppt_data')}...`,
  490. spinner: 'el-icon-loading',
  491. customClass:'loading',
  492. target:document.querySelector('.page-wrap'),
  493. background: 'rgba(255, 255, 255, 0.8)'
  494. });
  495. await this.getpptData()
  496. //遍历pageList,初始化图表,文字
  497. await this.initPPTAllPage(this.pageList)
  498. for(let i=0;i<this.pageList.length;i++){
  499. //计算图表总数
  500. const chartElements = this.pageList[i].elements.filter((item) => {
  501. return item.type === "chart";
  502. });
  503. this.chartNum+=chartElements.length
  504. await this.initPageElements(this.pageList[i])
  505. }
  506. //获取已加载图表的信息
  507. let chartInfoMap = {}
  508. for(let i=0;i<this.pageList.length;i++){
  509. this.pageList[i].elements.forEach(item=>{
  510. if(item.type==='chart'){
  511. let temp = getChartInfo(this.optionMap[item.chartId])
  512. chartInfoMap[item.chartId] = temp
  513. }
  514. })
  515. }
  516. this.$store.commit('SET_CHART_INFO_MAP',chartInfoMap)
  517. //添加ppt的情况:获取目录id
  518. if(!this.$route.query.id){
  519. this.catalogId = Number(sessionStorage.getItem('selectedCatalog'))
  520. }
  521. //防止自动保存时,有某一页处于更新图表的状态,其isUpdating为true
  522. this.pageList.forEach(i=>{
  523. i.isUpdating = false
  524. })
  525. this.dataLoading.close();
  526. // $('.ppt-item').css('background-image',`url(${this.pptBgImage})`);
  527. //开启自动保存
  528. this.autoSave()
  529. },
  530. async getpptData(){
  531. const {id} = this.$route.query
  532. if(id){
  533. await this.getpptDataById(id)
  534. const {status} = this.result
  535. if(status===200){
  536. const {content,FirstPage,ReportId,TitleSetting} = this.result
  537. this.pageList = content
  538. this.firstPage = FirstPage
  539. this.firstPage.BackIndex = FirstPage.TemplateType-1
  540. this.currentItem = this.pageList[0]
  541. this.ReportId=ReportId
  542. this.CoverContent = this.result.CoverContent
  543. this.titleSetting = TitleSetting||null
  544. if(this.firstPage.CurrentBackgroundImg){
  545. $('.ppt-item').css('background-image',`url(${this.firstPage.CurrentBackgroundImg})`);
  546. }
  547. /* //开启自动保存
  548. this.autoSave() */
  549. }else{
  550. this.$message.error(this.$t('Slides.error_ppt_data_msg') )
  551. this.dataLoading.close();
  552. window.close()
  553. }
  554. }else{
  555. this.pageList = []
  556. this.currentItem = null
  557. }
  558. this.currentIndex = 0
  559. },
  560. // 选择图片保存
  561. saveChooseImage(item){
  562. console.log(item)
  563. const key={
  564. 1:'BackgroundImg',
  565. 2:'CurrentBackgroundImg',
  566. 3:'BackCoverImg'
  567. }
  568. const idKey={
  569. 1:'BackgroundImgId',
  570. 2:'CurrentBackgroundImgId',
  571. 3:'BackCoverImgId'
  572. }
  573. if(item.type==1){
  574. const searchIndex = this.pptCoverList.findIndex(i=>i.Url===item.url)
  575. //如果基本配置-封面图,没有当前ppt的封面图,则默认第一个
  576. if(searchIndex>-1){
  577. this.$refs.ChooseCoverNewRef.pageData.BackgroundImg = item.url
  578. this.$refs.ChooseCoverNewRef.pageData.BackgroundImgId = item.id
  579. this.$refs.ChooseCoverNewRef.choosedIndex=searchIndex
  580. }
  581. }else{
  582. this.$set(this.firstPage,key[item.type],item.url)
  583. this.$set(this.firstPage,idKey[item.type],item.id)
  584. if(item.type==2){
  585. $('.ppt-item').css('background-image',`url(${item.url})`);
  586. }
  587. }
  588. },
  589. // 选择封面弹框选择更多模板
  590. coverChooseImage(){
  591. this.openSelectImage(1,this.$refs.ChooseCoverNewRef.pageData.BackgroundImgId,this.$refs.ChooseCoverNewRef.pageData.BackgroundImg)
  592. },
  593. // 打开选择背景图、封底图、封面图
  594. openSelectImage(type,id,url){
  595. this.$refs.selectImageRef.showHandle(type,id,url)
  596. },
  597. //打开选择封面页弹窗
  598. openChooseCover(){
  599. apiSmartReport.pptMaterialList({
  600. CurrentIndex: 1,
  601. PageSize: 1000,
  602. ImageType: 1,
  603. ImageName: '',
  604. ConfType: 1
  605. }).then(res => {
  606. this.pptCoverList=res.Data ? res.Data.List : []
  607. this.isShowChooseCover = true
  608. this.$nextTick(()=>{
  609. this.$refs.ChooseCoverNewRef.showDialog()
  610. })
  611. })
  612. },
  613. //关闭选择封面页弹窗
  614. closeChooseCover(){
  615. this.isShowChooseCover = false
  616. },
  617. //保存修改的封面页
  618. saveCover(info){
  619. console.log(info)
  620. this.firstPage = info
  621. this.closeChooseCover()
  622. },
  623. //在指定位置添加一个有版式的空白页
  624. addPage(modelId,index) {
  625. let page = {
  626. id: createRandomCode(),
  627. key:0,
  628. modelId: modelId,
  629. title:'',
  630. elements: [],
  631. titleDetail:this.titleSetting?this.titleSetting:null
  632. }
  633. this.pageList.splice(index,0,page)
  634. this.changeCurrentItem(page)
  635. this.chooseModalId = modelId
  636. },
  637. //计算ppt的版式名称
  638. getComponentName(modelId){
  639. return countComponentName(modelId);
  640. },
  641. //删除一页
  642. delPage(item) {
  643. //找到index
  644. const index = this.pageList.findIndex((i) => i.id === item.id);
  645. //选中它
  646. this.changeCurrentItem(item)
  647. //计算出该页有多少个图表,chartNum-=num
  648. const chartElements = this.pageList[index].elements.filter((item) => {
  649. return item.type === "chart";
  650. });
  651. this.chartNum-=chartElements.length
  652. //从pageList移除这一页
  653. this.pageList.splice(index, 1);
  654. //更新活动页(currentItem)
  655. if (this.pageList.length === 0) {
  656. //删除的是仅有的一页
  657. this.currentIndex = 0;
  658. } else if (this.pageList.length === this.currentIndex) {
  659. //删除的是最后一页
  660. this.currentIndex = this.pageList.length - 1;
  661. }
  662. if(this.pageList.length===0){
  663. this.currentItem = null
  664. }else{
  665. this.changeCurrentItem(this.pageList[this.currentIndex])
  666. }
  667. this.$message.success(this.$t('MsgPrompt.delete_msg'))
  668. },
  669. //删除活跃页的某一位置的图表/图片/其他组件
  670. handleDelChart(position) {
  671. this.currentItem.elements.map((i)=>{
  672. if(i.position===position){
  673. this.deleteFormatEl(i.type,position)
  674. }
  675. })
  676. //更新currentItem和pageList[currentIndex]
  677. //console.log(this.currentItem.elements);
  678. this.currentItem.elements = this.currentItem.elements.filter(
  679. (i) => i.position !== position
  680. );
  681. //console.log(this.currentItem.elements);
  682. this.pageList[this.currentIndex] = this.currentItem;
  683. //不使用强制刷新,而用deleteFormatEl代替
  684. //this.pageList[this.currentIndex].key++
  685. //有已经初始化了的文本框的话,做个标记
  686. const textElements = this.currentItem.elements.filter((item)=>{
  687. return item.type === 'text'
  688. })
  689. if(textElements.length>0){
  690. this.pageList[this.currentIndex].isLoadText = true
  691. }
  692. },
  693. deleteFormatEl(type,position){
  694. if(type==='chart'){
  695. this.chartNum--
  696. $(`#${type}_${this.currentIndex}_${position}`).html(`<img id="img_${this.currentIndex}_${position}" />`)
  697. $(`#preview_${type}_${this.currentIndex}_${position}`).html(`<img id="preview_img_${this.currentIndex}_${position}" />`)
  698. }
  699. if(type==='image'){
  700. $(`#${type}_${this.currentIndex}_${position}`).parent().html(`<img id="${type}_${this.currentIndex}_${position}" />`)
  701. $(`#preview_${type}_${this.currentIndex}_${position}`).parent().html(`<img id="preview_${type}_${this.currentIndex}_${position}" />`)
  702. }
  703. if(type==='sheet'){
  704. this.$refs[`pptPage_${this.currentIndex}`][0].$refs[`sheet_${this.currentIndex}_${position}`].getSheetData('',[])
  705. this.$refs.deletePage.isLoaded&&this.$refs.deletePage.$refs[`preview_${this.currentIndex}`][0].$refs[`preview_sheet_${this.currentIndex}_${position}`].getSheetData('',[])
  706. }
  707. },
  708. handlePasteOutSide:_.throttle(async function(e){
  709. //e:粘贴板事件
  710. console.log(e)
  711. //如果是标题/文本编辑框,直接返回
  712. if(e.target.tagName=='INPUT'||e.target.id==='mcepastebin') {
  713. return
  714. }
  715. //如果是文本框内右键粘贴,也返回
  716. if(e.target.tagName!=='DIV') return
  717. //算出currentItem还有哪些位置可以插入图表
  718. const {isAdd,addPositions}=this.checkElements(this.currentItem.modelId,this.currentItem.elements,'chart')
  719. if(!isAdd){
  720. this.$message(this.$t("Slides.please_delete_existing_chartsmsg"))
  721. return
  722. }
  723. //从clipboardData中获取图片
  724. if(!e.clipboardData) return
  725. const clipboardDataItems = e.clipboardData.items
  726. const clipboardDataFirstItem = clipboardDataItems[0]
  727. if(clipboardDataFirstItem){
  728. for (const item of clipboardDataItems) {
  729. if (item.kind === 'file' && item.type.indexOf('image') !== -1) {
  730. const imageFile = item.getAsFile()
  731. if (imageFile) this.$refs[`pptPage_${this.currentIndex}`][0].handlePaste(imageFile,addPositions[0])
  732. return
  733. }
  734. }
  735. }
  736. //clipboardData中没有图片,从navigator.clipboard.read里获取图片
  737. let clipboardItems = null
  738. try{
  739. clipboardItems = await navigator.clipboard.read()
  740. }catch(error){
  741. this.$message.error(this.$t('Slides.unable_files_msg') )
  742. return
  743. }
  744. const blob = await checkClipboardItems(clipboardItems)
  745. this.$refs[`pptPage_${this.currentIndex}`][0].handlePaste(blob,addPositions[0])
  746. },300),
  747. //黏贴图片
  748. handlePasteImg:_.throttle(async function($event){
  749. /** $event:
  750. * position:1
  751. * src:base64格式的
  752. */
  753. //这里进行上传操作
  754. if(this.isChartLoading) return
  755. this.chartLoadingText = this.$t('Slides.uploading_images_msg')
  756. this.isChartLoading = true
  757. // 1走后端接口上传
  758. const uploadType=this.$setting.dynamicOutLinks.PptUpdateApi ||
  759. this.$store.state.dynamicOutLinks.PptUpdateApi ||
  760. JSON.parse(localStorage.getItem('dynamicOutLinks')).PptUpdateApi
  761. if(uploadType==1){
  762. const params = new FormData();
  763. params.append('Image',$event.src)
  764. const res = await dataBaseInterface.uploadImg(params);
  765. if(!res||res&&res.Ret!==200){
  766. this.isChartLoading = false
  767. return
  768. }
  769. const {Data} = res
  770. if(!Data){
  771. this.$message.warning("上传图片失败")
  772. this.isChartLoading = false
  773. return
  774. }
  775. this.imgUrl = Data.ResourceUrl||''
  776. }else{
  777. //直接走oss不走接口
  778. let clientType = this.$setting.dynamicOutLinks.ObjectStorageClient
  779. || this.$store.state.dynamicOutLinks.ObjectStorageClient
  780. || JSON.parse(localStorage.getItem('dynamicOutLinks')).ObjectStorageClient;
  781. let temName = `ppt/image/${new Date().getTime()}`
  782. const res = await uploadFileDirect(clientType,$event.src,temName)
  783. this.imgUrl = res;
  784. }
  785. //console.log('OK',$event)
  786. let temp_elements = this.addElement(
  787. this.currentItem.elements,
  788. [$event.position],
  789. "image",
  790. -1,
  791. ""
  792. );
  793. this.refleshElements(temp_elements)
  794. this.initImage(`#image_${this.currentIndex}_${$event.position}`,this.imgUrl)
  795. this.initPreviewPageEl()
  796. this.isChartLoading = false
  797. },300),
  798. //改变活跃页某一位置的文字
  799. handleChangeText({ position, text, richContent,pageItemId }) {
  800. //console.log('addText',this.currentItem.id,pageItemId)
  801. //处理初始化的场景
  802. if(this.currentItem.id!==pageItemId) return
  803. //如果该位置元素为空,说明文字编辑器没有初始化,添加一个元素
  804. if (
  805. this.currentItem.elements.findIndex((i) => i.position === position) ===
  806. -1
  807. ) {
  808. //console.log('addElement',this.currentItem)
  809. let tempEls = this.addElement(
  810. this.currentItem.elements,
  811. [position],
  812. "text",
  813. -1,
  814. { text, richContent }
  815. );
  816. this.refleshElements(tempEls);
  817. }
  818. this.currentItem.elements.map((i) => {
  819. if (i.position === position) {
  820. i.content = text;
  821. i.richContent = richContent;
  822. }
  823. });
  824. this.pageList[this.currentIndex] = this.currentItem;
  825. },
  826. //切换活跃页(currentItem)
  827. changeCurrentItem(item){
  828. const {id} = item
  829. //切换到其他活跃页的时候,需退出图层编辑模式
  830. if(this.currentItem&&this.currentItem.id!==id){
  831. this.isEditLayer = false
  832. this.activeLayerEl = {}
  833. this.isEditTitle = false
  834. this.isVersionHistory = false
  835. }
  836. //点击当前页时,退出标题编辑模式
  837. if(this.currentItem&&this.currentItem.id===id){
  838. this.isEditTitle = false
  839. this.isVersionHistory = false
  840. return
  841. }
  842. this.pageList.map((item,index)=>{
  843. if(item.id===id){
  844. this.currentItem = item
  845. this.currentIndex = index
  846. }
  847. })
  848. this.$nextTick(()=>{
  849. let height = $('.ppt-editor-item')[0].offsetHeight
  850. const index = this.currentIndex
  851. //pptEditor的滚动条动画
  852. const pptEditorDom = document.getElementById('pptEditor')
  853. pptEditorDom.scrollTo({
  854. top:height*index,
  855. left:0,
  856. behavior: 'smooth'
  857. })
  858. let listDomArr = $('.index-item')
  859. let heightSum = 0
  860. for(let i=0;i<this.currentIndex;i++){
  861. //console.log('height?',listDomArr[i].offsetHeight)
  862. heightSum+=listDomArr[i].offsetHeight+5
  863. }
  864. //console.log('index',this.currentIndex,'height',heightSum)
  865. //pptList的滚动条动画
  866. this.$refs.pptList.scrollTo({
  867. top:heightSum,
  868. left:0,
  869. behavior: 'smooth'
  870. })
  871. })
  872. },
  873. //获取图表列表
  874. async getreportlist(){
  875. let params = {
  876. Keyword: this.key_word,
  877. CurrentIndex: this.search_page,
  878. PageSize: this.search_page_sizes,
  879. IsShowMe: this.isShowMe
  880. }
  881. const apiMap = {
  882. 1: dataBaseInterface.chartSearchByEs,
  883. 2: futuresInterface.searchChart,
  884. 3: chartRelevanceApi.searchChart,
  885. 6: fittingEquationInterface.searchChart,
  886. 7: statisticFeatureInterface.searchChart,
  887. 10: crossVarietyInterface.searchChart,
  888. }
  889. let res = await apiMap[this.chart_source](params)
  890. if (res.Ret !== 200) return;
  891. res.Data.List = res.Data.List || [];
  892. this.chartList = this.search_page > 1 ? [...this.chartList,...res.Data.List] : res.Data.List;
  893. this.search_have_more = this.search_page <= res.Data.Paging.Pages;
  894. },
  895. loadReportHandle() {
  896. if(!this.search_have_more) return
  897. this.search_page++;
  898. this.getreportlist(this.key_word);
  899. },
  900. // 获取沙盘图列表 分页
  901. getSandTable(){
  902. this.sandTableLoading = true
  903. this.isRequesting = true
  904. sandInterface.sandlistByQuote(this.sandTabelQuery).then(({Data:{List,Paging}})=>{
  905. if(this.sandTabelQuery.CurrentIndex>1){
  906. this.sandTableList = [...this.sandTableList,...List]
  907. }else{
  908. this.sandTableList = List
  909. this.sandTableTotal = Paging.Totals
  910. console.log(this.sandTableList.length,this.sandTableTotal);
  911. if(this.sandTableList.length>=this.sandTableTotal){
  912. this.loadedText = this.$t('Slides.all_loaded_completely_text')
  913. }else{
  914. this.loadedText=''
  915. }
  916. }
  917. })
  918. .finally(()=>{
  919. this.sandTableLoading = false
  920. this.isRequesting = false
  921. })
  922. },
  923. // 沙盘列表滚动事件,触底加载下一页数据
  924. sandTableHandleScroll:_.debounce(function (e) {
  925. if(this.sandTableList.length>=this.sandTableTotal){
  926. this.loadedText = this.$t('Slides.all_loaded_completely_text')
  927. return
  928. }
  929. if(e.target.scrollHeight-e.target.clientHeight-e.target.scrollTop<10 && !this.isRequesting){
  930. this.sandTabelQuery.CurrentIndex++
  931. this.getSandTable()
  932. }
  933. },200),
  934. //点击右侧知识资源
  935. chooseKnowledge:_.throttle(async function(item){
  936. if(this.pageList.length===0||!this.currentItem){
  937. this.$message.warning(this.$t('Slides.please_add_page_msg') );
  938. return;
  939. }
  940. if(this.isChartLoading) return
  941. await this.$nextTick();
  942. // 判断当前页是否有文本元素框
  943. let v = defaultPosition[this.currentItem.modelId];
  944. if(!v) return;
  945. let arr = Object.entries(v);
  946. let textItem = arr.find(_=>_[1].type=="text");
  947. if(!textItem) return this.$message.warning('该页PPT无文本位置,无法插入');
  948. //寻找目标文本元素框
  949. let i = this.pageList.findIndex(_=>_.id == this.currentItem.id);
  950. let pageItemDom = this.$refs[`pptPage_${i}`] ? this.$refs[`pptPage_${i}`][0] : null;
  951. if(!pageItemDom) return;
  952. let textItemDom = pageItemDom.$refs[`${textItem[1].type}_${i}_${+textItem[0]}`];
  953. if(!textItemDom) return;
  954. this.isChartLoading = true;
  955. const res = await eventInterface.getEventDetail({
  956. ResourceType: item.ResourceType,
  957. KnowledgeResourceId: item.KnowledgeResourceId
  958. });
  959. this.isChartLoading = false;
  960. if(res.Ret != 200) return;
  961. let content = res.Data.Content || '';
  962. let allContent = `<p>${item.Title}</p>${content}`;
  963. textItemDom.content += allContent;
  964. },300),
  965. //点击右侧图表/沙盘图/表格
  966. chooseChart:_.throttle(async function(item,type){
  967. const noAuthMsg = {
  968. 'chart': this.$t('MsgPrompt.no_chart_auth'),
  969. 'sheet': this.$t('MsgPrompt.no_sheet_auth')
  970. }
  971. if(!item.HaveOperaAuth&&noAuthMsg[type]) return this.$message.warning(noAuthMsg[type])
  972. if(this.pageList.length===0||!this.currentItem){
  973. this.$message.warning(this.$t('Slides.please_add_page_msg') );
  974. return;
  975. }
  976. if(item.Disabled&&type==='chart') return this.$message.warning(this.$t('Slides.internal_chart_no_msg') )
  977. if(this.isChartLoading) return
  978. //获取当前活动页
  979. const { elements, modelId } = this.currentItem;
  980. //判断element是否能再加入图表
  981. const { isAdd, addPositions } = this.checkElements(
  982. modelId,
  983. elements,
  984. "chart"
  985. );
  986. if (!isAdd) {
  987. this.$message.warning(this.$t('Slides.delete_chart_img_table') );
  988. return;
  989. }
  990. let temp_elements = null;
  991. this.chartLoadingText = `${this.$t('Slides.loading_urgently')}...`
  992. // type:sandImage 沙盘图 chart 图表 sheet
  993. if(type=='chart'){
  994. //判断选择的图表是否已经插入
  995. this.isChartLoading = true
  996. await this.getchartData(item.UniqueCode);
  997. //加入图表
  998. temp_elements = this.addElement(
  999. elements,
  1000. addPositions,
  1001. "chart",
  1002. item.UniqueCode,
  1003. ""
  1004. );
  1005. this.chartNum++
  1006. this.refleshElements(temp_elements);
  1007. //优化一下
  1008. const tempEls = [{type:'chart',position:addPositions[0],chartId:item.UniqueCode}]
  1009. const tempPage = {id:this.currentItem.id,elements:tempEls}
  1010. //这里不直接用initChart是因为initCharts里可以判断该图表有没有数据,然后显示图表或显示“该图表已被删除”
  1011. this.initCharts(/* pageElements,page */tempEls,tempPage)
  1012. this.isChartLoading = false
  1013. //更新图表数据
  1014. let chartInfoMap = _.cloneDeep(this.$store.state.ppt.chartInfoMap)
  1015. let chartInfo = getChartInfo(this.optionMap[item.UniqueCode])
  1016. chartInfoMap[item.UniqueCode] = chartInfo
  1017. this.$store.commit('SET_CHART_INFO_MAP',chartInfoMap)
  1018. //需要重新渲染一次缩略图
  1019. this.initPreviewPageEl()
  1020. }else if(type === 'sandImage'){
  1021. // 插入沙盘图
  1022. this.imgUrl = item.PicUrl
  1023. this.isChartLoading = true
  1024. //加入沙盘图
  1025. temp_elements = this.addElement(
  1026. elements,
  1027. addPositions,
  1028. "image",
  1029. -1,
  1030. ""
  1031. );
  1032. this.refleshElements(temp_elements);
  1033. this.initImage(`#image_${this.currentIndex}_${addPositions[0]}`,this.imgUrl)
  1034. this.isChartLoading = false
  1035. this.initPreviewPageEl()
  1036. }
  1037. type === 'sheet' && this.insertSheet(item,elements,addPositions,temp_elements);
  1038. },300),
  1039. //检查是否还能再加入元素,返回{isAdd:bool,addPosition:[]},isAdd:是否能插入,addPositions:可以插入的位置
  1040. //type:[chart,text] chart包含除text外的全部元素
  1041. checkElements(modelId, elements, type) {
  1042. const info = modelInfo[modelId];
  1043. let addPositions = [],
  1044. isAdd = false;
  1045. const elPositions = elements.map((i) => i.position);
  1046. let typeNum = 0
  1047. elements.forEach(i=>{
  1048. if(i.type!=='text') typeNum++
  1049. })
  1050. //先判断长度
  1051. if (elements.length >= info.elNum) return { isAdd, addPositions };
  1052. //去重:info.positions和el
  1053. let tempArr = info.positions.filter((i) => elPositions.indexOf(i) < 0);
  1054. if (!tempArr.length) return { isAdd, addPositions };
  1055. //同一版式下的位置支持互换,位置和类型根据 当前版式.positionInfo决定
  1056. //判断数量
  1057. if(typeNum>=info.elChartNum){
  1058. return { isAdd, addPositions };
  1059. }
  1060. const positionInfo = this.$refs[`pptPage_${this.currentIndex}`][0].positionInfo
  1061. //判断类型
  1062. tempArr.forEach((i)=>{
  1063. if(positionInfo[i].type!=='text'){
  1064. addPositions.push(i)
  1065. }
  1066. })
  1067. if (!addPositions.length) {
  1068. return { isAdd, addPositions };
  1069. } else {
  1070. isAdd = true;
  1071. return { isAdd, addPositions };
  1072. }
  1073. },
  1074. //添加一个元素进els,type:[chart,text,image],chart时有chartId,text为空;text/image时,chartId为-1
  1075. addElement(
  1076. el,
  1077. positions,
  1078. type,
  1079. UniqueCode,
  1080. { text, richContent } = { text: "", richContent: "" }
  1081. ) {
  1082. let temp = null;
  1083. if (type === "chart") {
  1084. temp = {
  1085. type: "chart",
  1086. position: positions[0],
  1087. chartId: UniqueCode,
  1088. };
  1089. } else if (type === "text") {
  1090. temp = {
  1091. type: "text",
  1092. position: positions[0],
  1093. content: text,
  1094. richContent: richContent,
  1095. };
  1096. }else if (type==='image'){
  1097. temp = {
  1098. type:'image',
  1099. position:positions[0],
  1100. src:this.imgUrl
  1101. }
  1102. }else if(type==='sheet'){
  1103. temp={
  1104. type:'sheet',
  1105. position:positions[0],
  1106. sheetId:UniqueCode
  1107. }
  1108. }
  1109. el.push(temp);
  1110. return el;
  1111. },
  1112. // 版本记录列表
  1113. handleVersionHistory(item) {
  1114. this.isVersionHistory = true;
  1115. },
  1116. //
  1117. async handleRestore(Id) {
  1118. let res = await pptInterface.getPptHistoryRevert({
  1119. Id
  1120. });
  1121. if (res.Ret !== 200) return;
  1122. this.$message.success('恢复成功!');
  1123. this.init()
  1124. },
  1125. //更新ppt页元素(数据)
  1126. refleshElements(els){
  1127. this.currentItem.elements = els;
  1128. this.pageList[this.currentIndex] = this.currentItem;
  1129. this.$refs[`pptPage_${this.currentIndex}`][0].initPositionInfo()
  1130. },
  1131. //手动保存PPT
  1132. async handleSave(type){
  1133. //保存走save_checkPPT,发布走checkPPT
  1134. let checkResult = null
  1135. if(type==='save'){
  1136. checkResult = this.save_checkPPT()
  1137. }else{
  1138. checkResult = this.checkPPT()
  1139. }
  1140. if(!checkResult.result){
  1141. this.$message.warning(checkResult.hintText)
  1142. return checkResult
  1143. }
  1144. let Content = JSON.stringify(this.pageList)
  1145. const {Title,ReportType,PptDate,BackgroundImg,BackIndex,CurrentBackgroundImg,BackCoverImg, BackCoverImgId,BackgroundImgId,CurrentBackgroundImgId} = this.firstPage
  1146. const FirstPage = {
  1147. Title,ReportType,PptDate,BackIndex,BackCoverImg,CurrentBackgroundImg,BackCoverImgId,BackgroundImgId,CurrentBackgroundImgId,
  1148. ImgUrl:BackgroundImg,
  1149. TemplateType:BackIndex+1
  1150. }
  1151. this.isSaved = true
  1152. if(this.$route.query.id||this.pptId){
  1153. await this.editPPT(FirstPage,Content,type)
  1154. }else{
  1155. // await this.addPPT(FirstPage,Content)
  1156. }
  1157. },
  1158. async addPPT(FirstPage,Content){
  1159. await pptInterface.addppt({
  1160. FirstPage:FirstPage,
  1161. Content:Content,
  1162. GroupId:this.catalogId,
  1163. CoverContent:this.CoverContent,
  1164. TitleSetting:JSON.stringify(this.titleSetting)
  1165. }).then(res=>{
  1166. this.isSaved = false
  1167. if(res.Ret===200){
  1168. this.$message.success(this.$t('MsgPrompt.add_msg'))
  1169. this.isSave = true
  1170. this.pptId = res.Data.PptId
  1171. sessionStorage.removeItem('selectedCatalog')
  1172. //开启自动保存
  1173. this.autoSave()
  1174. }
  1175. })
  1176. },
  1177. async editPPT(FirstPage,Content,type){
  1178. //console.log(type)
  1179. const ppt_id = this.$route.query.id||this.pptId
  1180. await pptInterface.editppt({
  1181. PptId:parseInt(ppt_id),
  1182. FirstPage:FirstPage,
  1183. Content:Content,
  1184. CoverContent:this.CoverContent,
  1185. TitleSetting:JSON.stringify(this.titleSetting)
  1186. }).then(res=>{
  1187. this.isSaved = false
  1188. if(res.Ret===200){
  1189. if(type==='save'){
  1190. this.$message.success(this.$t('MsgPrompt.edit_msg'))
  1191. }
  1192. this.isSave = true
  1193. this.pptId = res.Data.PptId
  1194. //如果ppt已转成双周报,则更新
  1195. }
  1196. })
  1197. },
  1198. //自动保存PPT
  1199. autoSave(){
  1200. if(this.loopTimer) return
  1201. if(!this.$route.query.id&&!this.pptId) return
  1202. this.loopTimer = setInterval(()=>{
  1203. //如果当前在刷新图表,则不进行自动保存
  1204. if(this.refreshBtnLoading) return
  1205. const ppt_id = this.$route.query.id||this.pptId
  1206. const {Title,ReportType,PptDate,BackgroundImg,BackIndex,CurrentBackgroundImg,BackCoverImg,BackCoverImgId,BackgroundImgId,CurrentBackgroundImgId} = this.firstPage
  1207. const FirstPage = {
  1208. Title,ReportType,PptDate,BackIndex,CurrentBackgroundImg,BackCoverImg,CurrentBackgroundImg,BackCoverImgId,BackgroundImgId,CurrentBackgroundImgId,
  1209. ImgUrl:BackgroundImg,
  1210. TemplateType:BackIndex+1
  1211. }
  1212. //防止自动保存时,有某一页处于更新图表的状态,其isUpdating为true
  1213. let pageList = this.pageList.map(i=>{
  1214. i.isUpdating = false
  1215. return i
  1216. })
  1217. let Content = JSON.stringify(pageList)
  1218. let TitleSetting = JSON.stringify(this.titleSetting)
  1219. pptInterface.saveLog({
  1220. PptId:parseInt(ppt_id),
  1221. FirstPage:FirstPage,
  1222. Content:Content,
  1223. CoverContent:this.CoverContent,
  1224. TitleSetting,
  1225. }).then((res)=>{
  1226. if(res.Ret!==200) return
  1227. this.showLastSaveTime = true
  1228. this.lastSaveTime = http.dateFormatter(new Date(), true);
  1229. })
  1230. },10000)
  1231. },
  1232. //保存时的校验规则:封面信息,至少一页
  1233. save_checkPPT(){
  1234. if(!this.firstPage.BackgroundImg){
  1235. return {result:false,hintText:'请选择封面页!'}
  1236. }
  1237. if(!this.firstPage.Title){
  1238. return {result:false,hintText:this.$t('Slides.please_input_cover_title')+'!'}
  1239. }
  1240. if(this.pageList.length===0){
  1241. return {result:false,hintText:this.$t('Slides.least_one_ppt_msg') }
  1242. }
  1243. return {result:true,hintText:''}
  1244. },
  1245. //发布时的校验规则:封面信息,每一页标题及内容
  1246. checkPPT(){
  1247. if(!this.firstPage.BackgroundImg){
  1248. return {result:false,hintText:'请选择封面页!'}
  1249. }
  1250. //检验首页
  1251. if(!this.firstPage.Title){
  1252. return {result:false,hintText:this.$t('Slides.please_input_cover_title')+'!'}
  1253. }
  1254. if(this.pageList.length===0){
  1255. return {result:false,hintText:this.$t('Slides.least_one_ppt_msg') }
  1256. }
  1257. //检验每一页
  1258. for(let i=0;i<this.pageList.length;i++){
  1259. if(!this.pageList[i].title||this.pageList[i].title==='<br>'){
  1260. return {result:false,hintText:this.$t('Slides.please_ppt_title_msg',{count:i+1}) }
  1261. }
  1262. //无内容
  1263. if(this.pageList[i].elements.length===0){
  1264. return {result:false,hintText:this.$t('Slides.please_ppt_content_msg',{count:i+1}) }
  1265. }
  1266. //有文本框,但是文本框无内容
  1267. }
  1268. return {result:true,hintText:''}
  1269. },
  1270. async handlePublish(){
  1271. //ETA1.7.5更改发布逻辑,点击发布时,自动执行保存操作,若可保存,则跳转发布页
  1272. const res = await this.handleSave('pub')
  1273. if(res&&!res.result) return
  1274. //ppt4.0后,合并后的PPT可能会超出页数or图表限制,在这里做个校验
  1275. if(this.pageList.length>this.maxPageNum){
  1276. this.$message.warning(this.$t('Slides.most_add_ppt_msg',{count:this.maxPageNum}))
  1277. return
  1278. }
  1279. if(this.chartNum>this.maxPageChart){
  1280. this.$message.warning(this.$t('Slides.most_add_chart_msg',{count:this.maxPageChart}));
  1281. return;
  1282. }
  1283. this.pptId&&this.$router.push({path:'/pptpublish',query:{id:this.pptId}})
  1284. },
  1285. //拖动相关
  1286. dragstart(e,value) {
  1287. e.dataTransfer.effectAllowed = "move";
  1288. this.oldNum = value;
  1289. },
  1290. dragend() {
  1291. let oldIndex = this.pageList.findIndex(_ => _.id ===this.oldNum.id);
  1292. let newIndex = this.pageList.findIndex(_ => _.id ===this.newNum.id);
  1293. // console.log(oldIndex,newIndex)
  1294. let tempOption = _.cloneDeep(this.pageList[newIndex])
  1295. if(oldIndex !== newIndex) {
  1296. this.$set(this.pageList, newIndex, this.pageList[oldIndex])
  1297. this.$set(this.pageList, oldIndex, tempOption)
  1298. this.$message.success(this.$t('Slides.move_success_msg') )
  1299. }
  1300. this.currentIndex = this.pageList.findIndex(_ => _.id ===this.currentItem.id);
  1301. },
  1302. dragenter(e,value) {
  1303. e.preventDefault()
  1304. this.newNum = value;
  1305. },
  1306. changePageIndex($event){
  1307. this.oldNum = this.pageList[$event.oldPos-1]
  1308. this.newNum = this.pageList[$event.newPos-1]
  1309. this.dragend()
  1310. },
  1311. /* 搜索表格 */
  1312. getSheetList() {
  1313. sheetInterface
  1314. .sheetList({
  1315. Keyword: this.sheetSearchObj.Keyword,
  1316. CurrentIndex: 1,
  1317. PageSize: 10000
  1318. })
  1319. .then((res) => {
  1320. if (res.Ret !== 200) return
  1321. this.sheetSearchList = res.Data.List || [];
  1322. });
  1323. },
  1324. /* 插入表格 */
  1325. async insertSheet({ExcelImage,UniqueCode},elements,addPositions,temp_elements) {
  1326. // 插入沙盘图
  1327. this.imgUrl = ExcelImage;
  1328. this.isChartLoading = true
  1329. const idName = `sheet_${this.currentIndex}_${addPositions[0]}`
  1330. const res = await this.getsheetData(UniqueCode)
  1331. if(!res) {
  1332. this.isChartLoading = false
  1333. return
  1334. }
  1335. //加入表格
  1336. temp_elements = this.addElement(
  1337. elements,
  1338. addPositions,
  1339. "sheet",
  1340. UniqueCode,
  1341. ""
  1342. );
  1343. this.refleshElements(temp_elements);
  1344. this.initSheet(this.$refs[`pptPage_${this.currentIndex}`][0],idName,UniqueCode,'insert')
  1345. this.isChartLoading = false
  1346. this.initPreviewPageEl()
  1347. },
  1348. //打开批量删除弹窗
  1349. openDeletePageDialog(){
  1350. //添加一页才能打开弹窗
  1351. if(this.pageList.length===0){
  1352. this.$message.warning(this.$t('Slides.please_add_one_page') )
  1353. return
  1354. }
  1355. this.deletePageShow = true
  1356. },
  1357. async handleDeletePages(list){
  1358. this.$refs.deletePage.loadingText= this.$t('Slides.deleting_process_loading')
  1359. this.$refs.deletePage.dataLoading=true
  1360. this.deletePages(list)
  1361. },
  1362. //批量删除
  1363. deletePages(list){
  1364. let temp = this.pageList.filter((item,index)=>{
  1365. if(!list.includes(index)){
  1366. return item
  1367. }
  1368. })
  1369. this.pageList = temp
  1370. this.currentIndex=0
  1371. if(this.pageList.length>0){
  1372. this.changeCurrentItem(this.pageList[0])
  1373. }else{
  1374. this.currentItem=null
  1375. }
  1376. //删除后,需要重新计算图表数
  1377. let newChartNum = 0
  1378. for(let i=0;i<this.pageList.length;i++){
  1379. const page = this.pageList[i]
  1380. page.elements.forEach(item=>{
  1381. if(item.type==='chart'){
  1382. newChartNum++
  1383. }
  1384. })
  1385. }
  1386. this.chartNum = newChartNum
  1387. this.$nextTick(()=>{
  1388. this.$refs.deletePage.dataLoading = false
  1389. this.deletePageShow = false
  1390. this.$message.success(this.$t('Slides.batch_deletion_successful'))
  1391. })
  1392. },
  1393. initPreviewPageEl(type,page){
  1394. const currentItem = page||this.currentItem
  1395. const isLoaded = this.$refs.deletePage.isLoaded
  1396. if(isLoaded){
  1397. type!=='delete'&&this.$refs.deletePage.$refs[`preview_${this.currentIndex}`][0].initPositionInfo()
  1398. this.$refs.deletePage.initPreviewEl(currentItem)
  1399. }
  1400. },
  1401. reloadPage({id,positionInfo}){
  1402. const index = this.pageList.findIndex(i=>i.id===id)
  1403. this.pageList[index].key++
  1404. this.pageList[index].positionInfo = positionInfo
  1405. this.initPageElements(this.pageList[index])
  1406. this.initPreviewPageEl()
  1407. },
  1408. },
  1409. updated(){
  1410. $('.ppt-item').css('height',$('.ppt-item').width()*0.7);
  1411. $('.ppt-item').css('background-image',`url(${this.firstPage.CurrentBackgroundImg})`);
  1412. window.onresize = ()=>{
  1413. $('.ppt-item').css('height',$('.ppt-item').width()*0.7);
  1414. }
  1415. },
  1416. destroyed(){
  1417. sessionStorage.removeItem('selectedCatalog')
  1418. window.removeEventListener('message',this.reInitIframe)
  1419. window.onresize=null
  1420. if(this.loopTimer) clearInterval(this.loopTimer)
  1421. }
  1422. };
  1423. </script>
  1424. <style lang="scss">
  1425. @import './css/common.scss';
  1426. @import './css/format.scss';
  1427. </style>
  1428. <style scoped lang="scss">
  1429. $titleColor:#333333;
  1430. .page-wrap{
  1431. display: flex;
  1432. width: 100%;
  1433. overflow-x: scroll;
  1434. &::-webkit-scrollbar-track{
  1435. display: none;
  1436. }
  1437. div::-webkit-scrollbar-track{
  1438. display: none;
  1439. }
  1440. .index-wrap{
  1441. min-width: 280px;
  1442. margin-right: 10px;
  1443. padding:10px;
  1444. .cover-wrap{
  1445. cursor: pointer;
  1446. width: 100%;
  1447. margin-bottom: 10px;
  1448. .cover{
  1449. //高:宽 0.75
  1450. height: 195px;
  1451. display: flex;
  1452. justify-content: center;
  1453. align-items: center;
  1454. background-size: 100% 100% !important;
  1455. }
  1456. }
  1457. .hint-box{
  1458. color:#409EFF;
  1459. display: flex;
  1460. justify-content: flex-end;
  1461. align-items: center;
  1462. margin-bottom:10px;
  1463. }
  1464. .hint{
  1465. border: 1px solid transparent;
  1466. cursor: pointer;
  1467. padding:5px;
  1468. &:hover{
  1469. border: 1px solid #409EFF;
  1470. border-radius: 4px;
  1471. background: #ECF5FF;
  1472. }
  1473. }
  1474. .index-list{
  1475. //margin-top: 10px;
  1476. flex: 1;
  1477. overflow-y: scroll;
  1478. .empty{
  1479. margin-top:120px;
  1480. text-align: center;
  1481. img{
  1482. width:76px;
  1483. height:76px;
  1484. display: inline-block;
  1485. }
  1486. p{
  1487. font-size: 14px;
  1488. color: $titleColor;
  1489. }
  1490. }
  1491. }
  1492. }
  1493. .ppt-editor-wrap{
  1494. flex:1;
  1495. /* min-width: 1370px; */
  1496. padding:20px;
  1497. display: flex;
  1498. .ppt-editor{
  1499. flex:1;
  1500. /* max-width: 980px;
  1501. min-width:776px; */
  1502. max-width: 980px;
  1503. min-width: 980px;
  1504. height:100%;
  1505. /* background-color: pink; */
  1506. background-color: #fff;
  1507. border:2px solid #EBEBEB;
  1508. border-radius: 4px;
  1509. margin-right: 30px;
  1510. overflow-y: scroll;
  1511. position:relative;
  1512. .ppt-editor-item {
  1513. position: relative;
  1514. align-items: center;
  1515. .ppt-item {
  1516. //padding 两边 40 减掉边框两边 8 max-width:100% - 32px
  1517. width:calc(100% - 64px);
  1518. background: transparent;
  1519. background-size: 100% 100%;
  1520. /* margin-bottom: 30px; */
  1521. position: relative;
  1522. border: 4px solid transparent;
  1523. cursor: pointer;
  1524. &.choose {
  1525. border: 4px solid rgba($color: #4B8DFF, $alpha: 0.7);
  1526. }
  1527. .close-btn{
  1528. color:#BDBDBD;
  1529. width:20px;
  1530. height:20px;
  1531. position:absolute;
  1532. cursor: pointer;
  1533. top:-10px;
  1534. right:-10px;
  1535. background: url('~@/assets/img/ppt_m/ppt-del.png') no-repeat center/cover;
  1536. background-color: white;
  1537. border-radius: 50%;
  1538. }
  1539. .page-num{
  1540. color:#666666;
  1541. position:absolute;
  1542. bottom:10px;
  1543. right:20px;
  1544. }
  1545. .update-btn{
  1546. position:absolute;
  1547. top:16px;
  1548. left:12px;
  1549. color:#409EFF;
  1550. cursor: pointer;
  1551. display: flex;
  1552. justify-content: center;
  1553. .update-ico{
  1554. width:20px;
  1555. height:20px;
  1556. background:url('~@/assets/img/ppt_m/update-ico.png') no-repeat center/cover;
  1557. margin-right: 4px;
  1558. }
  1559. }
  1560. .loading-cover{
  1561. position: absolute;
  1562. top:20px;
  1563. left:0;
  1564. height:20px;
  1565. background-color: #409EFF;
  1566. }
  1567. }
  1568. }
  1569. }
  1570. .ppt-tool{
  1571. min-width:320px;
  1572. width: 320px;
  1573. height:100%;
  1574. overflow-y: hidden;
  1575. .richtext-tool{
  1576. margin:10px 0;
  1577. }
  1578. .addppt-right-box{
  1579. flex: 1;
  1580. /* height: calc(100% - 182px); */
  1581. padding: 0 10px;
  1582. box-sizing: border-box;
  1583. border: 2px solid #EBEBEB;
  1584. border-radius: 4px;
  1585. min-width: 320px;
  1586. overflow-y: auto;
  1587. #tabs {
  1588. padding: 0px 40px;
  1589. box-sizing: border-box;
  1590. margin: 15px 0;
  1591. overflow: hidden;
  1592. > p {
  1593. float: left;
  1594. width: 50%;
  1595. font-size: 18px;
  1596. cursor: pointer;
  1597. color: #1f2e4d;
  1598. padding: 10px 0;
  1599. text-align: center;
  1600. }
  1601. > p.active {
  1602. border-bottom: 2px solid #3464e0;
  1603. color: #3464e0;
  1604. }
  1605. }
  1606. .chart-tool{
  1607. flex: 1;
  1608. margin-top: 10px;
  1609. height: calc(100% - 80px);
  1610. .chart-search{
  1611. margin-bottom: 10px;
  1612. }
  1613. .chart-list{
  1614. flex: 1;
  1615. border:2px solid #EBEBEB;
  1616. border-radius: 4px;
  1617. overflow-y: scroll;
  1618. text-align: center;
  1619. .chart-item {
  1620. cursor: pointer;
  1621. text-align: center;
  1622. color: #74818d;
  1623. font-size: 18px;
  1624. margin-bottom: 10px;
  1625. padding:10px;
  1626. img {
  1627. width: 100%;
  1628. }
  1629. }
  1630. .sandTable-item{
  1631. border-bottom: solid 1px #eeeeee;
  1632. padding: 20px 0 10px 0;
  1633. p{
  1634. font-size: 16px;
  1635. color: #3464e0;
  1636. text-align: center;
  1637. }
  1638. img{
  1639. cursor: pointer;
  1640. }
  1641. }
  1642. .loaded-text{
  1643. height: 20px;
  1644. text-align: center;
  1645. color: #666;
  1646. font-size: 14px;
  1647. }
  1648. }
  1649. }
  1650. }
  1651. .layer-edit-box,.title-edit-box{
  1652. flex: 1;
  1653. padding: 0 20px;
  1654. box-sizing: border-box;
  1655. border: 2px solid #EBEBEB;
  1656. border-radius: 4px;
  1657. min-width: 320px;
  1658. overflow-y: auto;
  1659. .tool-list{
  1660. .el-wrap{
  1661. display: flex;
  1662. gap: 0 15px;
  1663. flex-wrap: wrap;
  1664. .el-item{
  1665. border: 1px solid #DCDFE6;
  1666. border-radius: 4px;
  1667. width:55px;
  1668. height:55px;
  1669. margin-bottom: 20px;
  1670. display: flex;
  1671. justify-content: center;
  1672. align-items: center;
  1673. cursor: pointer;
  1674. &:hover,&.active{
  1675. border: 1px solid #409EFF;
  1676. }
  1677. }
  1678. }
  1679. .el-collapse-item__wrap{
  1680. overflow: visible;
  1681. }
  1682. }
  1683. }
  1684. .title-edit-box{
  1685. display:flex;
  1686. flex-direction: column;
  1687. padding:20px;
  1688. p{
  1689. font-size: 16px;
  1690. font-weight: bold;
  1691. }
  1692. }
  1693. }
  1694. }
  1695. .flex-align{
  1696. display:flex;
  1697. align-items: center;
  1698. }
  1699. }
  1700. </style>