pptEditor.vue 71 KB

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