Graphics.vue 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559
  1. <template>
  2. <div class="graphics">
  3. <div class="group-asset">
  4. <t-radio-group
  5. v-model="activeAssets"
  6. @change="assetsChange"
  7. variant="primary-filled"
  8. >
  9. <t-radio-button value="system">系统资源</t-radio-button>
  10. <t-radio-button value="user">我的资源</t-radio-button>
  11. </t-radio-group>
  12. </div>
  13. <div class="groups-panel">
  14. <div class="groups">
  15. <div
  16. v-for="group in groups"
  17. :class="group.name === activedGroup ? 'active' : ''"
  18. @click="groupChange(group.name)"
  19. >
  20. <template v-if="group.type === 'iconfont'">
  21. <i class="l-icon" :class="group.icon"> </i>
  22. {{ group.name }}
  23. </template>
  24. <template v-else>
  25. <!-- <t-icon :name="group.icon" /> -->
  26. <DesktopIcon v-if="group.icon==='desktop'" />
  27. <RootListIcon v-else-if="group.icon==='root-list'"/>
  28. <ImageIcon v-else-if="group.icon==='image'"/>
  29. <ControlPlatformIcon v-else-if="group.icon==='control-platform'"/>
  30. <ChartIcon v-else-if="group.icon==='chart'"/>
  31. <RelativityIcon v-else-if="group.icon==='relativity'"/>
  32. <ChartBubbleIcon v-else-if="group.icon==='chart-bubble'"/>
  33. {{ group.name }}
  34. </template>
  35. </div>
  36. </div>
  37. <div class="list" :class="groupType ? 'two-columns' : ''">
  38. <div class="input-search">
  39. <div class="btn">
  40. <!-- <t-icon name="search" /> -->
  41. <img src="/img/icon_search_gray.svg" />
  42. </div>
  43. <t-input
  44. v-model="search"
  45. @change="onSearch"
  46. @enter="onSearch"
  47. placeholder="搜索"
  48. />
  49. <div class="ml-16">
  50. <t-tooltip content="展开/折叠">
  51. <menu-fold-icon class="hover"
  52. style="font-size: 16px"
  53. @click="onFold"/>
  54. <!-- <t-icon
  55. name="menu-fold"
  56. class="hover"
  57. style="font-size: 16px"
  58. @click="onFold"
  59. /> -->
  60. </t-tooltip>
  61. </div>
  62. </div>
  63. <div v-if="loading" class="center mt-16">
  64. <t-loading text="加载中..." size="small" :indicator="false" />
  65. </div>
  66. <template v-else>
  67. <div
  68. v-if="
  69. activedGroup === '图片' ||
  70. (activeAssets === 'user' &&
  71. (activedGroup === '方案' || activedGroup === '模板' || activedGroup === '组件'))
  72. "
  73. class="px-16 mt-12 mb-8 ml-4"
  74. >
  75. <a @click="onCreateFolder">+ 新建文件夹</a>
  76. </div>
  77. <t-collapse v-model="activedPanels[activedGroup]">
  78. <t-collapse-panel
  79. :value="item.name"
  80. v-for="item in subGroups"
  81. :key="item.name"
  82. >
  83. <template #header>
  84. <div class="flex middle">
  85. <div v-if="item.edited" @click.stop>
  86. <t-input
  87. v-model="item.label"
  88. style="width: 140px"
  89. @blur="createFoder"
  90. @enter="createFoder"
  91. @keyup="onKeyHeader"
  92. :autofocus="true"
  93. />
  94. </div>
  95. <div v-else>
  96. {{ item.name }}
  97. </div>
  98. </div>
  99. </template>
  100. <template #headerRightContent>
  101. <t-space size="small" @click.stop tabindex="0">
  102. <t-upload
  103. v-if="item.canEdited && activedGroup === '图片'"
  104. action="/api/image/upload"
  105. accept="image/*"
  106. :headers="headers"
  107. :data="{
  108. directory: `/大屏/${activedGroup}/${item.name}`,
  109. conflict:'new'
  110. }"
  111. :auto-upload="true"
  112. :upload-all-files-in-one-request="false"
  113. :before-upload="beforeUpload"
  114. @selectChange="onSelectFiles(item)"
  115. allowUploadDuplicateFile
  116. @success="fileSuccessed"
  117. theme="custom"
  118. >
  119. <image-icon class="hover" />
  120. <!-- <t-icon name="image" class="hover" /> -->
  121. </t-upload>
  122. <template v-if="item.canEdited">
  123. <add-icon v-if="['组件', '方案', '模板'].includes(activedGroup)" class="hover"
  124. @click="onAdd(item)"/>
  125. <!-- <t-icon
  126. v-if="['组件', '方案', '模板'].includes(activedGroup)"
  127. name="add"
  128. class="hover"
  129. @click="onAdd(item)"
  130. /> -->
  131. <edit-icon class="hover"
  132. @click="onEditHeader(item)"/>
  133. <!-- <t-icon
  134. name="edit"
  135. class="hover"
  136. @click="onEditHeader(item)"
  137. /> -->
  138. <t-popconfirm
  139. content="确认删除该文件夹吗"
  140. placement="left"
  141. @confirm="delFolder(item)"
  142. >
  143. <delete-icon class="hover"/>
  144. <!-- <t-icon name="delete" class="hover" /> -->
  145. </t-popconfirm>
  146. </template>
  147. </t-space>
  148. </template>
  149. <template v-for="elem in item.list">
  150. <div
  151. v-show="elem.visible !== false"
  152. class="graphic"
  153. :draggable="true"
  154. @dragstart="dragStart($event, elem)"
  155. @click.stop="dragStart($event, elem)"
  156. @dblclick.stop="open(elem)"
  157. @contextmenu="onContextMenu($event, item, elem)"
  158. @touchstart.passive="dragStart($event, elem)"
  159. >
  160. <!-- img 路径这样拼凑避免更新后路径一致图片使用缓存不更新 -->
  161. <t-image
  162. v-if="!elem.svg && elem.image"
  163. :src="elem.image + '?' + Math.random()"
  164. :lazy="true"
  165. fit="contain"
  166. @load="loadImage(elem)"
  167. />
  168. <div class="svg-box" v-else-if="elem.svg" v-html="elem.svg" />
  169. <svg v-else class="l-icon" aria-hidden="true">
  170. <use :xlink:href="'#' + elem.icon"></use>
  171. </svg>
  172. <p :title="elem.name">{{ elem.name }}</p>
  173. <div class="price" v-if="elem.price > 0">
  174. ¥{{ elem.price }}
  175. </div>
  176. </div>
  177. </template>
  178. <div
  179. v-if="!item.list || !item.list.length"
  180. class="gray"
  181. style="white-space: nowrap; margin-left: 34px"
  182. >
  183. 暂无数据
  184. </div>
  185. </t-collapse-panel>
  186. </t-collapse>
  187. </template>
  188. <div class="div-manage" v-if="['图元', '素材'].includes(activedGroup)">
  189. <t-button
  190. class="w-full"
  191. @click="onManageGraphic"
  192. style="height: 30px;color:var(--color) !important;"
  193. >
  194. {{ activedGroup }}管理
  195. </t-button>
  196. </div>
  197. </div>
  198. </div>
  199. <div
  200. class="context-menu-box"
  201. ref="contextmenuDom"
  202. v-show="contextmenu.visible"
  203. tabindex="0"
  204. :style="contextmenu.style"
  205. @blur="hideContextmenu"
  206. >
  207. <t-menu
  208. class="context-menu"
  209. @change="onMenu"
  210. expandType="popup"
  211. v-model="contextmenu.activeValue"
  212. >
  213. <t-submenu
  214. value="moveTo"
  215. :title="`移动到${activedGroup==='方案'?'模板':'方案'}`"
  216. v-if="['方案', '模板'].includes(activedGroup)"
  217. :disabled="contextmenu.component['3d']"
  218. >
  219. <t-menu-item
  220. v-for="subMenu in moveGroups[activedGroup==='方案'?'模板':'方案']"
  221. :value="'moveTo:' + subMenu.name"
  222. >
  223. {{ subMenu.name }}
  224. </t-menu-item>
  225. </t-submenu>
  226. <t-submenu
  227. value="move"
  228. title="移动到"
  229. v-if="contextmenu.subMenus.length"
  230. :disabled="contextmenu.component['3d']"
  231. >
  232. <t-menu-item
  233. v-for="subMenu in contextmenu.subMenus"
  234. :value="'move:' + subMenu.name"
  235. >
  236. {{ subMenu.name }}
  237. </t-menu-item>
  238. </t-submenu>
  239. <t-menu-item value="edit" :disabled="activedGroup === '图片'">
  240. 编辑
  241. </t-menu-item>
  242. <t-menu-item value="del" :disabled="contextmenu.component['3d']">
  243. 删除
  244. </t-menu-item>
  245. </t-menu>
  246. </div>
  247. <t-dialog
  248. v-if="delDialog.show"
  249. theme="danger"
  250. header="删除"
  251. :visible="true"
  252. @close="delDialog.show = false"
  253. @confirm="delComponent"
  254. >
  255. 确定删除该数据吗?删除后不可恢复!
  256. </t-dialog>
  257. <!-- <t-dialog
  258. v-if="chargeDialog.show"
  259. :header="chargeDialog.data.name"
  260. :visible="true"
  261. @close="chargeDialog.show = false"
  262. width="70%"
  263. :top="8"
  264. >
  265. <t-image :src="chargeDialog.data.image" />
  266. <template #footer>
  267. <div class="flex between" style="margin-top: -7px">
  268. <p>付费项目,购买后查看并使用</p>
  269. <div>
  270. <label>金额:</label>
  271. <label class="bland">¥{{ chargeDialog.data.price }}</label>
  272. <t-button class="primary ml-12" @click="onSubmitOrder"
  273. >购买</t-button
  274. >
  275. </div>
  276. </div>
  277. </template>
  278. </t-dialog> -->
  279. <t-dialog
  280. class="dialog-charge"
  281. v-if="chargeDialogShow"
  282. :header="chargeDialog.name"
  283. :visible="true"
  284. @close="chargeDialogShow = false"
  285. width="80%"
  286. :top="8"
  287. :footer="false"
  288. :closeOnOverlayClick="false"
  289. >
  290. <iframe
  291. :src="`/enterprise/preview?product=v&id=${chargeDialog.data.id}`"
  292. frameborder="no"
  293. scrolling="no"
  294. allowtransparency="true"
  295. />
  296. </t-dialog>
  297. <t-dialog
  298. v-if="wechatPayDialog.show"
  299. v-model:visible="wechatPayDialog.show"
  300. class="pay-dialog"
  301. header="乐吾乐收银台"
  302. :close-on-overlay-click="false"
  303. :top="95"
  304. :width="700"
  305. confirm-btn="支付完成"
  306. :cancel-btn="null"
  307. @close="getPayResult"
  308. :footer="false"
  309. >
  310. <Pay
  311. :order="wechatPayDialog.order"
  312. :alipay-url="wechatPayDialog.order.alipayUrl"
  313. :code-url="wechatPayDialog.order.codeUrl"
  314. @success="onChargeSuccess"
  315. />
  316. </t-dialog>
  317. <t-dialog
  318. class="dialog-manage"
  319. :header="activedGroup + '管理'"
  320. :visible="manageDialog.show"
  321. @close="manageDialog.show = false"
  322. @confirm="manageConfirm"
  323. width="90%"
  324. :top="8"
  325. >
  326. <div class="manage-body">
  327. <t-collapse v-model="activedPanels[activedGroup]">
  328. <t-collapse-panel
  329. :value="item.name"
  330. v-for="item in manageDialog.data"
  331. :key="item.name"
  332. >
  333. <template #header>
  334. <div class="flex middle">
  335. {{ item.name }}
  336. </div>
  337. </template>
  338. <template v-for="elem in item.list">
  339. <div
  340. :style="{
  341. background: elem.visible ? '#42516c' : '',
  342. }"
  343. class="graphic manage-list"
  344. >
  345. <t-checkbox v-model:checked="elem.visible"></t-checkbox>
  346. <t-image
  347. :src="elem.image"
  348. :lazy="true"
  349. fit="contain"
  350. @load="loadImage(elem)"
  351. />
  352. </div>
  353. </template>
  354. <div
  355. v-if="!item.list || !item.list.length"
  356. class="gray"
  357. style="white-space: nowrap; margin-left: 34px"
  358. >
  359. 暂无数据
  360. </div>
  361. </t-collapse-panel>
  362. </t-collapse>
  363. </div>
  364. </t-dialog>
  365. </div>
  366. </template>
  367. <script lang="ts" setup>
  368. import { onMounted, onUnmounted, reactive, ref } from 'vue';
  369. import { useRouter } from 'vue-router';
  370. import { MessagePlugin } from 'tdesign-vue-next';
  371. import axios from 'axios';
  372. import { deepClone } from '@meta2d/core';
  373. import { cases, shapes, formComponents, templates } from '@/services/defaults';
  374. import { charts } from '@/services/echarts';
  375. import { getFolders, makeSvg } from '@/services/png';
  376. import {
  377. addCollection,
  378. delImage,
  379. getComponentsList,
  380. getLe5leV,
  381. updateCollection,
  382. getCollectionList,
  383. imageDrive,
  384. } from '@/services/api';
  385. import { convertPen } from '@/services/upgrade';
  386. import { isGif } from '@/services/utils';
  387. import { autoSave, delAttrs, blank, useFolder, chargeDialogShow } from '@/services/common';
  388. import { debounce, throttle } from '@/services/debouce';
  389. import { searchObjectPinyin } from '@/services/pinyin';
  390. import { getCookie } from '@/services/cookie';
  391. import { parseSvg } from '@meta2d/svg';
  392. import Pay from './Pay.vue';
  393. import { filename } from '@/services/file';
  394. import { useUser } from '@/services/user';
  395. import { iframeCustom, rootDomain } from '@/services/defaults';
  396. import { getLe5le3d } from '@/services/api';
  397. import { useSelection } from '@/services/selections';
  398. import localforage from 'localforage';
  399. import { MenuFoldIcon, ImageIcon, AddIcon, EditIcon, DeleteIcon, DesktopIcon, RootListIcon, ControlPlatformIcon, ChartIcon, RelativityIcon, ChartBubbleIcon } from 'tdesign-icons-vue-next';
  400. const { user } = useUser();
  401. const { setFolder, getFolder } = useFolder();
  402. const router = useRouter();
  403. const { select } = useSelection();
  404. const activedGroup = ref('');
  405. const activeAssets = ref('system');
  406. let groups = reactive([]);
  407. let moveGroups = reactive<any>({
  408. '方案':[],
  409. '模板':[]
  410. });
  411. const systemGroups = [
  412. {
  413. icon: 'desktop',
  414. name: '方案',
  415. key: '',
  416. class: 'tow',
  417. },
  418. {
  419. icon: 'root-list',
  420. name: '模板',
  421. key: '',
  422. },
  423. {
  424. icon: 'l-zujian',
  425. name: '组件',
  426. key: 'chart',
  427. type: 'iconfont',
  428. },
  429. {
  430. icon: 'chart',
  431. name: '图表',
  432. key: 'chart',
  433. },
  434. {
  435. icon: 'image',
  436. name: '素材',
  437. key: '',
  438. },
  439. {
  440. icon: 'control-platform',
  441. name: '图元',
  442. key: '',
  443. },
  444. {
  445. icon: 'relativity',
  446. name: '控件',
  447. key: '',
  448. },
  449. {
  450. icon: 'chart-bubble',
  451. name: '图形',
  452. key: 'shape',
  453. },
  454. // {
  455. // icon: 'app',
  456. // name: '我的',
  457. // key: '',
  458. // },
  459. ];
  460. const userGroups = [
  461. {
  462. icon: 'desktop',
  463. name: '方案',
  464. key: '',
  465. class: 'tow',
  466. },
  467. {
  468. icon: 'root-list',
  469. name: '模板',
  470. key: '',
  471. },
  472. {
  473. icon: 'l-zujian',
  474. name: '组件',
  475. key: 'chart',
  476. type: 'iconfont',
  477. },
  478. {
  479. icon: 'image',
  480. name: '图片',
  481. key: '',
  482. },
  483. {
  484. icon: 'control-platform',
  485. name: '3D',
  486. key: '',
  487. },
  488. ];
  489. groups = systemGroups;
  490. const subGroups = ref<any[]>([]);
  491. const groupType = ref(0);
  492. const activedPanels = reactive<any>({});
  493. const caseCaches = [];
  494. const templateCaches = [];
  495. const componentCaches = [];
  496. const materials = [];
  497. const pngs = [];
  498. const components = [
  499. {
  500. name:"默认",
  501. list:[]
  502. }
  503. ];
  504. let dropped = false;
  505. const chargeDialog = reactive<any>({});
  506. const wechatPayDialog = reactive<any>({
  507. show: false,
  508. });
  509. const manageDialog = reactive<any>({
  510. name: '',
  511. data: [],
  512. show: false,
  513. });
  514. const search = ref('');
  515. const loading = ref(false);
  516. const headers = {
  517. Authorization: 'Bearer ' + (getCookie('token') || ''),
  518. };
  519. const updataData = { directory: '/大屏/默认' };
  520. let lastName = '方案';
  521. let userLastName = '方案';
  522. const assetsChange = (value) => {
  523. if (value === 'system') {
  524. groups = systemGroups;
  525. activedGroup.value = lastName;
  526. } else if (value === 'user') {
  527. groups = userGroups;
  528. activedGroup.value = userLastName;
  529. }
  530. groupChange(activedGroup.value);
  531. };
  532. const groupChange = async (name: string) => {
  533. activedGroup.value = name;
  534. groupType.value = 0;
  535. switch (name) {
  536. case '方案':
  537. if (activeAssets.value === 'system') {
  538. if (!caseCaches.length) {
  539. loading.value = true;
  540. caseCaches.push(...(await getCaseProjects('系统方案',1)));
  541. for (const group of cases) {
  542. group.list = [];
  543. for (const item of caseCaches) {
  544. if (item.case === group.name) {
  545. group.list.push(item);
  546. }
  547. }
  548. }
  549. loading.value = false;
  550. }
  551. groupType.value = 1;
  552. subGroups.value = cases;
  553. lastName = name;
  554. } else {
  555. // subGroups.value = await getUserProjects('le5leV');
  556. // groupType.value = 1;
  557. // await getPrivateProjects('le5leV');
  558. // userLastName = name;
  559. //用户方案
  560. subGroups.value = await getCollectionImageList('方案', 'v',1);
  561. moveGroups['方案'] = [];
  562. subGroups.value.forEach((item)=>{if(item.name!=='默认'){ moveGroups['方案'].push({name:item.name})}});
  563. groupType.value = 1;
  564. userLastName = name;
  565. }
  566. break;
  567. case '模板':
  568. if (activeAssets.value === 'system') {
  569. if (!templateCaches.length) {
  570. loading.value = true;
  571. templateCaches.push(...(await getCaseProjects('系统模板',2)));
  572. for (const group of templates) {
  573. group.list = [];
  574. for (const item of templateCaches) {
  575. if (item.case === group.name) {
  576. group.list.push(item);
  577. }
  578. }
  579. }
  580. loading.value = false;
  581. }
  582. groupType.value = 1;
  583. subGroups.value = templates;
  584. lastName = name;
  585. } else {
  586. // subGroups.value = await getUserProjects('le5leV-template');
  587. // groupType.value = 1;
  588. // await getPrivateProjects('le5leV-template');
  589. // userLastName = name;
  590. subGroups.value = await getCollectionImageList('模板', 'v',2);
  591. moveGroups['模板'] = [];
  592. subGroups.value.forEach((item)=>{if(item.name!=='默认'){ moveGroups['模板'].push({name:item.name})}});
  593. groupType.value = 1;
  594. userLastName = name;
  595. }
  596. break;
  597. case '图表':
  598. subGroups.value = charts;
  599. lastName = name;
  600. break;
  601. case '控件':
  602. subGroups.value = formComponents;
  603. lastName = name;
  604. break;
  605. case '素材':
  606. groupType.value = 1;
  607. if (!materials.length) {
  608. loading.value = true;
  609. materials.push(...(await getFolders('v/material')));
  610. loading.value = false;
  611. const _materials: string = await localforage.getItem(
  612. 'le5leV-materials'
  613. );
  614. if (_materials) {
  615. Object.assign(materials, JSON.parse(_materials));
  616. }
  617. }
  618. subGroups.value = materials;
  619. lastName = name;
  620. break;
  621. case '图元':
  622. if (!pngs.length) {
  623. loading.value = true;
  624. pngs.push(...(await getFolders('png')));
  625. pngs.push(...(await getFolders('svg', true)));
  626. loading.value = false;
  627. const _pngs: string = await localforage.getItem('le5leV-pngs');
  628. if (_pngs) {
  629. Object.assign(pngs, JSON.parse(_pngs));
  630. }
  631. }
  632. subGroups.value = pngs;
  633. lastName = name;
  634. break;
  635. case '图形':
  636. subGroups.value = shapes;
  637. lastName = name;
  638. break;
  639. case '组件':
  640. if (activeAssets.value === 'system') {
  641. if (!componentCaches.length) {
  642. loading.value = true;
  643. componentCaches.push(...(await getCaseProjects('系统组件',1)));
  644. loading.value = false;
  645. for (const component of componentCaches) {
  646. if(component.case){
  647. let group = components.filter((item)=>{item.name===component.case});
  648. if(group&&group.length){
  649. group[0].list.push(component);
  650. }else{
  651. components.push({
  652. name:component.case,
  653. list:[component]
  654. })
  655. }
  656. }else{
  657. components[0].list.push(component);
  658. }
  659. }
  660. }
  661. groupType.value = 1;
  662. subGroups.value = components;
  663. lastName = name;
  664. } else {
  665. // subGroups.value = await getUserComponents();
  666. // groupType.value = 1;
  667. // await getPrivateGraphics();
  668. // userLastName = name;
  669. subGroups.value = await getCollectionImageList(
  670. '组件',
  671. 'v.component',
  672. 1
  673. );
  674. groupType.value = 1;
  675. userLastName = name;
  676. }
  677. break;
  678. case '图片':
  679. loading.value = true;
  680. subGroups.value = await getImageList();
  681. loading.value = false;
  682. userLastName = name;
  683. break;
  684. case '3D':
  685. subGroups.value = [
  686. {
  687. name: '3D',
  688. list: [],
  689. },
  690. ];
  691. groupType.value = 1;
  692. await getPrivateGraphics();
  693. userLastName = name;
  694. break;
  695. }
  696. // if (!activedPanels[name]) {
  697. activedPanels[name] = [];
  698. for (const item of subGroups.value) {
  699. activedPanels[name].push(item.name);
  700. }
  701. // }
  702. // searchGraphics();
  703. };
  704. // TODO 获取方案文件
  705. //获取方案文件夹
  706. const getCollectionImageList = async (name?: string, collection?: string, userFlag?:number) => {
  707. //1. 获取网盘文件夹
  708. const fullpath = `/大屏/${name}`;
  709. let ret: { list: any[] } = await axios.post('/api/directory/list', {
  710. fullpath,
  711. });
  712. if (!ret) {
  713. return [];
  714. }
  715. let list = [];
  716. for (let i of ret.list) {
  717. if (
  718. i.fullpath !== `${fullpath}/默认` &&
  719. i.fullpath.split('/').length === 4
  720. ) {
  721. //不取当前文件夹
  722. list.push(i);
  723. }
  724. }
  725. const data = {
  726. // directory: `/大屏/${name}`,
  727. // query: {
  728. // // folder: '',
  729. // tags: name !== '组件' ? name : undefined,
  730. // },
  731. userFlag,
  732. // projection: {
  733. // image: 1,
  734. // id: 1,
  735. // name: 1,
  736. // tags: 1,
  737. // folder: 1,
  738. // component: 1,
  739. // filename: 1,
  740. // },
  741. };
  742. const config = {
  743. params: {
  744. current: 1,
  745. pageSize: 1000,
  746. },
  747. };
  748. //2.请求所有图纸/组件数据
  749. const res: any = await getCollectionList(collection, data, config);
  750. //3.将数据对应到云盘文件夹
  751. const results = [];
  752. const resultsMap = {
  753. 默认: [],
  754. };
  755. for (const item of list) {
  756. let folder = item.fullpath.split('/')[3];
  757. if (!resultsMap[folder]) {
  758. resultsMap[folder] = [];
  759. }
  760. }
  761. for (const item of res.list) {
  762. if(collection === 'v.component') {
  763. item.component = true;
  764. }
  765. if (item.folder && resultsMap[item.folder]) {
  766. resultsMap[item.folder].push(item);
  767. } else {
  768. resultsMap['默认'].push(item);
  769. }
  770. }
  771. for (const item of list) {
  772. let folder = item.fullpath.split('/')[3];
  773. results.push({
  774. name: folder,
  775. canEdited: true,
  776. id: item.id,
  777. list: resultsMap[folder],
  778. });
  779. }
  780. results.push({
  781. name: '默认',
  782. list: resultsMap['默认'],
  783. });
  784. return results;
  785. };
  786. const getImageList = async () => {
  787. let ret: { list: any[] } = await axios.post('/api/directory/list', {
  788. fullpath: '/大屏/图片',
  789. });
  790. if (!ret) {
  791. return [];
  792. }
  793. let list = [];
  794. for (let i of ret.list) {
  795. if (i.fullpath.split('/').length === 4) {
  796. //不取当前文件夹
  797. list.push(i);
  798. }
  799. }
  800. return await Promise.all(
  801. list.map(async (item) => {
  802. let secondDir = item.fullpath.split('/');
  803. const _ret: { list: any[]; total: number } = await axios.post(
  804. '/api/file/list',
  805. {
  806. type: '图片',
  807. directory: item.fullpath,
  808. },
  809. {
  810. params: {
  811. current: 1,
  812. pageSize: 100,
  813. },
  814. }
  815. );
  816. let list = _ret.list.map((_item) => {
  817. return {
  818. ..._item,
  819. image: _item.url || `/file${_item.filename}`,
  820. visible: true,
  821. folder: item.fullpath,
  822. id: _item.id || _item._id,
  823. };
  824. });
  825. return {
  826. name: secondDir[3],
  827. id: item.id || item._id,
  828. canEdited: secondDir[3] !== '默认',
  829. list: list,
  830. };
  831. })
  832. );
  833. };
  834. const getCaseProjects = async (name: string,systemFlag = 1, current = 1, pageSize = 1000) => {
  835. const query: any = { tags: name };
  836. let collection = name == '系统组件' ? 'v.component' : 'v';
  837. const ret: any = await axios.post(
  838. `/api/data/${collection}/list`,
  839. {
  840. // query: {
  841. // tags: "系统方案"
  842. // },
  843. //shared: true,
  844. // projection: "id,_id,name,image,price,case",
  845. // sort: { createdAt: 1 },
  846. systemFlag
  847. },
  848. {
  849. params: {
  850. current,
  851. pageSize,
  852. },
  853. }
  854. );
  855. if (!ret) {
  856. return [];
  857. }
  858. for (const item of ret.list) {
  859. if (!item.id) {
  860. item.id = item._id;
  861. }
  862. if(name !== '系统组件'){
  863. item.draggable = false;
  864. }else{
  865. item.component = true;
  866. }
  867. }
  868. return ret.list;
  869. };
  870. // const getUserProjects = async (name: string, current = 1, pageSize = 1000) => {
  871. // const query: any = { tags: name };
  872. // const ret: any = await axios.post(
  873. // '/api/data/le5leV/list',
  874. // {
  875. // query,
  876. // projection: {
  877. // id: 1,
  878. // _id: 1,
  879. // name: 1,
  880. // image: 1,
  881. // price: 1,
  882. // case: 1,
  883. // folder: 1,
  884. // },
  885. // sort: { createdAt: 1 },
  886. // },
  887. // {
  888. // params: {
  889. // current,
  890. // pageSize,
  891. // },
  892. // }
  893. // );
  894. // if (!ret) {
  895. // return [];
  896. // }
  897. // for (const item of ret.list) {
  898. // if (!item.id) {
  899. // item.id = item._id;
  900. // }
  901. // item.draggable = false;
  902. // }
  903. // return ret.list;
  904. // };
  905. const getPrivateGroups = async () => {
  906. const list = [
  907. {
  908. name: '默认',
  909. list: [],
  910. },
  911. ];
  912. const config = {
  913. params: {
  914. current: 1,
  915. pageSize: 1000,
  916. },
  917. };
  918. let ret: any = await axios.post(
  919. '/api/data/folders/list',
  920. {
  921. // projection: {
  922. // image: 1,
  923. // _id: 1,
  924. // name: 1,
  925. // list: 1,
  926. // },
  927. projection:'image,id,name,list',
  928. // query: {
  929. // type: `v-components`,
  930. // },
  931. sort: { createdAt: 1 },
  932. },
  933. config
  934. );
  935. if (!ret) {
  936. ret = { list: [] };
  937. }
  938. for (const item of ret.list) {
  939. item.canEdited = true;
  940. }
  941. list.push(...ret.list);
  942. list.push({
  943. name: '3D',
  944. list: [],
  945. });
  946. return list;
  947. };
  948. const getUserComponents = async () => {
  949. const list = [
  950. {
  951. name: '默认',
  952. list: [],
  953. },
  954. ];
  955. const config = {
  956. params: {
  957. current: 1,
  958. pageSize: 1000,
  959. },
  960. };
  961. let ret: any = await axios.post(
  962. '/api/data/folders/list',
  963. {
  964. // projection: {
  965. // image: 1,
  966. // _id: 1,
  967. // name: 1,
  968. // list: 1,
  969. // },
  970. projection:'image,id,name,list',
  971. // query: {
  972. // type: `v.component`,
  973. // },
  974. sort: { createdAt: 1 },
  975. },
  976. config
  977. );
  978. if (!ret) {
  979. ret = { list: [] };
  980. }
  981. for (const item of ret.list) {
  982. item.canEdited = true;
  983. }
  984. list.push(...ret.list);
  985. return list;
  986. };
  987. const getUserProjects = async (type: string) => {
  988. const list = [
  989. {
  990. name: '默认',
  991. list: [],
  992. },
  993. ];
  994. const config = {
  995. params: {
  996. current: 1,
  997. pageSize: 1000,
  998. },
  999. };
  1000. let ret: any = await axios.post(
  1001. '/api/data/folders/list',
  1002. {
  1003. // projection: {
  1004. // image: 1,
  1005. // _id: 1,
  1006. // name: 1,
  1007. // list: 1,
  1008. // },
  1009. projection:'image,id,name,list',
  1010. // query: {
  1011. // type,
  1012. // },
  1013. sort: { createdAt: 1 },
  1014. },
  1015. config
  1016. );
  1017. if (!ret) {
  1018. ret = { list: [] };
  1019. }
  1020. for (const item of ret.list) {
  1021. item.canEdited = true;
  1022. }
  1023. list.push(...ret.list);
  1024. return list;
  1025. };
  1026. const getPrivateProjects = async (type: string) => {
  1027. for (const item of subGroups.value) {
  1028. if (!item.list.length) {
  1029. item.loading = true;
  1030. //TODO 方案/模板分类
  1031. if (item.name === '默认') {
  1032. const data = {
  1033. // query: {
  1034. // folder: '',
  1035. // tags: type === 'v-template' ? '模板' : '方案',
  1036. // },
  1037. // projection: {
  1038. // image: 1,
  1039. // _id: 1,
  1040. // name: 1,
  1041. // tags: 1,
  1042. // },
  1043. projection:'image,id,name,tags'
  1044. };
  1045. const config = {
  1046. params: {
  1047. current: 1,
  1048. pageSize: 1000,
  1049. },
  1050. };
  1051. const res: any = await getCollectionList('v', data, config);
  1052. if (res?.list) {
  1053. // res.list.forEach((item) => {
  1054. // item.draggable = false;
  1055. // })
  1056. item.list = res.list;
  1057. // if (type === 'le5leV') {
  1058. // //过滤模板
  1059. // // item.list = res.list.filter((item) => !item.isTemplate);
  1060. // }
  1061. }
  1062. }
  1063. item.loading = false;
  1064. }
  1065. }
  1066. };
  1067. const dragStart = async (event: DragEvent | MouseEvent|TouchEvent, item: any) => {
  1068. // event.stopPropagation();
  1069. if (!item) {
  1070. return;
  1071. }
  1072. meta2d.canvas.addCaches = [];
  1073. dropped = false;
  1074. let data = null;
  1075. const id = item.id || item._id;
  1076. let isAsync: boolean;
  1077. if (
  1078. activeAssets.value === 'user' &&
  1079. ['方案', '模板'].includes(activedGroup.value)
  1080. ) {
  1081. if (!item._id) {
  1082. item._id = item.id;
  1083. }
  1084. item.draggable = false;
  1085. data = item.data || item;
  1086. dropped =true;
  1087. } else if (item.draggable === false) {
  1088. //方案
  1089. data = item.data || item;
  1090. dropped =true;
  1091. } else if (item['3d']) {
  1092. const res: any = await getLe5le3d(item.id || item._id, {
  1093. image: 1,
  1094. _id: 1,
  1095. name: 1,
  1096. });
  1097. data = {
  1098. name: 'iframe',
  1099. x: 0,
  1100. y: 0,
  1101. tags: ['meta3d'],
  1102. zIndex: 1,
  1103. operationalRect: {
  1104. x: 0.2,
  1105. y: 0.2,
  1106. height: 0.8,
  1107. width: 0.6,
  1108. },
  1109. props: {
  1110. custom: iframeCustom,
  1111. },
  1112. width: meta2d.store.data.width || meta2d.store.options.width,
  1113. height: meta2d.store.data.height || meta2d.store.options.height,
  1114. externElement: true,
  1115. thumbImg: res.image,
  1116. iframe: location.origin+'/view/3d/?id=' + (item.id || item._id),
  1117. };
  1118. } else if (item.component) {
  1119. // 默认
  1120. if (!item.componentDatas && !item.componentData) {
  1121. isAsync = true;
  1122. const ret: any = await axios.post(`/api/data/v.component/get`, {
  1123. id,
  1124. });
  1125. item.componentDatas = ret.data.componentDatas;
  1126. item.componentData = ret.data.componentData;
  1127. }
  1128. if (item.componentData) {
  1129. const pens = convertPen([item.componentData]);
  1130. data = deepClone(pens);
  1131. } else if (item.componentDatas) {
  1132. data = deepClone(item.componentDatas);
  1133. }
  1134. } else if (item.data) {
  1135. // 普通图元
  1136. data = item.data;
  1137. } else if (item.image) {
  1138. // 拖拽图片
  1139. let target: any = event.target;
  1140. target.children[0] && (target = target.children[0].children[0]);
  1141. // firefox naturalWidth svg 图片 可能是 0
  1142. const width = target.naturalWidth || target.width;
  1143. const height = target.naturalHeight || target.height;
  1144. const [name, lockedOnCombine] = await isGif(item.image)
  1145. ? ['gif', 0]
  1146. : ['image', undefined];
  1147. data = {
  1148. name,
  1149. width,
  1150. height,
  1151. isBottom:true,
  1152. image: item.image,
  1153. imageRatio: true,
  1154. ratio: true,
  1155. lockedOnCombine,
  1156. };
  1157. } else {
  1158. return;
  1159. }
  1160. if (!Array.isArray(data)) {
  1161. data = deepClone([data]);
  1162. }
  1163. !dropped && (meta2d.canvas.addCaches = data);
  1164. if (event instanceof DragEvent) {
  1165. event.dataTransfer.setData(
  1166. 'Meta2d',
  1167. isAsync ? undefined : JSON.stringify(data)
  1168. );
  1169. }
  1170. };
  1171. const dragstart = (event: any) => {
  1172. event.target.style.opacity = 0.5;
  1173. };
  1174. const dragend = (event: any) => {
  1175. event.target.style.opacity = 1;
  1176. };
  1177. const open = async (item: any) => {
  1178. if (!item || item.draggable !== false) {
  1179. return;
  1180. }
  1181. if (activeAssets.value === 'user') {
  1182. router.push({
  1183. path: '/',
  1184. query: {
  1185. r: Date.now() + '',
  1186. id:item.id || item._id,
  1187. },
  1188. });
  1189. } else {
  1190. const ret: any = await getLe5leV(item._id || item.id);
  1191. // if (!ret) {
  1192. // if (item.price > 0) {
  1193. // chargeDialog.data = item;
  1194. // chargeDialog.show = true;
  1195. // }
  1196. // return;
  1197. // }
  1198. if(!ret.data&&ret.price>0){
  1199. chargeDialog.data = item;
  1200. chargeDialogShow.value = true;
  1201. return;
  1202. }
  1203. sessionStorage.setItem('opening', '1');
  1204. router.push({
  1205. path: '/',
  1206. query: {
  1207. r: Date.now() + '',
  1208. },
  1209. });
  1210. for (const k of delAttrs) {
  1211. delete ret[k];
  1212. delete ret.data[k];
  1213. }
  1214. autoSave();
  1215. meta2d.open(ret.data);
  1216. meta2d.fitView();
  1217. }
  1218. select();
  1219. };
  1220. const getPrivateGraphics = async () => {
  1221. for (const item of subGroups.value) {
  1222. if (!item.list.length) {
  1223. item.loading = true;
  1224. if (item.name === '默认') {
  1225. const data = {
  1226. // query: { folder: '' },
  1227. // projection: {
  1228. // image: 1,
  1229. // _id: 1,
  1230. // name: 1,
  1231. // component: 1,
  1232. // },
  1233. projection:'image,id,name,component'
  1234. };
  1235. const config = {
  1236. params: {
  1237. current: 1,
  1238. pageSize: 1000,
  1239. },
  1240. };
  1241. const res: any = await getComponentsList(data, config);
  1242. if (res?.list) {
  1243. item.list = res.list;
  1244. }
  1245. } else if (item.name === '3D') {
  1246. const data = {
  1247. // projection: {
  1248. // image: 1,
  1249. // _id: 1,
  1250. // name: 1,
  1251. // },
  1252. projection:"id, name, image"
  1253. };
  1254. const config = {
  1255. params: {
  1256. current: 1,
  1257. pageSize: 1000,
  1258. },
  1259. };
  1260. const res: any = await axios.post(
  1261. '/api/data/3d/list',
  1262. data,
  1263. config
  1264. );
  1265. if (res?.list) {
  1266. for (const item of res.list) {
  1267. item['3d'] = true;
  1268. item['draggable'] = true;
  1269. }
  1270. item.list = res.list;
  1271. }
  1272. }
  1273. item.loading = false;
  1274. }
  1275. }
  1276. };
  1277. const editedFolder = ref<any>(undefined);
  1278. const onCreateFolder = () => {
  1279. activedPanels[activedGroup.value].splice(
  1280. 0,
  1281. activedPanels[activedGroup.value].length
  1282. );
  1283. editedFolder.value = {
  1284. _id: '',
  1285. name: '',
  1286. label: '新建文件夹',
  1287. list: [],
  1288. edited: true,
  1289. canEdited: true,
  1290. };
  1291. subGroups.value.splice(subGroups.value.length - 1, 0, editedFolder.value);
  1292. };
  1293. const createFoder = async () => {
  1294. if (!editedFolder.value.label) {
  1295. return;
  1296. }
  1297. if (editedFolder.value.label === editedFolder.value.name) {
  1298. editedFolder.value.edited = false;
  1299. return;
  1300. }
  1301. const found = subGroups.value.findIndex(
  1302. (group: any) => group.name === editedFolder.value.label
  1303. );
  1304. if (found >= 0) {
  1305. MessagePlugin.error('已经存在相同名称文件夹');
  1306. return;
  1307. }
  1308. if (activeAssets.value !== 'user') {
  1309. return;
  1310. }
  1311. if (editedFolder.value.id || editedFolder.value._id) {
  1312. const ret: any = await axios.post('/api/directory/update', {
  1313. oldFullpath: `/大屏/${activedGroup.value}/` + editedFolder.value.oldLabel,
  1314. newFullpath: `/大屏/${activedGroup.value}/` + editedFolder.value.label,
  1315. });
  1316. if (ret) {
  1317. editedFolder.value.name = editedFolder.value.label;
  1318. editedFolder.value.edited = false;
  1319. }
  1320. //更新图纸的folder
  1321. if (['组件', '方案', '模板'].includes(activedGroup.value)) {
  1322. const collection =
  1323. activedGroup.value === '组件' ? 'v.component' : 'v';
  1324. editedFolder.value.list?.forEach(async (item) => {
  1325. item.folder = editedFolder.value.label;
  1326. await updateCollection(collection, {
  1327. id: item.id || item._id,
  1328. folder: editedFolder.value.label,
  1329. });
  1330. });
  1331. }
  1332. } else {
  1333. const ret: any = await axios.post('/api/directory/add', {
  1334. fullpath: `/大屏/${activedGroup.value}/` + editedFolder.value.label,
  1335. });
  1336. if (ret) {
  1337. editedFolder.value.name = editedFolder.value.label;
  1338. editedFolder.value.id = ret.id;
  1339. editedFolder.value.edited = false;
  1340. }
  1341. }
  1342. };
  1343. const _createFoder = async () => {
  1344. if (!editedFolder.value.label) {
  1345. return;
  1346. }
  1347. if (editedFolder.value.label === editedFolder.value.name) {
  1348. editedFolder.value.edited = false;
  1349. return;
  1350. }
  1351. const found = subGroups.value.findIndex(
  1352. (group: any) => group.name === editedFolder.value.label
  1353. );
  1354. if (found >= 0) {
  1355. MessagePlugin.error('已经存在相同名称文件夹');
  1356. return;
  1357. }
  1358. if (activeAssets.value !== 'user') {
  1359. return;
  1360. }
  1361. if (['组件', '方案', '模板'].includes(activedGroup.value)) {
  1362. if (editedFolder.value._id) {
  1363. const ret: any = await axios.post('/api/data/folders/update', {
  1364. _id: editedFolder.value._id,
  1365. name: editedFolder.value.label,
  1366. });
  1367. if (ret) {
  1368. editedFolder.value.name = editedFolder.value.label;
  1369. editedFolder.value.edited = false;
  1370. }
  1371. } else {
  1372. let type =
  1373. activedGroup.value === '组件'
  1374. ? 'v.component'
  1375. : activedGroup.value === '模板'
  1376. ? 'v-template'
  1377. : 'v';
  1378. const ret: any = await axios.post('/api/data/folders/add', {
  1379. name: editedFolder.value.label,
  1380. type,
  1381. list: [],
  1382. });
  1383. if (ret) {
  1384. editedFolder.value.name = editedFolder.value.label;
  1385. editedFolder.value._id = ret._id;
  1386. editedFolder.value.edited = false;
  1387. }
  1388. }
  1389. } else if (activedGroup.value === '图片') {
  1390. if (editedFolder.value._id) {
  1391. const ret: any = await axios.post('/api/directory/update', {
  1392. oldFullpath: '/大屏/' + editedFolder.value.oldLabel,
  1393. newFullpath: '/大屏/' + editedFolder.value.label,
  1394. });
  1395. if (ret) {
  1396. editedFolder.value.name = editedFolder.value.label;
  1397. editedFolder.value.edited = false;
  1398. }
  1399. } else {
  1400. const ret: any = await axios.post('/api/directory/add', {
  1401. fullpath: '/大屏/' + editedFolder.value.label,
  1402. });
  1403. if (ret) {
  1404. editedFolder.value.name = editedFolder.value.label;
  1405. editedFolder.value._id = ret.id || ret._id;
  1406. editedFolder.value.edited = false;
  1407. }
  1408. }
  1409. }
  1410. };
  1411. const onEditHeader = (item: any) => {
  1412. item.label = item.name;
  1413. item.edited = true;
  1414. item.oldLabel = item.name;
  1415. editedFolder.value = item;
  1416. };
  1417. const onAdd = (item: any) => {
  1418. blank();
  1419. if (activedGroup.value === '方案') {
  1420. item.vType = 'v';
  1421. } else if (activedGroup.value === '模板') {
  1422. item.vType = 'v-template';
  1423. } else if (activedGroup.value === '组件') {
  1424. item.vType = 'v.component';
  1425. }
  1426. setFolder(item);
  1427. const query: any = {
  1428. r: Date.now() + '',
  1429. folder: item.name,
  1430. tags: activedGroup.value,
  1431. };
  1432. if (activedGroup.value === '组件') {
  1433. query.c = 1;
  1434. }
  1435. router.push({
  1436. path: '/',
  1437. query,
  1438. });
  1439. activeAssets.value = 'system';
  1440. assetsChange('system');
  1441. // meta2d.open({
  1442. // name: '新建项目',
  1443. // pens: [],
  1444. // enableMock: true,
  1445. // tags: activedGroup.value,
  1446. // folder: item.name,
  1447. // } as any);
  1448. };
  1449. const onKeyHeader = (text: string, event: any) => {
  1450. if (event.e.key === 'Escape') {
  1451. editedFolder.value.edited = false;
  1452. }
  1453. };
  1454. // 默认右键菜单
  1455. const contextmenu = reactive<any>({
  1456. visible: false,
  1457. style: {},
  1458. // 子分类
  1459. group: undefined,
  1460. // 组件图纸
  1461. component: {},
  1462. // 右键二级子菜单
  1463. subMenus: [],
  1464. });
  1465. const contextmenuDom = ref<any>(null);
  1466. const onContextMenu = async (e: MouseEvent, group: any, item: any) => {
  1467. e.preventDefault();
  1468. e.stopPropagation();
  1469. if (activeAssets.value === 'system') {
  1470. return;
  1471. }
  1472. contextmenu.group = group;
  1473. contextmenu.component = item;
  1474. if (document.body.clientHeight - e.clientY < 128) {
  1475. contextmenu.style = {
  1476. left: e.clientX + 'px',
  1477. bottom: '4px',
  1478. };
  1479. } else {
  1480. contextmenu.style = {
  1481. left: e.clientX + 'px',
  1482. top: e.clientY + 'px',
  1483. };
  1484. }
  1485. if(!(moveGroups['模板']&&moveGroups['模板'].length)){
  1486. let ret: { list: any[] } = await axios.post('/api/directory/list', {
  1487. fullpath:"/大屏/模板",
  1488. });
  1489. moveGroups['模板'] = [];
  1490. ret.list.forEach((item)=>{
  1491. if(item.fullpath!=='/大屏/模板/默认'){
  1492. moveGroups['模板'].push({name:item.fullpath.split('/')[3]})
  1493. }
  1494. });
  1495. }
  1496. if(!(moveGroups['方案']&&moveGroups['方案'].length)){
  1497. let ret: { list: any[] } = await axios.post('/api/directory/list', {
  1498. fullpath:"/大屏/方案",
  1499. });
  1500. moveGroups['方案'] = [];
  1501. ret.list.forEach((item)=>{
  1502. if(item.fullpath!=='/大屏/方案/默认'){
  1503. moveGroups['方案'].push({name:item.fullpath.split('/')[3]})
  1504. }
  1505. });
  1506. }
  1507. contextmenu.subMenus = [];
  1508. for (const elem of subGroups.value) {
  1509. if (elem === group || elem.name === '默认' || elem.name === '3D') {
  1510. continue;
  1511. }
  1512. contextmenu.subMenus.push(elem);
  1513. }
  1514. contextmenu.visible = true;
  1515. setTimeout(() => {
  1516. if (contextmenuDom.value) {
  1517. contextmenuDom.value.focus();
  1518. }
  1519. }, 500);
  1520. };
  1521. const delDialog = reactive<any>({
  1522. contextmenuObj: {},
  1523. });
  1524. // TODO 右键菜单移动图纸
  1525. const onMenu = async (val: string) => {
  1526. const id = contextmenu.component.id || contextmenu.component._id;
  1527. setTimeout(() => {
  1528. contextmenu.group = '';
  1529. contextmenu.component = {};
  1530. contextmenu.subMenus = [];
  1531. }, 500);
  1532. switch (val) {
  1533. case 'edit':
  1534. if (
  1535. contextmenu.component.tags &&
  1536. contextmenu.component.tags.includes('svg')
  1537. ) {
  1538. MessagePlugin.warning('解析的svg图元不允许编辑!');
  1539. hideContextmenu();
  1540. contextmenu.activeValue = 0;
  1541. return;
  1542. }
  1543. // if (contextmenu.component.component) {
  1544. if (activedGroup.value == '组件') {
  1545. autoSave();
  1546. router.push({
  1547. path: '/',
  1548. query: {
  1549. id,
  1550. c: 1,
  1551. r: Date.now() + '',
  1552. },
  1553. });
  1554. } else if (contextmenu.component['3d']) {
  1555. let url = `https://3d${rootDomain}/?id=`;
  1556. if (window.url3D) {
  1557. url = window.url3D;
  1558. }
  1559. window.open(url + id, '_blank');
  1560. } else {
  1561. if ((contextmenu.group.id||contextmenu.group._id) && contextmenu.group.name !== '默认') {
  1562. setFolder(contextmenu.group);
  1563. }
  1564. autoSave();
  1565. //文件夹
  1566. router.push({
  1567. path: '/',
  1568. query: {
  1569. id,
  1570. r: Date.now() + '',
  1571. },
  1572. });
  1573. }
  1574. hideContextmenu();
  1575. break;
  1576. case 'del':
  1577. delDialog.show = true;
  1578. Object.assign(delDialog.contextmenuObj, contextmenu);
  1579. break;
  1580. default:
  1581. if(val.startsWith('moveTo:')){
  1582. val = val.replace('moveTo:', '');
  1583. //更新前端
  1584. contextmenu.group.list.forEach((item: any, index: number, arr: any[]) => {
  1585. if (id === item._id || id === item.id) {
  1586. arr.splice(index, 1);
  1587. }
  1588. });
  1589. //更新后端图纸
  1590. let ret = await updateCollection('v', {
  1591. id,
  1592. folder: val === '默认' ? '' : val,
  1593. userFlag:activedGroup.value === '方案' ? 2 : 1
  1594. });
  1595. if (!ret) {
  1596. return;
  1597. }
  1598. //更新后端 图片
  1599. let path: string =
  1600. contextmenu.component.filename || contextmenu.component.image;
  1601. if (imageDrive && path.startsWith(imageDrive)) {
  1602. path = path.slice(imageDrive.length);
  1603. }
  1604. if(!path.startsWith('/api/file')) {
  1605. path = '/api/file' + path;
  1606. }
  1607. await axios.patch(`${path}`, {
  1608. // filenames: [filename],
  1609. directory: `/大屏/${activedGroup.value==='方案'?'模板':'方案' }/${val || '默认'}`,
  1610. });
  1611. break;
  1612. }
  1613. if (val.indexOf('move:')) {
  1614. return;
  1615. }
  1616. val = val.replace('move:', '');
  1617. const group = contextmenu.subMenus.find(
  1618. (element: any) => element.name === val
  1619. );
  1620. if (!group) {
  1621. return;
  1622. }
  1623. // 前端: 添加组件到目标文件夹
  1624. let data: any;
  1625. if (contextmenu.component.component) {
  1626. data = {
  1627. component: true,
  1628. image: contextmenu.component.image,
  1629. name: contextmenu.component.name,
  1630. visible: true,
  1631. _id: contextmenu.component._id || contextmenu.component.id,
  1632. filename: contextmenu.component.filename,
  1633. };
  1634. } else {
  1635. data = {
  1636. image: contextmenu.component.image,
  1637. name: contextmenu.component.name,
  1638. tags: contextmenu.component.tags,
  1639. visible: true,
  1640. _id: contextmenu.component._id || contextmenu.component.id,
  1641. filename: contextmenu.component.filename,
  1642. };
  1643. }
  1644. group.list.push(data);
  1645. // 前端:从源文件夹移出组件
  1646. contextmenu.group.list.forEach((item: any, index: number, arr: any[]) => {
  1647. if (id === item._id || id === item.id) {
  1648. arr.splice(index, 1);
  1649. }
  1650. });
  1651. if (activedGroup.value !== '图片') {
  1652. let collection = activedGroup.value === '组件'
  1653. ? 'v.component'
  1654. : 'v';
  1655. // 更新后端组件信息
  1656. let ret = await updateCollection(collection, {
  1657. id,
  1658. folder: val === '默认' ? '' : val,
  1659. });
  1660. if (!ret) {
  1661. return;
  1662. }
  1663. }
  1664. // // 更新后端源文件夹列表
  1665. // if (contextmenu.group.name !== '默认') {
  1666. // await axios.post('/api/data/folders/update', {
  1667. // _id: contextmenu.group._id || contextmenu.group.id,
  1668. // list: contextmenu.group.list,
  1669. // });
  1670. // }
  1671. // 更新后端目标文件夹列表
  1672. // if (group.name !== '默认') {
  1673. // await axios.post('/api/data/folders/update', {
  1674. // _id: group._id || group.id,
  1675. // list: group.list,
  1676. // });
  1677. // }
  1678. // let filename: string =
  1679. // contextmenu.component.filename || contextmenu.component.image;
  1680. // if (imageDrive && filename.startsWith(imageDrive)) {
  1681. // filename = filename.slice(imageDrive.length);
  1682. // }
  1683. let path: string =
  1684. contextmenu.component.filename || contextmenu.component.image;
  1685. //更新缩略图位置
  1686. // await axios.post('/api/files/update', {
  1687. // filenames: [filename],
  1688. // 'metadata.directory': `/大屏/${activedGroup.value}/${val || '默认'}`,
  1689. // });
  1690. // 原接口路径是 /api/file/{fullname}
  1691. // 因为img的路径中包含file,所以做如下拼接
  1692. if (imageDrive && path.startsWith(imageDrive)) {
  1693. path = path.slice(imageDrive.length);
  1694. }
  1695. if(path.startsWith('/file')) {
  1696. path = '/api' + path;
  1697. } else if(!path.startsWith('/api/file')) {
  1698. path = '/api/file' + path;
  1699. }
  1700. await axios.patch(`${path}`, {
  1701. // filenames: [filename],
  1702. directory: `/大屏/${activedGroup.value}/${val || '默认'}`,
  1703. });
  1704. break;
  1705. }
  1706. contextmenu.activeValue = 0;
  1707. };
  1708. const hideContextmenu = () => {
  1709. contextmenu.visible = false;
  1710. };
  1711. const _delComponent = async () => {
  1712. // const id = contextmenu.component._id || contextmenu.component.id;
  1713. if (['组件', '方案', '模板'].includes(activedGroup.value)) {
  1714. let collection = delDialog.contextmenuObj.component.component
  1715. ? 'v.component'
  1716. : 'v';
  1717. const id =
  1718. delDialog.contextmenuObj.component._id ||
  1719. delDialog.contextmenuObj.component.id;
  1720. try {
  1721. await axios.post(`/api/data/${collection}/delete`, {
  1722. id,
  1723. });
  1724. } catch (e) {
  1725. console.error(e);
  1726. return;
  1727. }
  1728. //删除缩略图
  1729. if (delDialog.contextmenuObj.component.image) {
  1730. await delImage(delDialog.contextmenuObj.component.image);
  1731. }
  1732. // 前端:从源文件夹移出组件
  1733. delDialog.contextmenuObj.group.list.forEach(
  1734. (item: any, index: number, arr: any[]) => {
  1735. if (id === item._id || id === item.id) {
  1736. arr.splice(index, 1);
  1737. }
  1738. }
  1739. );
  1740. // 更新后端源文件夹列表
  1741. if (delDialog.contextmenuObj.group.name !== '默认') {
  1742. await axios.post('/api/data/folders/update', {
  1743. _id:
  1744. delDialog.contextmenuObj.group._id ||
  1745. delDialog.contextmenuObj.group.id,
  1746. list: delDialog.contextmenuObj.group.list,
  1747. });
  1748. }
  1749. } else {
  1750. const id =
  1751. delDialog.contextmenuObj.component._id ||
  1752. delDialog.contextmenuObj.component.id;
  1753. delDialog.contextmenuObj.group.list.forEach(
  1754. (item: any, index: number, arr: any[]) => {
  1755. if (id && (id === item._id || id === item.id)) {
  1756. arr.splice(index, 1);
  1757. }
  1758. if (!id) {
  1759. if (item.url === delDialog.contextmenuObj.component.url) {
  1760. arr.splice(index, 1);
  1761. }
  1762. }
  1763. }
  1764. );
  1765. await axios.post(`/api/files/delete`, {
  1766. fullnames: [delDialog.contextmenuObj.component.filename],
  1767. physically: true,
  1768. });
  1769. }
  1770. delDialog.show = false;
  1771. delDialog.contextmenuObj = {};
  1772. MessagePlugin.success('删除成功');
  1773. };
  1774. const delComponent = async () => {
  1775. // const id = contextmenu.component._id || contextmenu.component.id;
  1776. if (['组件', '方案', '模板'].includes(activedGroup.value)) {
  1777. // let collection = delDialog.contextmenuObj.component.component
  1778. // ? 'v.component'
  1779. // : 'v';
  1780. let collection = '';
  1781. if(activedGroup.value == '组件') {
  1782. collection = 'v.component'
  1783. } else {
  1784. collection = 'v'
  1785. }
  1786. const id =
  1787. delDialog.contextmenuObj.component._id ||
  1788. delDialog.contextmenuObj.component.id;
  1789. try {
  1790. await axios.post(`/api/data/${collection}/delete`, {
  1791. id,
  1792. });
  1793. } catch (e) {
  1794. console.error(e);
  1795. return;
  1796. }
  1797. // 前端:从源文件夹移出组件
  1798. delDialog.contextmenuObj.group.list.forEach(
  1799. (item: any, index: number, arr: any[]) => {
  1800. if (id === item._id || id === item.id) {
  1801. arr.splice(index, 1);
  1802. }
  1803. }
  1804. );
  1805. } else {
  1806. const id =
  1807. delDialog.contextmenuObj.component._id ||
  1808. delDialog.contextmenuObj.component.id;
  1809. delDialog.contextmenuObj.group.list.forEach(
  1810. (item: any, index: number, arr: any[]) => {
  1811. if (id && (id === item.id || id === item._id)) {
  1812. arr.splice(index, 1);
  1813. }
  1814. if (!id) {
  1815. if (item.url === delDialog.contextmenuObj.component.url) {
  1816. arr.splice(index, 1);
  1817. }
  1818. }
  1819. }
  1820. );
  1821. }
  1822. let fullname: string =
  1823. delDialog.contextmenuObj.component.fullname ||
  1824. delDialog.contextmenuObj.component.image;
  1825. if (imageDrive && fullname.startsWith(imageDrive)) {
  1826. fullname = fullname.slice(imageDrive.length);
  1827. }
  1828. if(fullname.startsWith('/file')) {
  1829. fullname = fullname.slice('/file'.length);
  1830. }
  1831. if(fullname.startsWith('/api/file/')) {
  1832. fullname = fullname.slice('/api/file/'.length);
  1833. }
  1834. await axios.post(`/api/files/delete`, {
  1835. fullnames: [fullname],
  1836. physically: true,
  1837. });
  1838. delDialog.show = false;
  1839. delDialog.contextmenuObj = {};
  1840. MessagePlugin.success('删除成功');
  1841. };
  1842. const drop = (obj: any) => {
  1843. dropped = true;
  1844. if (obj) {
  1845. Array.isArray(obj) && open(obj[0]);
  1846. } else {
  1847. MessagePlugin.warning('正在请求网络数据中,请稍后重试');
  1848. }
  1849. };
  1850. const onSubmitOrder = async () => {
  1851. const result: any = await axios.post('/api/order/datas/submit', {
  1852. collection: 'v',
  1853. id: chargeDialog.data.id||chargeDialog.data._id,
  1854. });
  1855. if (result) {
  1856. wechatPayDialog.order = result;
  1857. wechatPayDialog.show = true;
  1858. }
  1859. };
  1860. const getPayResult = async () => {
  1861. const result: { state: number } = await axios.post('/api/order/pay/state', {
  1862. id: wechatPayDialog.order.id || wechatPayDialog.order._id,
  1863. });
  1864. if (result && result.state) {
  1865. return true;
  1866. }
  1867. };
  1868. const onChargeSuccess = () => {
  1869. MessagePlugin.success('支付成功!');
  1870. wechatPayDialog.show = false;
  1871. chargeDialog.show = false;
  1872. };
  1873. const onSearch = () => {
  1874. debounce(searchGraphics, 300);
  1875. };
  1876. const searchGraphics = async () => {
  1877. if (search.value) {
  1878. activedPanels[activedGroup.value].splice(
  1879. 0,
  1880. activedPanels[activedGroup.value].length
  1881. );
  1882. }
  1883. for (const group of subGroups.value) {
  1884. for (const item of group.list) {
  1885. if (search.value) {
  1886. item.visible = searchObjectPinyin(item, 'name', search.value);
  1887. } else {
  1888. item.visible = true;
  1889. }
  1890. }
  1891. if (search.value) {
  1892. activedPanels[activedGroup.value].push(group.name);
  1893. }
  1894. }
  1895. };
  1896. const onFold = () => {
  1897. if (!activedPanels[activedGroup.value]) {
  1898. return;
  1899. }
  1900. if (activedPanels[activedGroup.value].length) {
  1901. activedPanels[activedGroup.value] = [];
  1902. } else {
  1903. activedPanels[activedGroup.value] = [];
  1904. for (const item of subGroups.value) {
  1905. activedPanels[activedGroup.value].push(item.name);
  1906. }
  1907. }
  1908. };
  1909. const loadImage = (elem: any) => {
  1910. if (elem.isSvg) {
  1911. makeSvg(elem);
  1912. if (activedGroup.value === '图元') {
  1913. throttle(renderPngGroup, 100);
  1914. }
  1915. }
  1916. };
  1917. const renderPngGroup = () => {
  1918. subGroups.value = pngs;
  1919. };
  1920. let uploadGroup: any;
  1921. const onSelectFiles = (item: any) => {
  1922. uploadGroup = item;
  1923. };
  1924. const beforeUpload = (file: any) => {
  1925. if (!(user && user.id)) {
  1926. MessagePlugin.warning('请先登录!');
  1927. return false;
  1928. }
  1929. return true;
  1930. };
  1931. /*
  1932. * @description 根据上传的文件处理为meta2d能够识别的内容
  1933. * */
  1934. function processFileObj(fileObj, c) {
  1935. return new Promise((resolve) => {
  1936. if (fileObj.name.endsWith('.svg')) {
  1937. let fileReader = new FileReader();
  1938. fileReader.readAsText(fileObj.raw);
  1939. fileReader.onload = async () => {
  1940. let svgText = fileReader.result;
  1941. c.componentDatas = parseSvg(svgText as string);
  1942. c.component = true;
  1943. c.tags = ['svg'];
  1944. resolve(c);
  1945. };
  1946. } else {
  1947. // 除了svg 其他一律按照图片处理,这样是否会有问题?
  1948. resolve(c);
  1949. }
  1950. });
  1951. }
  1952. const fileSuccessed = async (content: any) => {
  1953. // 组件中去掉了上传图片入口
  1954. // if (activedGroup.value === '组件') {
  1955. // const c: any = {
  1956. // name: filename(content.file.name),
  1957. // image:
  1958. // content.response.url ||
  1959. // content.response.metadata.url ||
  1960. // `/file${content.response.filename}`,
  1961. // folder: uploadGroup.name === '默认' ? '' : uploadGroup.name,
  1962. // };
  1963. // let rst = await processFileObj(
  1964. // { raw: content.file.raw, name: content.file.name },
  1965. // c
  1966. // );
  1967. // const ret: any = await addCollection('v.component', rst);
  1968. // c._id = ret._id || ret.id;
  1969. // if (ret && uploadGroup.name !== '默认') {
  1970. // if (!uploadGroup.list) {
  1971. // uploadGroup.list = [];
  1972. // }
  1973. // uploadGroup.list.push(c);
  1974. // await axios.post('/api/data/folders/update', {
  1975. // _id: uploadGroup._id || uploadGroup.id,
  1976. // list: uploadGroup.list,
  1977. // });
  1978. // } else {
  1979. // if (!uploadGroup.list) {
  1980. // uploadGroup.list = [];
  1981. // }
  1982. // uploadGroup.list.push(c);
  1983. // }
  1984. // uploadGroup.list.push(c);
  1985. // } else if (activedGroup.value === '图片') {
  1986. uploadGroup.list.push({
  1987. ...content.response,
  1988. image:
  1989. content.response.url ||
  1990. content.response.metadata.url ||
  1991. `/file${content.response.filename}`,
  1992. visible: true,
  1993. folder: content.response.directory || content.response.metadata.directory,
  1994. });
  1995. // }
  1996. MessagePlugin.success('上传成功');
  1997. };
  1998. const delFolder = async (item: any) => {
  1999. if (item.list?.length) {
  2000. MessagePlugin.error('文件夹不为空!');
  2001. return;
  2002. }
  2003. const id = item.id || item._id;
  2004. let ret: any;
  2005. if (activeAssets.value !== 'user') {
  2006. return;
  2007. }
  2008. // if (['组件', '方案', '模板'].includes(activedGroup.value)) {
  2009. // ret = await axios.post('/api/data/folders/delete', {
  2010. // id,
  2011. // });
  2012. // } else if (activedGroup.value === '图片') {
  2013. // ret = await axios.post('/api/directory/delete', {
  2014. // fullpaths: [`/大屏/${item.name}`],
  2015. // });
  2016. // }
  2017. ret = await axios.post('/api/directory/delete', {
  2018. fullpaths: [`/大屏/${activedGroup.value}/${item.name}`],
  2019. physically: true
  2020. });
  2021. if (ret) {
  2022. const i = subGroups.value.findIndex(
  2023. (elem: any) => id === elem._id || id === elem.id
  2024. );
  2025. i >= 0 && subGroups.value.splice(i, 1);
  2026. }
  2027. };
  2028. const reloadCurrent = () => {
  2029. groupChange(activedGroup.value);
  2030. };
  2031. const updateAfterSave = (e) => {
  2032. if (activeAssets.value === 'user') {
  2033. if (e === 'v.component' && activedGroup.value === '组件') {
  2034. groupChange('组件');
  2035. } else if (e === 'v-template' && activedGroup.value === '模板') {
  2036. groupChange('模板');
  2037. } else if (e === '' && activedGroup.value === '方案') {
  2038. groupChange('方案');
  2039. }
  2040. }
  2041. };
  2042. const onManageGraphic = () => {
  2043. if (activedGroup.value === '素材') {
  2044. materials.forEach((item) => {
  2045. item.list.forEach((_item) => {
  2046. if(_item.visible === undefined){
  2047. _item.visible = true;
  2048. }
  2049. });
  2050. });
  2051. manageDialog.data = deepClone(materials);
  2052. } else if (activedGroup.value === '图元') {
  2053. pngs.forEach((item) => {
  2054. item.list.forEach((_item) => {
  2055. if(_item.visible === undefined){
  2056. _item.visible = true;
  2057. }
  2058. });
  2059. });
  2060. manageDialog.data = deepClone(pngs);
  2061. }
  2062. manageDialog.show = true;
  2063. };
  2064. const manageConfirm = () => {
  2065. //TODO 后续存放到后端 目前本地存储
  2066. if (activedGroup.value === '素材') {
  2067. localforage.setItem('le5leV-materials', JSON.stringify(manageDialog.data));
  2068. materials.length = 0;
  2069. materials.push(...manageDialog.data);
  2070. } else if (activedGroup.value === '图元') {
  2071. localforage.setItem('le5leV-pngs', JSON.stringify(manageDialog.data));
  2072. pngs.length = 0;
  2073. pngs.push(...manageDialog.data);
  2074. }
  2075. subGroups.value = manageDialog.data;
  2076. manageDialog.show = false;
  2077. };
  2078. onMounted(() => {
  2079. groupChange('方案');
  2080. document.addEventListener('dragstart', dragstart, false);
  2081. document.addEventListener('dragend', dragend, false);
  2082. setTimeout(() => {
  2083. meta2d.on('drop', drop);
  2084. meta2d.on('logout', reloadCurrent);
  2085. meta2d.on('business-save', updateAfterSave);
  2086. meta2d.on('business-assets', changeAssets);
  2087. }, 2000);
  2088. });
  2089. const changeAssets = (e)=>{
  2090. if(e){
  2091. activeAssets.value = 'system';
  2092. assetsChange( activeAssets.value);
  2093. }
  2094. }
  2095. onUnmounted(() => {
  2096. document.removeEventListener('dragstart', dragstart);
  2097. document.removeEventListener('dragend', dragend);
  2098. meta2d.off('drop', drop);
  2099. meta2d.off('logout', reloadCurrent);
  2100. meta2d.off('business-save', updateAfterSave);
  2101. meta2d.off('business-assets', changeAssets);
  2102. });
  2103. </script>
  2104. <style lang="postcss" scoped>
  2105. .graphics {
  2106. display: flex;
  2107. flex-direction: column;
  2108. background-color: var(--color-background);
  2109. z-index: 2;
  2110. .group-asset {
  2111. height: 40px;
  2112. justify-content: center;
  2113. align-items: center;
  2114. display: flex;
  2115. .t-radio-group.t-radio-group--filled {
  2116. padding: 0px;
  2117. height: 30px;
  2118. }
  2119. :deep(.t-radio-button__label) {
  2120. margin: auto;
  2121. }
  2122. .t-radio-button {
  2123. width: 120px;
  2124. height: 100%;
  2125. color: var(--color);
  2126. &:hover {
  2127. color: var(--color-primary);
  2128. }
  2129. &.t-is-checked {
  2130. background-color: var(--color-primary) !important;
  2131. color: #fff !important;
  2132. }
  2133. }
  2134. }
  2135. .groups-panel {
  2136. display: grid;
  2137. grid-template-columns: 50px 1fr;
  2138. border-top: 1px solid var(--color-background-input);
  2139. flex-grow: 1;
  2140. overflow-y: auto;
  2141. font-size: 12px;
  2142. z-index: 7;
  2143. .groups {
  2144. background: var(--color-background-groups);
  2145. & > div {
  2146. display: flex;
  2147. flex-direction: column;
  2148. align-items: center;
  2149. padding: 16px 4px;
  2150. line-height: 1;
  2151. cursor: pointer;
  2152. .t-icon {
  2153. font-size: 20px;
  2154. margin-bottom: 8px;
  2155. }
  2156. .l-icon {
  2157. font-size: 24px;
  2158. margin-bottom: 8px;
  2159. }
  2160. &:hover {
  2161. color: var(--color-primary);
  2162. }
  2163. }
  2164. .active {
  2165. background-color: var(--color-background-active);
  2166. color: var(--color-primary);
  2167. border-left: 2px solid var(--color-primary);
  2168. }
  2169. }
  2170. .list {
  2171. overflow-y: auto;
  2172. max-height: calc(100vh - 80px);
  2173. background-color: var(--color-background-active);
  2174. /* padding-top: 8px; */
  2175. .input-search {
  2176. flex-shrink: 0;
  2177. /* height: 40px; */
  2178. position: sticky;
  2179. top: 0px;
  2180. z-index: 10;
  2181. padding: 16px;
  2182. color: #878f9c;
  2183. margin-top: -10px;
  2184. .btn {
  2185. background: #fff0;
  2186. img {
  2187. background-color: #fff0;
  2188. margin-top: 9px;
  2189. }
  2190. /* .t-icon {
  2191. background: #fff0;
  2192. } */
  2193. }
  2194. }
  2195. .div-manage {
  2196. position: sticky;
  2197. bottom: 2px;
  2198. z-index: 10;
  2199. margin-top: 800px;
  2200. }
  2201. * {
  2202. background-color: var(--color-background-active);
  2203. }
  2204. :deep(.t-collapse) {
  2205. /* min-height: 100vh; */
  2206. border: none;
  2207. }
  2208. :deep(.t-collapse-panel__header) {
  2209. border: none;
  2210. font-size: 12px;
  2211. font-weight: 400;
  2212. padding: 8px 8px 8px 16px;
  2213. & > .t-space {
  2214. display: none;
  2215. }
  2216. & > .t-space:focus {
  2217. display: inline-flex;
  2218. }
  2219. &:hover .t-collapse-panel__icon,
  2220. &:hover > .flex {
  2221. color: var(--color-primary);
  2222. }
  2223. .t-collapse-panel__icon,
  2224. .t-collapse-panel__icon * {
  2225. transition: none;
  2226. }
  2227. .t-icon {
  2228. font-size: 13px;
  2229. }
  2230. }
  2231. :deep(.t-collapse-panel__wrapper:hover) {
  2232. .t-collapse-panel__header > .t-space {
  2233. display: inline-flex;
  2234. }
  2235. }
  2236. :deep(.t-collapse-panel__body) {
  2237. border: none;
  2238. }
  2239. :deep(.t-collapse-panel__content) {
  2240. background-color: var(--color-background-active);
  2241. padding: 4px 4px 20px 4px;
  2242. display: grid;
  2243. grid-template-columns: 1fr 1fr 1fr;
  2244. grid-row-gap: 12px;
  2245. }
  2246. :deep(.t-loading--center) {
  2247. width: 100px;
  2248. .t-loading__text {
  2249. margin-left: 8px;
  2250. height: 24px;
  2251. }
  2252. }
  2253. :deep(.t-image__error) {
  2254. .t-space-item:last-child {
  2255. display: none;
  2256. }
  2257. }
  2258. :deep(.t-image__loading) {
  2259. .t-space-item:last-child {
  2260. display: none;
  2261. }
  2262. }
  2263. .graphic {
  2264. position: relative;
  2265. padding: 10px 0;
  2266. border-radius: 2px;
  2267. border: 1px solid transparent;
  2268. &:hover {
  2269. cursor: pointer;
  2270. border-color: var(--color-primary);
  2271. }
  2272. p {
  2273. margin-top: 10px;
  2274. padding: 0 8px;
  2275. text-align: center;
  2276. font-size: 12px;
  2277. height: 12px;
  2278. line-height: 1;
  2279. overflow: hidden;
  2280. text-overflow: ellipsis;
  2281. display: -webkit-box;
  2282. -webkit-line-clamp: 1;
  2283. word-break: break-all;
  2284. -webkit-box-orient: vertical;
  2285. }
  2286. .t-image__wrapper {
  2287. height: 32px;
  2288. width: 32px;
  2289. margin: auto;
  2290. :deep(.t-image) {
  2291. border-radius: 2px;
  2292. }
  2293. }
  2294. svg {
  2295. color: var(--color);
  2296. height: 32px;
  2297. width: 100%;
  2298. margin: auto;
  2299. }
  2300. .svg-box {
  2301. height: 32px;
  2302. width: 32px;
  2303. margin-left: calc(50% - 16px);
  2304. margin-top: 10px;
  2305. margin-bottom: 10px;
  2306. &:deep(svg) {
  2307. height: 100%;
  2308. width: 100%;
  2309. .cls-1 {
  2310. stroke: var(--color) !important;
  2311. stroke-width: 4px;
  2312. fill: none;
  2313. stroke-dasharray: none;
  2314. opacity: 1;
  2315. }
  2316. }
  2317. }
  2318. .price {
  2319. position: absolute;
  2320. top: 8px;
  2321. right: 8px;
  2322. display: inline-block;
  2323. z-index: 1;
  2324. border-radius: 2px;
  2325. background-color: #ff400060;
  2326. color: var(--color-bland);
  2327. font-size: 10px;
  2328. line-height: 1;
  2329. padding: 3px;
  2330. }
  2331. }
  2332. }
  2333. .two-columns {
  2334. :deep(.t-collapse-panel__content) {
  2335. grid-template-columns: 1fr 1fr;
  2336. }
  2337. .graphic {
  2338. .t-image__wrapper {
  2339. width: 100px;
  2340. height: 56.25px;
  2341. background-color: '#162030';
  2342. }
  2343. }
  2344. }
  2345. }
  2346. .context-menu-box {
  2347. position: fixed;
  2348. z-index: 200;
  2349. & > div {
  2350. width: 140px !important;
  2351. position: static;
  2352. }
  2353. :deep(.t-menu) {
  2354. .t-menu__item {
  2355. &.t-is-opened {
  2356. background-color: var(--color-background-popup-hover);
  2357. transition: none !important;
  2358. }
  2359. }
  2360. .t-fake-arrow {
  2361. transform: rotate(-90deg) !important;
  2362. }
  2363. .t-fake-arrow--active {
  2364. transform: rotate(90deg) !important;
  2365. }
  2366. }
  2367. }
  2368. :deep(.dialog-manage) {
  2369. .t-dialog__body {
  2370. height: 500px;
  2371. overflow: scroll;
  2372. }
  2373. .t-collapse {
  2374. border: 0px;
  2375. }
  2376. .t-collapse-panel__header {
  2377. border: 0px;
  2378. }
  2379. .t-collapse-panel__body {
  2380. border: 0px;
  2381. }
  2382. .t-collapse-panel__content {
  2383. display: grid;
  2384. grid-template-columns: 1fr 1fr 1fr 1fr;
  2385. /* grid-template-rows: repeat(100, 100px); */
  2386. grid-auto-rows: minmax(100px, auto);
  2387. grid-row-gap: 20px;
  2388. grid-column-gap: 20px;
  2389. }
  2390. .t-collapse-panel__body {
  2391. background: #fff0;
  2392. }
  2393. .manage-list {
  2394. max-height: 310px;
  2395. border: 1px solid #fff;
  2396. position: relative;
  2397. border: 1px solid #535f79;
  2398. position: relative;
  2399. border-radius: 2px;
  2400. .t-checkbox {
  2401. position: absolute;
  2402. right: 0px;
  2403. top: 10px;
  2404. z-index: 10;
  2405. }
  2406. }
  2407. }
  2408. :deep(.dialog-charge){
  2409. .t-dialog__body {
  2410. iframe{
  2411. width: 100%;
  2412. height: 80vh;
  2413. }
  2414. }
  2415. }
  2416. }
  2417. </style>