create.vue 82 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670
  1. <template>
  2. <div class="doc-container">
  3. <div class="editor-top">
  4. <div class="left">
  5. <div class="doc" v-if="type == 'document'">
  6. <span>当前打开文档:</span
  7. >{{ docAttr.title == "" ? "新建文档" : docAttr.title }}
  8. </div>
  9. <div class="doc" v-else-if="type == 'module'">
  10. <span>当前打开模块:</span
  11. >{{ coms[0].name == "" ? "新建模块" : coms[0].name }}
  12. </div>
  13. <div class="doc" v-else>
  14. <span>当前打开模版:</span
  15. >{{ docAttr.title == "" ? "新建模版" : docAttr.title }}
  16. </div>
  17. <div class="creator">
  18. <span>创建者:</span
  19. ><!-- {{ userInfo && userInfo.username }} -->
  20. </div>
  21. </div>
  22. <div class="right">
  23. <el-button
  24. type="primary"
  25. size="mini"
  26. @click="onSaveAs"
  27. v-if="
  28. type !== 'module' && type == 'document' && articleId == undefined
  29. "
  30. >保存文档</el-button
  31. ><!-- v-if="docAttr.id > 0" -->
  32. <el-button
  33. type="primary"
  34. size="mini"
  35. @click="renew"
  36. v-if="
  37. articleId !== undefined && type !== 'module' && type == 'document'
  38. "
  39. >更新文档</el-button
  40. >
  41. <!-- <el-popover
  42. placement="bottom"
  43. trigger="click"
  44. v-if="type !== 'module' && type !== 'document'"
  45. > -->
  46. <el-button
  47. type="primary"
  48. v-if="type !== 'module' && type !== 'document' && !articleId"
  49. @click="onSaveUpload"
  50. >保存</el-button
  51. >
  52. <el-button
  53. type="primary"
  54. v-if="type !== 'module' && type !== 'document' && articleId"
  55. @click="onUpload"
  56. >更新</el-button
  57. >
  58. <!-- <el-button
  59. slot="reference"
  60. type="primary"
  61. size="mini"
  62. style="margin: 0 10px"
  63. v-if="$store.state.user.name == 'admin'"
  64. >保存并更新模版</el-button
  65. >
  66. </el-popover> -->
  67. <!-- <el-button
  68. type="primary"
  69. size="mini"
  70. v-if="$store.state.user.name == 'admin'"
  71. @click="onSaveUpload"
  72. >保存并更新模版</el-button
  73. > -->
  74. <el-button
  75. type="primary"
  76. size="mini"
  77. v-if="type !== 'module' && type == 'document'"
  78. @click="onOpenView"
  79. >预览导出
  80. </el-button>
  81. <el-button type="primary" size="mini" @click="onClose">
  82. 关闭文档
  83. </el-button>
  84. </div>
  85. </div>
  86. <div class="editor-content">
  87. <div class="left_scheme">
  88. <div class="scheme-header">
  89. <div class="title">
  90. 请选择可用的方案
  91. <span class="count">[方案数量:47]</span>
  92. <i class="el-icon-menu"></i>
  93. </div>
  94. <div class="search">
  95. <el-input
  96. v-model="searchKey"
  97. placeholder="请输入搜索"
  98. prefix-icon="el-icon-search"
  99. clearable
  100. >
  101. </el-input>
  102. </div>
  103. <div class="action-btns">
  104. <el-button type="primary" size="small" @click="createScheme"
  105. >新建方案</el-button
  106. >
  107. <el-button type="primary" size="small" @click="createCategory"
  108. >新建分类</el-button
  109. >
  110. </div>
  111. <div class="current-scheme">
  112. 当前方案: {{ currentScheme || "已选择方案三" }}
  113. </div>
  114. </div>
  115. <div class="scheme-content">
  116. <el-tree
  117. :data="schemeData"
  118. :props="defaultProps"
  119. @node-click="handleNodeClick"
  120. :default-expanded-keys="expandedKeys"
  121. >
  122. <span class="custom-tree-node" slot-scope="{ node, data }">
  123. <span>
  124. <i class="el-icon-folder" v-if="data.children"></i>
  125. <i class="el-icon-document" v-else></i>
  126. {{ node.label }}
  127. </span>
  128. </span>
  129. </el-tree>
  130. </div>
  131. </div>
  132. <!-- 资源 -->
  133. <div class="natural">
  134. <div class="resource-header-title">
  135. <div class="title-left">
  136. <span>请选择可用的资源</span>
  137. <span class="resource-count">[资源明细] 资源数量:474</span>
  138. </div>
  139. <i class="el-icon-menu"></i>
  140. </div>
  141. <div class="resource-container">
  142. <div class="resource-header">
  143. <el-input
  144. v-model="resourceSearchKey"
  145. placeholder="请输入选择"
  146. prefix-icon="el-icon-search"
  147. clearable
  148. >
  149. </el-input>
  150. <div class="action-btns">
  151. <el-button type="primary" @click="createResource"
  152. >新建资源</el-button
  153. >
  154. <el-button type="primary" @click="createResourceCategory"
  155. >新建资源分类</el-button
  156. >
  157. </div>
  158. </div>
  159. <div class="resource-status">
  160. 已打开1个资源,已选择3个资源
  161. <el-button size="small" plain @click="refreshResources"
  162. >更新</el-button
  163. >
  164. </div>
  165. <div class="resource-content">
  166. <el-collapse v-model="activeCategories">
  167. <!-- DLP产品 -->
  168. <el-collapse-item name="dlp">
  169. <template slot="title">
  170. <span>DLP产品</span>
  171. <!-- <i class="el-icon-arrow-up" :class="{ 'is-active': activeCategories.includes('dlp') }"></i> -->
  172. </template>
  173. <div class="resource-list">
  174. <div
  175. v-for="item in dlpProducts"
  176. :key="item.id"
  177. class="resource-item"
  178. >
  179. <el-checkbox v-model="item.selected">
  180. {{ item.name }}
  181. </el-checkbox>
  182. <!-- <i class="el-icon-menu"></i> -->
  183. </div>
  184. </div>
  185. </el-collapse-item>
  186. <!-- LED产品系列 -->
  187. <el-collapse-item name="led">
  188. <template slot="title">
  189. <span>LED产品系列</span>
  190. <!-- <i class="el-icon-arrow-up"></i> -->
  191. </template>
  192. <div class="resource-list">
  193. <div
  194. v-for="item in ledProducts"
  195. :key="item.id"
  196. class="resource-item"
  197. >
  198. <el-checkbox v-model="item.selected">
  199. {{ item.name }}
  200. </el-checkbox>
  201. <i class="el-icon-menu"></i>
  202. </div>
  203. </div>
  204. </el-collapse-item>
  205. <!-- 处理器 -->
  206. <el-collapse-item name="processor">
  207. <template slot="title">
  208. <span>处理器</span>
  209. <!-- <i class="el-icon-arrow-up"></i> -->
  210. </template>
  211. <div class="resource-list">
  212. <div
  213. v-for="item in processors"
  214. :key="item.id"
  215. class="resource-item"
  216. >
  217. <el-checkbox v-model="item.selected">
  218. {{ item.name }}
  219. </el-checkbox>
  220. <i class="el-icon-menu"></i>
  221. </div>
  222. </div>
  223. </el-collapse-item>
  224. <!-- 售后服务 -->
  225. <el-collapse-item name="service">
  226. <template slot="title">
  227. <span>售后服务</span>
  228. <!-- <i class="el-icon-arrow-up"></i> -->
  229. </template>
  230. <div class="resource-list">
  231. <div
  232. v-for="item in services"
  233. :key="item.id"
  234. class="resource-item"
  235. >
  236. <el-checkbox v-model="item.selected">
  237. {{ item.name }}
  238. </el-checkbox>
  239. <i class="el-icon-menu"></i>
  240. </div>
  241. </div>
  242. </el-collapse-item>
  243. </el-collapse>
  244. </div>
  245. </div>
  246. </div>
  247. <!-- <div class="neary-doc">
  248. <div class="left-content">
  249. <div class="new-article">
  250. <div v-if="showView == 0 && type !== 'module'">
  251. <el-collapse v-model="activeNames">
  252. <el-collapse-item
  253. title="最新文档"
  254. name="-1"
  255. v-if="type == 'document'"
  256. >
  257. <div
  258. v-for="(it, index) in articleList"
  259. draggable
  260. :key="it.id"
  261. :data-index="index"
  262. data-type="article"
  263. class="sub-menus"
  264. >
  265. <div @click="onLoadArticle(it.id)" style="cursor: pointer">
  266. {{ it.title }}
  267. </div>
  268. </div>
  269. </el-collapse-item>
  270. <el-collapse-item
  271. title="模版列表"
  272. name="-2"
  273. v-if="showView == 0"
  274. >
  275. <div
  276. v-for="(it, index) in templateList"
  277. draggable
  278. :key="it.id"
  279. :data-index="index"
  280. data-type="article"
  281. class="sub-menus"
  282. >
  283. <div @click="onTemplateInfo(it.id)" style="cursor: pointer">
  284. {{ it.title }}
  285. </div>
  286. </div>
  287. </el-collapse-item>
  288. </el-collapse>
  289. </div>
  290. <div v-if="showView == 1" class="scrollable-container">
  291. <el-collapse
  292. v-model="activeModel"
  293. :accordion="true"
  294. @change="handleItemClick"
  295. class="borderless-collapse"
  296. >
  297. <el-collapse-item
  298. v-for="(item, itemIndex) in categoryList"
  299. :key="itemIndex"
  300. :title="item.name"
  301. :name="item.id"
  302. class="min-width-content"
  303. >
  304. <el-collapse
  305. v-if="item.children && item.children.length"
  306. v-model="item.activeChildren"
  307. @change="handleItemVal"
  308. v-show="item.children"
  309. class="borderless-collapse"
  310. >
  311. <el-collapse-item
  312. v-for="(child, childIndex) in item.children"
  313. :key="childIndex"
  314. :title="child.name"
  315. :name="child.id"
  316. class="min-width-content"
  317. >
  318. <el-collapse
  319. v-if="child.children && child.children.length"
  320. v-model="child.activeChildren"
  321. @change="handleChildItemVal"
  322. v-show="child.children"
  323. class="borderless-collapse"
  324. >
  325. <el-collapse-item
  326. v-for="(
  327. grandChild, grandChildIndex
  328. ) in child.children"
  329. :key="grandChildIndex"
  330. :title="grandChild.name"
  331. :name="grandChild.id"
  332. class="min-width-content"
  333. >
  334. <el-collapse
  335. v-if="
  336. grandChild.children && grandChild.children.length
  337. "
  338. v-model="grandChild.activeChildren"
  339. @change="handleGrandChildItemVal"
  340. v-show="grandChild.children"
  341. class="borderless-collapse"
  342. >
  343. <el-collapse-item
  344. v-for="(
  345. greatGrandChild, greatGrandChildIndex
  346. ) in grandChild.children"
  347. :key="greatGrandChildIndex"
  348. :title="greatGrandChild.name"
  349. :name="greatGrandChild.id"
  350. class="min-width-content"
  351. >
  352. <el-collapse
  353. v-if="
  354. greatGrandChild.children &&
  355. greatGrandChild.children.length
  356. "
  357. v-model="greatGrandChild.activeChildren"
  358. @change="handlegreatGrandChildItemVal"
  359. v-show="greatGrandChild.children"
  360. class="borderless-collapse"
  361. >
  362. <el-collapse-item
  363. v-for="(
  364. fiveChild, fiveIndex
  365. ) in greatGrandChild.children"
  366. :key="fiveIndex"
  367. :title="fiveChild.name"
  368. :name="fiveChild.id"
  369. class="min-width-content"
  370. >
  371. <draggable
  372. v-model="fiveChild.dataList"
  373. :options="{
  374. group: { name: 'itxst', pull: 'clone' },
  375. sort: true,
  376. }"
  377. :disabled="type === 'module'"
  378. >
  379. <transition-group>
  380. <div
  381. class="sub-menus min-width-content"
  382. v-for="(
  383. fiveIts, fiveIndex
  384. ) in fiveChild.dataList"
  385. :key="fiveIndex"
  386. >
  387. <div style="cursor: move">
  388. {{ fiveIts.name }}
  389. </div>
  390. </div>
  391. </transition-group>
  392. </draggable>
  393. </el-collapse-item>
  394. </el-collapse>
  395. <draggable
  396. v-model="greatGrandChild.dataList"
  397. :options="{
  398. group: { name: 'itxst', pull: 'clone' },
  399. sort: true,
  400. }"
  401. :disabled="type == 'module'"
  402. >
  403. <transition-group>
  404. <div
  405. class="sub-menus min-width-content"
  406. v-for="(
  407. its, index
  408. ) in greatGrandChild.dataList"
  409. :key="index"
  410. >
  411. <div style="cursor: move">
  412. {{ its.name }}
  413. </div>
  414. </div>
  415. </transition-group>
  416. </draggable>
  417. </el-collapse-item>
  418. </el-collapse>
  419. <draggable
  420. v-model="grandChild.dataList"
  421. :options="{
  422. group: { name: 'itxst', pull: 'clone' },
  423. sort: true,
  424. }"
  425. :disabled="type == 'module'"
  426. >
  427. <transition-group>
  428. <div
  429. class="sub-menus min-width-content"
  430. v-for="(it, index) in grandChild.dataList"
  431. :key="index"
  432. >
  433. <div style="cursor: move">{{ it.name }}</div>
  434. </div>
  435. </transition-group>
  436. </draggable>
  437. </el-collapse-item>
  438. </el-collapse>
  439. <draggable
  440. v-model="child.dataList"
  441. :options="{
  442. group: { name: 'itxst', pull: 'clone' },
  443. sort: true,
  444. }"
  445. :disabled="type == 'module'"
  446. >
  447. <transition-group>
  448. <div
  449. class="sub-menus min-width-content"
  450. v-for="(it, index) in child.dataList"
  451. :key="index"
  452. >
  453. <div style="cursor: move">{{ it.name }}</div>
  454. </div>
  455. </transition-group>
  456. </draggable>
  457. </el-collapse-item>
  458. </el-collapse>
  459. <draggable
  460. v-model="item.dataList"
  461. :options="{
  462. group: { name: 'itxst', pull: 'clone' },
  463. sort: true,
  464. }"
  465. :disabled="type == 'module'"
  466. >
  467. <transition-group>
  468. <div
  469. class="sub-menus min-width-content"
  470. v-for="(it, index) in item.dataList"
  471. :key="index"
  472. >
  473. <div style="cursor: move">{{ it.name }}</div>
  474. </div>
  475. </transition-group>
  476. </draggable>
  477. </el-collapse-item>
  478. </el-collapse>
  479. </div>
  480. </div>
  481. </div>
  482. <div class="right-sidebarew">
  483. <div
  484. v-if="type !== 'module'"
  485. class="sidebar-item"
  486. :class="showView == 0 ? 'active-item' : ''"
  487. @click="viewDocument"
  488. >
  489. <span v-if="type == 'document'">查看文档</span>
  490. <span v-else>查看模版</span>
  491. </div>
  492. <div
  493. v-if="type !== 'document'"
  494. class="sidebar-item"
  495. :class="showView == 1 ? 'active-item' : ''"
  496. @click="viewModule"
  497. >
  498. 模块列表
  499. </div>
  500. </div>
  501. </div> -->
  502. <div class="editor-main">
  503. <!-- 添加tab页导航 -->
  504. <div class="editor-tabs">
  505. <el-tabs v-model="activeTab" type="card" @tab-click="handleClick">
  506. <el-tab-pane label="目录" name="catalog">
  507. <div class="catalog-content">
  508. <!-- 目录内容展示区域 -->
  509. <el-tree
  510. :data="catalogData"
  511. :props="catalogProps"
  512. default-expand-all
  513. @node-click="handleCatalogClick"
  514. >
  515. <span class="custom-tree-node" slot-scope="{ data }"
  516. ><!-- node, -->
  517. <span>{{ data.label }}</span>
  518. <span v-if="data.children" class="expand-icon">
  519. <i class="el-icon-arrow-right"></i>
  520. </span>
  521. </span>
  522. </el-tree>
  523. </div>
  524. </el-tab-pane>
  525. <el-tab-pane label="模板内容" name="template">
  526. <div class="template-content">
  527. <!-- 原有的menus和editor内容 -->
  528. <div class="menus-box">
  529. <menus
  530. @onEvents="onInsert"
  531. @onVariable="uptadeVariable"
  532. :comArr="coms"
  533. ></menus>
  534. </div>
  535. <div
  536. class="editor-box"
  537. ref="tabHtml"
  538. v-loading="loading"
  539. element-loading-text="加载中..."
  540. element-loading-spinner="el-icon-loading"
  541. >
  542. <editor
  543. :coms="coms"
  544. :comIndex="comIndex"
  545. :isAdmin="isAdmin"
  546. :templateCate="categoryList"
  547. :insertCmd="insertCmd"
  548. @onSetActiveIndex="onSetActiveIndex"
  549. @onInsert="onInsert"
  550. @onLoadArticle="onLoadArticle"
  551. @onRebuild="onRebuild"
  552. @onDelete="onRemove"
  553. @onSetComs="onSetComs"
  554. ></editor>
  555. </div>
  556. </div>
  557. </el-tab-pane>
  558. </el-tabs>
  559. </div>
  560. </div>
  561. </div>
  562. <!-- 新增资源选择弹框 -->
  563. <!-- <el-dialog
  564. title="请选择可用的资源"
  565. :visible.sync="resourceDialogVisible"
  566. width="800px"
  567. custom-class="resource-dialog"
  568. >
  569. <div class="resource-container">
  570. <div class="resource-header">
  571. <el-input
  572. v-model="resourceSearchKey"
  573. placeholder="请输入选择"
  574. prefix-icon="el-icon-search"
  575. clearable
  576. >
  577. </el-input>
  578. <div class="action-btns">
  579. <el-button type="primary" @click="createResource"
  580. >新建资源</el-button
  581. >
  582. <el-button type="primary" @click="createResourceCategory"
  583. >新建资源分类</el-button
  584. >
  585. </div>
  586. </div>
  587. <div class="resource-status">
  588. 已打开1个资源,已选择3个资源
  589. <el-button size="small" plain @click="refreshResources"
  590. >更新</el-button
  591. >
  592. </div>
  593. <div class="resource-content">
  594. <el-collapse v-model="activeCategories">
  595. <el-collapse-item name="dlp">
  596. <template slot="title">
  597. <span>DLP产品</span>
  598. <i class="el-icon-arrow-up"></i>
  599. </template>
  600. <div class="resource-list">
  601. <div
  602. v-for="item in dlpProducts"
  603. :key="item.id"
  604. class="resource-item"
  605. >
  606. <el-checkbox v-model="item.selected">
  607. {{ item.name }}
  608. </el-checkbox>
  609. <i class="el-icon-menu"></i>
  610. </div>
  611. </div>
  612. </el-collapse-item>
  613. <el-collapse-item name="led">
  614. <template slot="title">
  615. <span>LED产品系列</span>
  616. <i class="el-icon-arrow-up"></i>
  617. </template>
  618. <div class="resource-list">
  619. <div
  620. v-for="item in ledProducts"
  621. :key="item.id"
  622. class="resource-item"
  623. >
  624. <el-checkbox v-model="item.selected">
  625. {{ item.name }}
  626. </el-checkbox>
  627. <i class="el-icon-menu"></i>
  628. </div>
  629. </div>
  630. </el-collapse-item>
  631. <el-collapse-item name="processor">
  632. <template slot="title">
  633. <span>处理器</span>
  634. <i class="el-icon-arrow-up"></i>
  635. </template>
  636. <div class="resource-list">
  637. <div
  638. v-for="item in processors"
  639. :key="item.id"
  640. class="resource-item"
  641. >
  642. <el-checkbox v-model="item.selected">
  643. {{ item.name }}
  644. </el-checkbox>
  645. <i class="el-icon-menu"></i>
  646. </div>
  647. </div>
  648. </el-collapse-item>
  649. <el-collapse-item name="service">
  650. <template slot="title">
  651. <span>售后服务</span>
  652. <i class="el-icon-arrow-up"></i>
  653. </template>
  654. <div class="resource-list">
  655. <div
  656. v-for="item in services"
  657. :key="item.id"
  658. class="resource-item"
  659. >
  660. <el-checkbox v-model="item.selected">
  661. {{ item.name }}
  662. </el-checkbox>
  663. <i class="el-icon-menu"></i>
  664. </div>
  665. </div>
  666. </el-collapse-item>
  667. </el-collapse>
  668. </div>
  669. </div>
  670. </el-dialog> -->
  671. <el-dialog
  672. :visible.sync="showViewForm"
  673. :close-on-click-modal="false"
  674. append-to-body
  675. v-el-drag-dialog
  676. width="850px"
  677. custom-class="prod-verify"
  678. title="文档预览"
  679. >
  680. <ViewForm :coms="coms" :docAttr="docAttr"></ViewForm>
  681. </el-dialog>
  682. <el-dialog
  683. :visible.sync="showProductAttr"
  684. append-to-body
  685. v-el-drag-dialog
  686. :close-on-click-modal="false"
  687. width="850px"
  688. custom-class="prod-verify"
  689. title="插入产品属性"
  690. >
  691. <ProductAttr
  692. :docAttr="docAttr"
  693. @onInsertProductAttr="onInsertProductAttr"
  694. ></ProductAttr>
  695. </el-dialog>
  696. <el-dialog
  697. :visible.sync="docVisible"
  698. append-to-body
  699. v-el-drag-dialog
  700. :close-on-click-modal="false"
  701. width="500px"
  702. custom-class="prod-verify"
  703. title="文档信息"
  704. >
  705. <el-form
  706. :model="docForm"
  707. :rules="docRules"
  708. ref="docRef"
  709. label-position="left"
  710. label-width="100"
  711. >
  712. <el-form-item label="文档名称:" prop="title">
  713. <el-input
  714. v-model="docForm.title"
  715. style="width: 60%"
  716. class="input-item"
  717. placeholder="请填写文档名称"
  718. :disabled="docAttr.id > 0"
  719. />
  720. </el-form-item>
  721. <el-form-item label="文档分类:" prop="category_id">
  722. <el-select
  723. v-model="docForm.category_id"
  724. style="width: 60%"
  725. placeholder="请选择所属分类"
  726. :disabled="docAttr.id > 0"
  727. >
  728. <el-option
  729. v-for="(item, index) in articleCategoryList"
  730. :key="index"
  731. :label="item.name"
  732. :value="item.id"
  733. />
  734. </el-select>
  735. </el-form-item>
  736. <el-form-item label="创建人:">
  737. {{ userInfo && userInfo.username }}
  738. </el-form-item>
  739. </el-form>
  740. <span slot="footer" class="dialog-footer">
  741. <el-button @click="closeDoc">取 消</el-button>
  742. <el-button type="primary" @click="submitDoc">确 定</el-button>
  743. </span>
  744. </el-dialog>
  745. </div>
  746. </template>
  747. <script>
  748. import { findData } from "@/api/sourceData";
  749. /* import utils from "@/utils/fun"; // 方法类 */
  750. import { searchDocument, pageDocument } from "@/api/document";
  751. import menus from "./com/menus";
  752. import editor from "./com/editor";
  753. import Attribute from "./com/components/Attribute";
  754. import attributeVar from "./com/components/Attribute/attributeVar/index.vue";
  755. import ProductAttr from "./com/components/ProductAttr";
  756. import {
  757. searchTemplateCategory,
  758. searchTemplate,
  759. getTemplateInfo,
  760. getAllCategory,
  761. } from "@/api/template";
  762. import docAttr from "./com/components/Attribute/docAttr";
  763. import comList from "./com/components/Attribute/comList";
  764. import Directory from "./com/components/Attribute/Directory";
  765. import { getCurrentUserInfo } from "@/api/api";
  766. import {
  767. createDocument,
  768. updateDocument,
  769. getDocumentInfo,
  770. exportDocument,
  771. searchDocumentCategory,
  772. } from "@/api/document";
  773. import ViewForm from "./com/view";
  774. import elDragDialog from "@/directive/el-drag-dialog";
  775. import draggable from "vuedraggable";
  776. import htmlDocx from "html-docx-js/dist/html-docx";
  777. import { searchFormula } from "@/api/formula";
  778. import axios from "axios";
  779. import settings from "@/settings";
  780. // import htmlDocx from "htmlDocx";
  781. export default {
  782. name: "create",
  783. components: {
  784. menus,
  785. editor,
  786. Attribute,
  787. comList,
  788. docAttr,
  789. ViewForm,
  790. ProductAttr,
  791. Directory,
  792. draggable,
  793. attributeVar,
  794. },
  795. directives: {
  796. elDragDialog,
  797. },
  798. data() {
  799. return {
  800. activeNames: "-1",
  801. nestedActiveNames: [],
  802. articleList: [],
  803. activeModel: "",
  804. templateList: [],
  805. categoryList: [],
  806. //组件相关
  807. coms: [],
  808. comIndex: 9999, //当前组件索引
  809. showProductAttr: false,
  810. comList: [],
  811. //文档属性
  812. docAttr: {
  813. id: 0,
  814. category_id: "",
  815. title: "",
  816. content: "",
  817. status: 5,
  818. links: "",
  819. linkProduct: [],
  820. linkProject: [],
  821. projects: "",
  822. },
  823. insertCmd: null,
  824. showViewForm: false,
  825. isAdmin: 2, //1是管理员,2非管理员
  826. //当前选中表格
  827. tabExt: {
  828. row: 0,
  829. col: 0,
  830. },
  831. userInfo: null,
  832. articleId: 0,
  833. loading: false, // 增加 loading 状态
  834. showView: 0, //查看 文档/模块
  835. childrenList: "",
  836. value: [],
  837. AttributeIndex: 0,
  838. catalogIndex: 0, //目录信息
  839. docuComIndex: 3,
  840. type: "",
  841. docVisible: false,
  842. docForm: {
  843. title: "",
  844. category_id: "",
  845. },
  846. docRules: {
  847. title: [{ required: true, message: "请输文档名称", trigger: "blur" }],
  848. category_id: [
  849. { required: true, message: "请选择文档分类", trigger: "change" },
  850. ],
  851. },
  852. articleCategoryList: [],
  853. //方案
  854. searchKey: "",
  855. currentScheme: "",
  856. expandedKeys: [], // 默认展开的节点
  857. schemeData: [
  858. {
  859. label: "LED项目",
  860. children: [],
  861. },
  862. {
  863. label: "LCD项目",
  864. children: [],
  865. },
  866. {
  867. label: "集成项目",
  868. children: [
  869. {
  870. label: "方案一",
  871. },
  872. {
  873. label: "方案二",
  874. },
  875. {
  876. label: "方案三",
  877. },
  878. ],
  879. },
  880. ],
  881. defaultProps: {
  882. children: "children",
  883. label: "label",
  884. },
  885. /* 资源 */
  886. resourceDialogVisible: false,
  887. resourceSearchKey: "",
  888. activeCategories: ["dlp", "led", "processor", "service"],
  889. dlpProducts: [
  890. { id: 1, name: "产品选型/DLP/单元/", selected: false },
  891. { id: 2, name: "产品选型/DLP/机芯/", selected: true },
  892. { id: 3, name: "产品选型/DLP/控制盒/", selected: true },
  893. ],
  894. ledProducts: [
  895. { id: 4, name: "产品选型/LED/黄河系/", selected: false },
  896. { id: 5, name: "产品选型/LED/华夏系/", selected: true },
  897. { id: 6, name: "产品选型/LED/黄河单元/", selected: false },
  898. ],
  899. processors: [
  900. { id: 7, name: "产品选型/处理器/D301/", selected: false },
  901. { id: 8, name: "产品选型/处理器/IPWH300/", selected: false },
  902. { id: 9, name: "产品选型/处理器/IPWD400/", selected: false },
  903. ],
  904. services: [
  905. { id: 10, name: "产品选型/处理器/IPWH300/", selected: false },
  906. { id: 11, name: "产品选型/处理器/IPWH301/", selected: false },
  907. { id: 12, name: "产品选型/处理器/IPWD400/", selected: false },
  908. ],
  909. /* 目录/模板 */
  910. activeTab: "template", // 默认显示模板内容tab
  911. catalogData: [
  912. {
  913. label: "1. 概述 4",
  914. children: [
  915. {
  916. label: "1.1. 强大的显示功能",
  917. children: [
  918. { label: "1.1.1. 计算机信号显示" },
  919. { label: "1.1.2. 视频信号显示" },
  920. { label: "1.1.3. 海量流媒体信号接入" },
  921. { label: "1.1.4. 网络信号显示" },
  922. { label: "1.1.5. 信号综合处理" },
  923. { label: "1.1.6. 显示效果及图像拼接" },
  924. ],
  925. },
  926. { label: "1.2. 任意开窗漫游显示" },
  927. { label: "1.3. 信号混合显示" },
  928. { label: "1.4. 全数字连接" },
  929. ],
  930. },
  931. {
  932. label: "2. 系统设计",
  933. children: [
  934. { label: "2.1. 设计标准及规范" },
  935. { label: "2.2. 系统规模及尺寸" },
  936. ],
  937. },
  938. ],
  939. catalogProps: {
  940. children: "children",
  941. label: "label",
  942. },
  943. };
  944. },
  945. watch: {
  946. coms: {
  947. handler(newComs, oldComs) {
  948. this.updateAttrs(newComs, oldComs);
  949. },
  950. immediate: true, //立即执行
  951. deep: true,
  952. },
  953. articleId: {
  954. handler(val) {
  955. if (val == null || val == undefined || val <= 0) return;
  956. if (this.$route.query.type == "document") {
  957. this.loadArticle(val);
  958. } else {
  959. this.onTemplateInfo(val);
  960. }
  961. //
  962. },
  963. immediate: true,
  964. deep: true,
  965. },
  966. },
  967. async mounted() {
  968. this.articleId = this.$route.query.articleId;
  969. this.type = this.$route.query.type;
  970. if (this.type == "module") {
  971. this.showView = 1;
  972. }
  973. this.searchArticle();
  974. await this.initCategoryList();
  975. await this.initCurrentUser();
  976. let templateId = this.$route.query.templateId;
  977. if (templateId > 0) {
  978. this.loadTemplateInfo(templateId);
  979. }
  980. this.isAdmin = 2; //this.userInfo ? this.userInfo.roleInfo.is_admin : 2;
  981. this.initArticleCategoryList();
  982. if (this.type !== "module" && this.type !== "document") {
  983. document.title = "新建模版-" + settings.title;
  984. }
  985. if (
  986. this.type !== "module" &&
  987. this.type !== "document" &&
  988. this.articleId !== undefined
  989. ) {
  990. document.title = this.docAttr.title + settings.title;
  991. }
  992. this.$nextTick(() => {
  993. const arrows = document.querySelectorAll(".el-collapse-item__arrow");
  994. arrows.forEach((arrow) => {
  995. arrow.style.margin = "0";
  996. });
  997. });
  998. },
  999. methods: {
  1000. /* 切换目录/模板 */
  1001. handleClick(val) {
  1002. if (val.name === "catalog") {
  1003. // 初始化目录数据
  1004. let catalogData = [];
  1005. this.coms.forEach((item, moduleIndex) => {
  1006. // 获取所有Directory类型的属性并排序
  1007. const directoryAttrs = item.attrs
  1008. .filter((attr) => attr.type === "Directory")
  1009. .sort((a, b) => {
  1010. // 首先按level排序
  1011. if (a.level !== b.level) {
  1012. return a.level - b.level;
  1013. }
  1014. // level相同时按number排序
  1015. return a.number.localeCompare(b.number, undefined, {
  1016. numeric: true,
  1017. });
  1018. });
  1019. directoryAttrs.forEach((attr) => {
  1020. const catalogItem = {
  1021. label: `${attr.number} ${attr.content}`,
  1022. level: attr.level,
  1023. moduleIndex: moduleIndex,
  1024. children: [],
  1025. };
  1026. // 根据level确定目录层级
  1027. if (attr.level === 1) {
  1028. // 一级目录直接添加到根
  1029. catalogData.push(catalogItem);
  1030. } else {
  1031. // 查找父级目录
  1032. let parent = this.findParentDirectory(catalogData, attr.number);
  1033. if (parent) {
  1034. parent.children.push(catalogItem);
  1035. }
  1036. }
  1037. });
  1038. });
  1039. console.log(catalogData);
  1040. // 更新目录数据
  1041. this.catalogData = catalogData;
  1042. // 强制更新视图
  1043. this.$nextTick(() => {
  1044. this.$forceUpdate();
  1045. });
  1046. }
  1047. },
  1048. // 查找父级目录的辅助方法
  1049. findParentDirectory(catalogData, number) {
  1050. const parentNumber = number.split(".").slice(0, -1).join(".");
  1051. const findInChildren = (items) => {
  1052. for (let item of items) {
  1053. if (item.label.startsWith(parentNumber + " ")) {
  1054. return item;
  1055. }
  1056. if (item.children) {
  1057. const found = findInChildren(item.children);
  1058. if (found) return found;
  1059. }
  1060. }
  1061. return null;
  1062. };
  1063. return findInChildren(catalogData);
  1064. },
  1065. /* 方案点击 */
  1066. handleNodeClick(data) {
  1067. this.currentScheme = data.label;
  1068. this.resourceDialogVisible = true; // 点击方案时打开资源选择弹框
  1069. },
  1070. createScheme() {
  1071. // 实现新建方案逻辑
  1072. this.$message.success("新建方案");
  1073. },
  1074. createCategory() {
  1075. // 实现新建分类逻辑
  1076. this.$message.success("新建分类");
  1077. },
  1078. /* 资源 */
  1079. createResource() {
  1080. this.$message.success("新建资源");
  1081. },
  1082. createResourceCategory() {
  1083. this.$message.success("新建资源分类");
  1084. },
  1085. refreshResources() {
  1086. this.$message.success("刷新资源列表");
  1087. },
  1088. /* 目录模板 */
  1089. handleCatalogClick(data) {
  1090. // 处理目录点击事件
  1091. console.log("点击的目录项:", data);
  1092. },
  1093. handleItemVal(value) {
  1094. this.$forceUpdate();
  1095. this.loadChildren(value);
  1096. },
  1097. handleChildItemClick(child) {
  1098. if (!child.children) {
  1099. this.loadChildren(child);
  1100. }
  1101. },
  1102. handleChildItemVal(value) {
  1103. this.$forceUpdate();
  1104. this.loadChildren(value);
  1105. },
  1106. handleGrandChildItemClick(grandChild) {
  1107. if (!grandChild.children) {
  1108. this.loadChildren(grandChild);
  1109. }
  1110. },
  1111. handleGrandChildItemVal(value) {
  1112. this.loadChildren(value);
  1113. this.$forceUpdate();
  1114. },
  1115. handlegreatGrandChildItemVal(greatGrandChild) {
  1116. this.loadChildren(greatGrandChild);
  1117. this.$forceUpdate();
  1118. },
  1119. async loadChildren(category) {
  1120. const category_id = category[category.length - 1];
  1121. try {
  1122. const res = await searchTemplateCategory({ parent_id: category_id });
  1123. if (res.status != 200 || res.data.length == 0) return;
  1124. const newChildren = res.data;
  1125. for (let i = 0; i < newChildren.length; i++) {
  1126. newChildren[i].dataList = await this.getTemplateList(
  1127. newChildren[i].id
  1128. );
  1129. }
  1130. this.insertChildrenById(this.categoryList, category_id, newChildren);
  1131. console.log(this.categoryList);
  1132. this.$forceUpdate(); // Force Vue to re-render the component
  1133. } catch (error) {
  1134. console.error("Error fetching template categories:", error);
  1135. }
  1136. },
  1137. insertChildrenById(list, id, newChildren) {
  1138. for (let item of list) {
  1139. if (item.id === id) {
  1140. this.$set(item, "children", newChildren); // Use Vue.set to ensure reactivity
  1141. return true; // Stop searching once the item is found
  1142. }
  1143. if (item.children && item.children.length > 0) {
  1144. const found = this.insertChildrenById(item.children, id, newChildren);
  1145. if (found) return true; // Stop searching if the item is found in deeper levels
  1146. }
  1147. }
  1148. return false; // Continue searching
  1149. },
  1150. /* 取消新增 */
  1151. closeDoc() {
  1152. this.docVisible = false;
  1153. this.docForm = {
  1154. title: "",
  1155. category_id: "",
  1156. };
  1157. },
  1158. /* 确定新增模块*/
  1159. submitDoc() {
  1160. this.$refs.docRef.validate((valid) => {
  1161. if (valid) {
  1162. this.docAttr.title = this.docForm.title;
  1163. this.docAttr.category_id = this.docForm.category_id;
  1164. this.onSave();
  1165. }
  1166. });
  1167. },
  1168. //加载文档分类
  1169. initArticleCategoryList() {
  1170. let _this = this;
  1171. searchDocumentCategory({ page: 1, pageSize: 99, status: 5 }).then(
  1172. (res) => {
  1173. if (res.status != 200) return;
  1174. _this.articleCategoryList = res.data.dataList;
  1175. }
  1176. );
  1177. },
  1178. updateAttrs(newComs, oldComs) {
  1179. console.log(newComs);
  1180. newComs.forEach((newCom, comIndex) => {
  1181. const oldCom = oldComs[comIndex];
  1182. if (oldCom) {
  1183. newCom.attrs.forEach((newAttr, attrIndex) => {
  1184. const oldAttr = oldCom.attrs[attrIndex];
  1185. if (oldAttr && newAttr.content !== oldAttr.content) {
  1186. // 内容发生变化,进行全局更新
  1187. this.updateGlobalAttr(newAttr.name, newAttr.content);
  1188. }
  1189. });
  1190. }
  1191. });
  1192. },
  1193. updateGlobalAttr(attrId, newContent) {
  1194. // 遍历所有组件,更新匹配的属性
  1195. this.coms.forEach((com) => {
  1196. com.attrs.forEach((attr) => {
  1197. // 只更新非 variableNull 类型的属性
  1198. if (attr.name === attrId && attr.type !== "variableNull") {
  1199. attr.content = newContent;
  1200. }
  1201. });
  1202. // 如果是文本区域,更新内容中的占位符
  1203. if (com.type === "TextArea") {
  1204. com.content = com.content.replace(
  1205. new RegExp(`{{${attrId}}}`, "g"),
  1206. (match) => {
  1207. const attr = com.attrs.find((a) => a.id === attrId);
  1208. if (attr && attr.type !== "variableNull") {
  1209. return newContent;
  1210. }
  1211. return match; // 保留 variableNull 类型的原始占位符
  1212. }
  1213. );
  1214. }
  1215. });
  1216. // 触发视图更新
  1217. this.replaceData(this.coms);
  1218. this.$forceUpdate();
  1219. },
  1220. async replaceData(data) {
  1221. for (let item of this.coms) {
  1222. for (let el of item.attrs) {
  1223. let attrId = el.id;
  1224. if (el.type === "formual") {
  1225. try {
  1226. let formual = await this.analysisFormual(el);
  1227. formual = await this.getRemote(formual);
  1228. el.content = eval(formual);
  1229. } catch (error) {
  1230. console.error("处理公式时出错:", error);
  1231. }
  1232. } else if (el.type === "variableNull") {
  1233. // 保留 variableNull 类型的原始内容
  1234. el.content = el.content || "请输入";
  1235. }
  1236. }
  1237. }
  1238. return data;
  1239. },
  1240. //分析公式
  1241. async analysisFormual(attrs) {
  1242. let _this = this;
  1243. // console.log("开始分析公式:", attrs.formula);
  1244. var pattern = /(\[.*?\]){3}/;
  1245. var formual = attrs.formula;
  1246. var reg = new RegExp(pattern);
  1247. while (true) {
  1248. var items = formual.match(reg);
  1249. if (items == null) break;
  1250. let itemName = items[0];
  1251. // console.log("处理项:", itemName);
  1252. try {
  1253. let data = await _this.getFormualData(itemName);
  1254. // console.log(`获取到的数据: ${itemName} = ${data}`);
  1255. if (data === null || data === undefined || isNaN(data)) {
  1256. console.warn(`获取到的数据无效: ${itemName}`);
  1257. formual = formual.replace(itemName, "(0)");
  1258. } else {
  1259. formual = formual.replace(itemName, `(${parseFloat(data)})`);
  1260. }
  1261. } catch (error) {
  1262. console.error(`处理 ${itemName} 时出错:`, error);
  1263. formual = formual.replace(itemName, "(0)");
  1264. }
  1265. }
  1266. // console.log("分析后的公式:", formual);
  1267. return formual;
  1268. },
  1269. async getFormualData(formualItem) {
  1270. let _this = this;
  1271. // console.log("开始获取公式数据:", formualItem);
  1272. var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
  1273. var reg = new RegExp(pattern);
  1274. let items = formualItem.match(reg);
  1275. // console.log("解析结果:", items);
  1276. let calResult = 0;
  1277. if (items && items[1] == "T") {
  1278. calResult = await _this.getModuleData(items[2], items[3]);
  1279. } else {
  1280. console.warn("无法解析公式项:", formualItem);
  1281. }
  1282. // console.log("计算结果:", calResult);
  1283. return calResult;
  1284. },
  1285. //获取本地文档模块数据
  1286. async getModuleData(code, attrName) {
  1287. let _this = this;
  1288. // console.log(`尝试获取模块数据: code=${code}, attrName=${attrName}`);
  1289. // console.log("当前 coms:", _this.coms);
  1290. let item = _this.coms.filter((o) => o.name == code);
  1291. // console.log(`找到的模块:`, item);
  1292. if (item.length > 0) {
  1293. let attr = item[0].attrs.filter((o) => o.name == attrName);
  1294. // console.log(`找到的属性:`, attr);
  1295. if (attr.length > 0) {
  1296. // console.log(`返回的值:`, attr[0].content);
  1297. return parseFloat(attr[0].content);
  1298. }
  1299. }
  1300. // console.log("未找到匹配的模块或属性,返回 0");
  1301. return 0;
  1302. },
  1303. async getRemote(formual) {
  1304. let _this = this;
  1305. var pattern = /\[(.*?)\]\[(.*?)\]\[(.*?)\]\[(.*?)\]/;
  1306. var reg = new RegExp(pattern);
  1307. while (true) {
  1308. let items = formual.match(reg);
  1309. if (items == null) break;
  1310. if (items[1] == "R") {
  1311. //表示获取远程数据
  1312. var dataIndex = items[4];
  1313. dataIndex = items[4].split(",");
  1314. let calResult = await _this.getRemoteData(
  1315. items[2],
  1316. items[3],
  1317. dataIndex[0],
  1318. dataIndex[1]
  1319. );
  1320. let itemName = items[0];
  1321. // 检查calResult是否为数字
  1322. if (!isNaN(calResult)) {
  1323. formual = formual.replace(
  1324. itemName,
  1325. "(" + parseFloat(calResult) + ")"
  1326. );
  1327. } else {
  1328. formual = formual.replace(itemName, `"${calResult}"`);
  1329. }
  1330. formual = formual.replace(
  1331. itemName,
  1332. "(" + parseFloat(calResult) + ")"
  1333. );
  1334. }
  1335. }
  1336. return formual;
  1337. },
  1338. async getRemoteData(code, sheet, row, col) {
  1339. let _this = this;
  1340. let result = 0;
  1341. let par = {
  1342. code: code,
  1343. sheetName: sheet,
  1344. row: row,
  1345. col: col,
  1346. };
  1347. /* if (!this.isEditing) {
  1348. this.loading = true;
  1349. this.progress = 0;
  1350. try {
  1351. const updateProgress = setInterval(() => {
  1352. if (this.progress < 90) {
  1353. this.progress += 10;
  1354. }
  1355. }, 100);
  1356. let res = await findData(par);
  1357. if (res.status == 200) {
  1358. result = res.data.result;
  1359. }
  1360. this.progress = 100;
  1361. clearInterval(updateProgress);
  1362. } catch (error) {
  1363. console.error("Error fetching remote data:", error);
  1364. } finally {
  1365. setTimeout(() => {
  1366. this.loading = false;
  1367. this.progress = 0;
  1368. }, 1000);
  1369. }
  1370. } else { */
  1371. // 如果正在编辑,直接获取数据而不显示进度条
  1372. try {
  1373. let res = await findData(par);
  1374. if (res.status == 200) {
  1375. result = res.data.result;
  1376. // 添加数据类型检查和转换
  1377. if (typeof result === "string" && !isNaN(result)) {
  1378. result = parseFloat(result);
  1379. }
  1380. }
  1381. } catch (error) {
  1382. console.error("获取远程数据错误:", error);
  1383. }
  1384. /* } */
  1385. return result;
  1386. },
  1387. /*
  1388. handleItemVal(value) {
  1389. console.log(value);
  1390. this.$forceUpdate();
  1391. }, */
  1392. async handleItemClick(item) {
  1393. const category = this.categoryList.find((cat) => cat.id === item);
  1394. if (!category) return;
  1395. if (!category.children) {
  1396. try {
  1397. const res = await searchTemplateCategory({ parent_id: item });
  1398. if (res.status != 200 || res.data.length == 0) return;
  1399. category.children = res.data;
  1400. for (let i = 0; i < category.children.length; i++) {
  1401. category.children[i].dataList = await this.getTemplateList(
  1402. category.children[i].id
  1403. );
  1404. }
  1405. } catch (error) {
  1406. console.error("Error fetching template categories:", error);
  1407. }
  1408. }
  1409. // 触发视图更新
  1410. this.$set(category, "activeChildren", category.activeChildren || []);
  1411. },
  1412. /* 切换标签 */
  1413. viewDocument() {
  1414. this.showView = 0;
  1415. },
  1416. viewModule() {
  1417. this.showView = 1;
  1418. },
  1419. /* 更新变量 */
  1420. /* uptadeVariable(value) {
  1421. for (const item of this.coms) {
  1422. for (const el of item.attrs) {
  1423. if (el.type === "variable") {
  1424. if (el.data.id == value.id) {
  1425. el.content = value.value;
  1426. el.data = value;
  1427. }
  1428. } else if (el.type === "constant") {
  1429. if (el.data.id == value.id) {
  1430. el.content = value.value;
  1431. el.data = value;
  1432. }
  1433. }
  1434. }
  1435. }
  1436. } */
  1437. uptadeVariable(value) {
  1438. const { id, value: newValue } = value;
  1439. this.coms.forEach((item) => {
  1440. item.attrs.forEach((el) => {
  1441. if (
  1442. (el.type === "variable" || el.type === "constant") &&
  1443. el.data.id === id
  1444. ) {
  1445. el.content = newValue;
  1446. el.data = value;
  1447. }
  1448. });
  1449. });
  1450. },
  1451. /* 更新检索内容 */
  1452. async uptadeSearch() {
  1453. for (const item of this.coms) {
  1454. for (const el of item.attrs) {
  1455. if (el.type === "ai") {
  1456. // await this.retrieval(el);
  1457. }
  1458. }
  1459. }
  1460. },
  1461. /* 初始化检索 */
  1462. async retrieval(el) {
  1463. this.loading = true; // 开始加载动画
  1464. try {
  1465. const response = await axios.post(
  1466. "http://58.246.234.210:7860/api/v1/run/3f84a841-cefd-44b3-9555-568cc3b6c2d2?stream=false",
  1467. {
  1468. input_value: el.search,
  1469. output_type: "chat",
  1470. input_type: "chat",
  1471. tweaks: {
  1472. "ChatInput-em6qC": {},
  1473. "ParseData-yO3YQ": {},
  1474. "Prompt-Wj75b": {},
  1475. "ChatOutput-zy9na": {},
  1476. "SplitText-O1knk": {},
  1477. "File-4j6Zd": {},
  1478. "OllamaEmbeddings-xbYXX": {},
  1479. "Chroma-OIejP": {},
  1480. "OllamaModel-04mEO": {},
  1481. "OllamaEmbeddings-UGvLP": {},
  1482. "Chroma-HzukO": {},
  1483. },
  1484. },
  1485. {
  1486. headers: {
  1487. "Content-Type": "application/json",
  1488. },
  1489. }
  1490. );
  1491. if (response.status === 200) {
  1492. // 假设返回的数据在 response.data.outputs[0].outputs[0].results.message.data.text 中
  1493. const resultText =
  1494. response.data.outputs[0].outputs[0].results.message.data.text;
  1495. // 将搜索词和生成的内容存储在 searchResult 对象中
  1496. el.content = resultText; // 重新赋值给原数组的对应 content
  1497. }
  1498. } catch (error) {
  1499. console.error("Error during retrieval:", error);
  1500. this.$message.error("检索失败,请稍后重试");
  1501. } finally {
  1502. this.loading = false; // 结束加载动画
  1503. }
  1504. },
  1505. async loadTemplateInfo(id) {
  1506. try {
  1507. // 获取模板信息
  1508. const { data } = await getTemplateInfo({ id });
  1509. // 设置默认值
  1510. if (!data.attrs || !data.type) {
  1511. Object.assign(data, {
  1512. attrs: "[]",
  1513. content: "请填写内容",
  1514. lay_id: "textArea",
  1515. type: "TextArea",
  1516. });
  1517. }
  1518. // 设置文档标题
  1519. document.title = data.name
  1520. ? `${data.name}-${settings.title}`
  1521. : "新建模块-" + settings.title;
  1522. // 解析属性
  1523. data.attrs = JSON.parse(data.attrs);
  1524. // 获取公式并更新属性
  1525. const {
  1526. data: { dataList },
  1527. } = await searchFormula({ page: 1, pageSize: 999 });
  1528. console.log(data);
  1529. data.attrs = data.attrs.map((item) => {
  1530. const formula = dataList.find((el) => el.id === item.id);
  1531. return formula
  1532. ? { ...item, formula: formula.formula, data: formula }
  1533. : item;
  1534. });
  1535. // 从 content 中提取 {{}} 包裹的 ID
  1536. const contentIds = (data.content.match(/{{([^}]+)}}/g) || []).map(
  1537. (match) => match.slice(2, -2).trim()
  1538. );
  1539. // 过滤 attrs,只保留在 content 中出现的 ID
  1540. data.attrs = data.attrs.filter((item) => contentIds.includes(item.id));
  1541. this.coms = [data];
  1542. } catch (error) {
  1543. console.error("加载模板信息失败:", error);
  1544. }
  1545. },
  1546. onExport(e) {
  1547. let _this = this;
  1548. _this.comIndex = -1;
  1549. let content = _this.$refs.tabHtml.innerHTML;
  1550. },
  1551. onOpenView(e) {
  1552. console.log("this.coms", this.coms);
  1553. this.showViewForm = true;
  1554. },
  1555. onClose() {
  1556. this.$router.back();
  1557. },
  1558. loadArticle(e) {
  1559. let _this = this;
  1560. _this.onLoadArticle(e);
  1561. /* getDocumentInfo({
  1562. id: e,
  1563. }).then((res) => {
  1564. if (res.status != 200) return;
  1565. _this.onLoadArticle(res.data);
  1566. }); */
  1567. },
  1568. handleDragStart(e) {
  1569. let data = {};
  1570. if (e.target.dataset.type == "article") {
  1571. let index = e.target.dataset.index;
  1572. data = {
  1573. optType: e.target.dataset.type,
  1574. item: this.articleList[index],
  1575. };
  1576. } else {
  1577. let index = e.target.dataset.index;
  1578. let subIndex = e.target.dataset.subIndex;
  1579. let item = this.categoryList[index].dataList[subIndex];
  1580. delete item.category;
  1581. data = {
  1582. ...item,
  1583. optType: e.target.dataset.type,
  1584. key: "addNew",
  1585. attrs: JSON.parse(item.attrs),
  1586. };
  1587. }
  1588. e.dataTransfer.setData("item", JSON.stringify(data));
  1589. this.operation = "drag";
  1590. },
  1591. onRebuild(updatedComList) {
  1592. this.coms = [...updatedComList];
  1593. this.$nextTick(() => {
  1594. this.$forceUpdate();
  1595. });
  1596. },
  1597. //初始化当前用户信息
  1598. async initCurrentUser() {
  1599. let _this = this;
  1600. let res = await getCurrentUserInfo();
  1601. if (res.status != 200) return;
  1602. _this.userInfo = res.data;
  1603. },
  1604. //加载文档信息
  1605. async onLoadArticle(id) {
  1606. try {
  1607. this.loading = true;
  1608. const res = await getDocumentInfo({ id });
  1609. if (res.status !== 200) {
  1610. throw new Error("Invalid response status");
  1611. }
  1612. this.docAttr = {
  1613. id: res.data.id,
  1614. category_id: Number(res.data.category_id),
  1615. title: res.data.title,
  1616. content: "",
  1617. status: res.data.status,
  1618. is_template: res.data.is_template,
  1619. linkProduct: res.data.linkProduct,
  1620. links: res.data.links,
  1621. linkProject: res.data.linkProject,
  1622. projects: res.data.projects,
  1623. };
  1624. const templateData =
  1625. typeof res.data.data === "string"
  1626. ? JSON.parse(res.data.data)
  1627. : res.data.data;
  1628. const updatedComs = await Promise.all(
  1629. templateData.map(async (el) => {
  1630. /* let templateInfo = { data: {} };
  1631. if (this.type !== "document") {
  1632. templateInfo = await getTemplateInfo({ id: el.id });
  1633. } */
  1634. const formulaData = await searchFormula({ page: 1, pageSize: 999 });
  1635. const attrs = el.attrs;
  1636. /* typeof templateInfo.data.attrs === "string"
  1637. ? JSON.parse(templateInfo.data.attrs)
  1638. : templateInfo.data.attrs || []; // Add a fallback empty array */
  1639. attrs.forEach((item) => {
  1640. if (item && item.data && item.data.id) {
  1641. const matchedFormula = formulaData.data.dataList.find(
  1642. (ite) => ite.id === item.data.id
  1643. );
  1644. if (matchedFormula) {
  1645. item.data = matchedFormula;
  1646. item.formula = matchedFormula.formula;
  1647. }
  1648. }
  1649. });
  1650. return { ...el /* , ...templateInfo.data, attrs */ };
  1651. })
  1652. );
  1653. this.coms = updatedComs;
  1654. console.log("coms", updatedComs);
  1655. if (this.type === "document" && this.articleId !== undefined) {
  1656. document.title = `${this.docAttr.title}-${settings.title}`;
  1657. }
  1658. this.uptadeSearch();
  1659. } catch (error) {
  1660. console.error("Error in onLoadArticle:", error);
  1661. } finally {
  1662. this.loading = false;
  1663. }
  1664. },
  1665. /* 加载模版信息 */
  1666. async onTemplateInfo(id) {
  1667. try {
  1668. this.loading = true;
  1669. // 获取文档信息
  1670. const res = await getDocumentInfo({ id });
  1671. if (res.status !== 200 || !res.data) {
  1672. throw new Error("无效的响应或未收到数据");
  1673. }
  1674. // 设置文档属性
  1675. this.docAttr = {
  1676. id: this.docAttr.id,
  1677. category_id: Number(this.docAttr.category_id),
  1678. title: res.data.title,
  1679. content: "",
  1680. status: res.data.status,
  1681. is_template: res.data.is_template,
  1682. linkProduct: res.data.linkProduct || [],
  1683. links: res.data.links || "",
  1684. linkProject: res.data.linkProject || [],
  1685. projects: res.data.projects || "",
  1686. };
  1687. // 解析文档数据
  1688. const documentData = res.data.data ? JSON.parse(res.data.data) : [];
  1689. console.log(documentData);
  1690. const updatedComs = await Promise.all(
  1691. documentData.map(async (docEl) => {
  1692. if (!docEl || !docEl.id) {
  1693. console.warn("无效的文档项:", docEl);
  1694. return null;
  1695. }
  1696. // 获取模板信息
  1697. const templateInfo = await getTemplateInfo({ id: docEl.id });
  1698. // 获取公式数据
  1699. const formulaData = await searchFormula({ page: 1, pageSize: 999 });
  1700. // 使用模板的 content 作为基础
  1701. let content = templateInfo.data.content;
  1702. // 使用模板的 attrs 作为基础,但排除 Directory 类型
  1703. let attrs = templateInfo.data.attrs
  1704. ? JSON.parse(templateInfo.data.attrs).filter(
  1705. (attr) => attr.type !== "Directory"
  1706. )
  1707. : [];
  1708. // 从文档数据中提取所有 Directory 类型的属性
  1709. const docDirectories = docEl.attrs.filter(
  1710. (attr) => attr.type === "Directory"
  1711. );
  1712. // 将文档中的 Directory 属性添加到 attrs 中
  1713. attrs = [...attrs, ...docDirectories];
  1714. // 解析 content 中的所有项
  1715. const contentItems = (content.match(/{{([^}]+)}}/g) || []).map(
  1716. (match) => match.slice(2, -2)
  1717. );
  1718. console.log("contentItems", contentItems);
  1719. // 确保 content 中引用的所有 Directory 项都存在于 attrs 中
  1720. contentItems.forEach((itemId) => {
  1721. if (
  1722. itemId.startsWith("Directory_") &&
  1723. !attrs.some((attr) => attr.id === itemId)
  1724. ) {
  1725. const [, moduleIndex, level] = itemId.split("_");
  1726. attrs.push({
  1727. type: "Directory",
  1728. id: itemId,
  1729. name: "目录信息",
  1730. intro: "目录信息",
  1731. number: "",
  1732. content: "",
  1733. level: parseInt(level),
  1734. moduleIndex: parseInt(moduleIndex),
  1735. });
  1736. }
  1737. });
  1738. // 更新公式数据
  1739. attrs = attrs.map((item) => {
  1740. if (item.type === "formual" && item.data && item.data.id) {
  1741. const matchedFormula = formulaData.data.dataList.find(
  1742. (ite) => ite.id === item.data.id
  1743. );
  1744. if (matchedFormula) {
  1745. return {
  1746. ...item,
  1747. data: matchedFormula,
  1748. formula: matchedFormula.formula,
  1749. };
  1750. }
  1751. }
  1752. return item;
  1753. });
  1754. // 返回更新后的数据,以模板信息为主,但 Directory 项完全使用文档信息
  1755. return { ...templateInfo.data, attrs, content };
  1756. })
  1757. );
  1758. // 过滤掉无效的组件
  1759. this.coms = updatedComs.filter(Boolean);
  1760. console.log("组件", this.coms);
  1761. console.log("模版", this.docAttr);
  1762. if (this.articleId !== undefined) {
  1763. document.title = `${this.docAttr.title}-${settings.title}`;
  1764. }
  1765. this.uptadeSearch();
  1766. } catch (error) {
  1767. console.error("加载模板信息时出错:", error);
  1768. this.$message.error("加载模板信息时出错,请稍后重试");
  1769. } finally {
  1770. this.loading = false;
  1771. }
  1772. },
  1773. onRemove(index) {
  1774. this.coms.splice(index, 1);
  1775. },
  1776. /* 目录信息 */
  1777. onCatalogIndex(e) {
  1778. this.catalogIndex = e;
  1779. if (
  1780. (this.docuComIndex =
  1781. 3 || this.comIndex == 9998 || this.AttributeIndex == 1)
  1782. ) {
  1783. this.comIndex = 0;
  1784. this.AttributeIndex = 0;
  1785. this.docuComIndex = 0;
  1786. }
  1787. this.$nextTick(() => {
  1788. this.$forceUpdate();
  1789. });
  1790. },
  1791. onSetActiveIndexs(e) {
  1792. this.docuComIndex = e;
  1793. if (
  1794. this.AttributeIndex == 1 ||
  1795. this.comIndex == 9998 ||
  1796. this.catalogIndex == 9997
  1797. ) {
  1798. this.catalogIndex = 0;
  1799. this.AttributeIndex = 0;
  1800. this.comIndex = 0;
  1801. }
  1802. },
  1803. //设置当前索引
  1804. onSetActiveIndex(e) {
  1805. this.comIndex = e;
  1806. if (
  1807. this.AttributeIndex == 1 ||
  1808. this.docuComIndex == 3 ||
  1809. this.catalogIndex == 9997
  1810. ) {
  1811. this.catalogIndex = 0;
  1812. this.docuComIndex = 0;
  1813. }
  1814. },
  1815. /* 属性变量 */
  1816. onAttributeIndex(e) {
  1817. this.AttributeIndex = e;
  1818. if (
  1819. (this.docuComIndex =
  1820. 3 || this.comIndex == 9998 || this.catalogIndex == 9997)
  1821. ) {
  1822. this.catalogIndex = 0;
  1823. this.comIndex = 0;
  1824. this.docuComIndex = 0;
  1825. }
  1826. },
  1827. /* 更新 */
  1828. renew() {
  1829. let _this = this;
  1830. _this.docVisible = true;
  1831. this.docForm.title = _this.docAttr.title;
  1832. this.docForm.category_id = _this.docAttr.category_id;
  1833. },
  1834. /* 保存 */
  1835. onSaveAs(e) {
  1836. let _this = this;
  1837. if (_this.coms.length <= 0) {
  1838. _this.$alert("请填写内容");
  1839. return;
  1840. }
  1841. _this.docAttr.id = "";
  1842. _this.docVisible = true;
  1843. this.docForm.title = _this.docAttr.title;
  1844. this.docForm.category_id = _this.docAttr.category_id;
  1845. },
  1846. //保存文档
  1847. onSave(e) {
  1848. let _this = this;
  1849. if (_this.coms.length <= 0) {
  1850. _this.$alert("增加组件");
  1851. return;
  1852. }
  1853. if (_this.docAttr.category_id == "" || _this.docAttr.category_id <= 0) {
  1854. _this.$alert("请选择文档分类");
  1855. return;
  1856. }
  1857. if (_this.docAttr.title == "") {
  1858. _this.$alert("请填写文档标题");
  1859. return;
  1860. }
  1861. _this.docAttr.links = JSON.stringify(_this.docAttr.linkProduct);
  1862. _this.docAttr.projects = JSON.stringify(_this.docAttr.linkProject);
  1863. _this.docAttr.data = JSON.stringify(_this.coms);
  1864. _this.docAttr.is_template = 0;
  1865. /* _this.docAttr.user_name = _this.$store.state.user.name;
  1866. _this.docAttr.user_id = _this.$store.state.user.id; 获取用户id,名称 */
  1867. if (_this.docAttr.id > 0) {
  1868. updateDocument(_this.docAttr).then((res) => {
  1869. if (res.status != 200) return; //更新文档
  1870. _this.docAttr.id = res.data;
  1871. _this.$alert("文档更新成功");
  1872. _this.docVisible = false;
  1873. _this.docForm = {
  1874. title: "",
  1875. category_id: "",
  1876. };
  1877. _this.searchArticle();
  1878. });
  1879. } else {
  1880. createDocument(_this.docAttr).then((res) => {
  1881. if (res.status != 200) return; //保存文档
  1882. _this.docAttr.id = res.data;
  1883. _this.articleId = res.data;
  1884. _this.$alert("文档保存成功");
  1885. _this.docVisible = false;
  1886. _this.docForm = {
  1887. title: "",
  1888. category_id: "",
  1889. };
  1890. _this.searchArticle();
  1891. });
  1892. }
  1893. },
  1894. /*更新 */
  1895. onUpload() {
  1896. let _this = this;
  1897. if (_this.coms.length <= 0) {
  1898. _this.$alert("增加组件");
  1899. return;
  1900. }
  1901. /* if (_this.docAttr.category_id == "" || _this.docAttr.category_id <= 0) {
  1902. _this.$alert("请选择分类");
  1903. return;
  1904. } */
  1905. if (_this.docAttr.title == "") {
  1906. _this.$alert("请填写模版标题");
  1907. return;
  1908. }
  1909. _this.docAttr.links = JSON.stringify(_this.docAttr.linkProduct);
  1910. _this.docAttr.projects = JSON.stringify(_this.docAttr.linkProject);
  1911. _this.docAttr.data = JSON.stringify(_this.coms);
  1912. _this.docAttr.is_template = 1;
  1913. _this.docAttr.id = this.$route.query.articleId;
  1914. /* _this.docAttr.user_name = _this.$store.state.user.name;
  1915. _this.docAttr.user_id = _this.$store.state.user.id; 获取用户id,名称*/
  1916. updateDocument(_this.docAttr).then((res) => {
  1917. if (res.status != 200) return; //更新文档
  1918. _this.docAttr.id = res.data;
  1919. _this.$alert("模版更新成功");
  1920. _this.searchArticle();
  1921. });
  1922. },
  1923. /* 保存并更新模版 */
  1924. onSaveUpload(e) {
  1925. let _this = this;
  1926. if (_this.coms.length <= 0) {
  1927. _this.$alert("增加组件");
  1928. return;
  1929. }
  1930. /* if (_this.docAttr.category_id == "" || _this.docAttr.category_id <= 0) {
  1931. _this.$alert("请选择分类");
  1932. return;
  1933. } */
  1934. if (_this.docAttr.title == "") {
  1935. _this.$alert("请填写模版标题");
  1936. return;
  1937. }
  1938. _this.docAttr.links = JSON.stringify(_this.docAttr.linkProduct);
  1939. _this.docAttr.projects = JSON.stringify(_this.docAttr.linkProject);
  1940. _this.docAttr.data = JSON.stringify(_this.coms);
  1941. _this.docAttr.is_template = 1;
  1942. /* _this.docAttr.user_name = _this.$store.state.user.name;
  1943. _this.docAttr.user_id = _this.$store.state.user.id; 获取用户id,名称*/
  1944. /* if (_this.docAttr.id > 0) {
  1945. updateDocument(_this.docAttr).then((res) => {
  1946. if (res.status != 200) return; //更新文档
  1947. _this.docAttr.id = res.data;
  1948. _this.$alert("模版更��成功");
  1949. _this.searchArticle();
  1950. });
  1951. } else { */
  1952. createDocument(_this.docAttr).then((res) => {
  1953. if (res.status != 200) return; //保存文档
  1954. _this.docAttr.id = res.data;
  1955. _this.articleId = res.data;
  1956. _this.$alert("模版保存成功");
  1957. _this.searchArticle();
  1958. });
  1959. /* } */
  1960. },
  1961. //设置组件值
  1962. onSetComs(e) {
  1963. let _this = this;
  1964. _this.coms = [...e];
  1965. },
  1966. onAddLayer(cateIndex, dataIndex) {
  1967. let _this = this;
  1968. let item = _this.categoryList[cateIndex].dataList[dataIndex];
  1969. let data = {
  1970. ...item,
  1971. attrs: JSON.parse(item.attrs),
  1972. };
  1973. delete data.category;
  1974. _this.coms.push(data);
  1975. _this.comIndex = _this.coms.length - 1;
  1976. },
  1977. //处理插入事件
  1978. onInsert(e) {
  1979. let _this = this;
  1980. switch (e.key) {
  1981. case "article": //插入图文
  1982. _this.insertArticle();
  1983. break;
  1984. case "table": //插入图表
  1985. _this.insertTable();
  1986. break;
  1987. case "sourceData": //插入原数据
  1988. _this.insertSourceData(e);
  1989. break;
  1990. case "formual": //插入公式
  1991. _this.insertFormual(e);
  1992. break;
  1993. case "constant": //插入常量
  1994. _this.insertConstant(e);
  1995. break;
  1996. case "variable": //插入变量
  1997. _this.insertVariable(e);
  1998. break;
  1999. case "pager": //插入分页符
  2000. _this.insertPager();
  2001. break;
  2002. case "attr":
  2003. this.insertProductAttr();
  2004. break;
  2005. case "Directory": //插入主题
  2006. _this.insertDirectory(e);
  2007. break;
  2008. case "addNew": //插入新记录
  2009. _this.insertNew(e);
  2010. break;
  2011. case "InsertNull":
  2012. _this.insertVal();
  2013. break;
  2014. case "ai": //插入ai
  2015. _this.insertAI(e);
  2016. break;
  2017. }
  2018. },
  2019. /* 插入空值 */
  2020. insertVal() {
  2021. let _this = this;
  2022. if (_this.comIndex < 0) {
  2023. _this.$alert("请选择插入图层");
  2024. return false;
  2025. }
  2026. let com = _this.coms[_this.comIndex];
  2027. let uniqueId = "val" + Date.now(); // 使用时间戳创建唯一ID
  2028. let data = {
  2029. type: "variableNull",
  2030. id: uniqueId,
  2031. dataId: "",
  2032. name: "非变量",
  2033. intro: "",
  2034. content: "请输入",
  2035. data: "",
  2036. };
  2037. com.attrs.push(data);
  2038. if (com.type == "TextArea") {
  2039. //如果是图文,更新内容
  2040. _this.insertCmd = {
  2041. content: "{{" + data.id + "}}",
  2042. };
  2043. } else {
  2044. //仅对图表中插入有效
  2045. if (_this.comIndex >= 0) {
  2046. _this.setTableData(data.id);
  2047. }
  2048. }
  2049. },
  2050. /* 插入ai */
  2051. insertAI(e) {
  2052. let _this = this;
  2053. if (_this.comIndex < 0) {
  2054. _this.$alert("请选择插入图层");
  2055. return false;
  2056. }
  2057. let com = _this.coms[_this.comIndex];
  2058. let data = {
  2059. type: "ai",
  2060. id: "ai" + (com.attrs.length + 1),
  2061. dataId: "",
  2062. name: "AI",
  2063. intro: "插入AI",
  2064. content: e.content.result,
  2065. search: e.content.searchTerm,
  2066. };
  2067. com.attrs.push(data);
  2068. if (com.type == "TextArea") {
  2069. //如果是图文,更新内容
  2070. _this.insertCmd = {
  2071. content: "{{" + data.id + "}}",
  2072. };
  2073. }
  2074. },
  2075. insertProductAttr() {
  2076. if (this.docAttr.linkProduct.length <= 0) {
  2077. this.$alert("请选择文档关联商品信息");
  2078. return false;
  2079. }
  2080. this.showProductAttr = true;
  2081. },
  2082. //插入目录
  2083. insertDirectory(e) {
  2084. let _this = this;
  2085. if (_this.comIndex < 0) {
  2086. _this.$alert("请选择插入图层");
  2087. return false;
  2088. }
  2089. let com = _this.coms[_this.comIndex];
  2090. let uniqueId = `Directory_${_this.comIndex}_${com.attrs.length + 1}`;
  2091. // 获取当前层级
  2092. let currentLevel = e.content.level || 1;
  2093. // 生成带有模块索引和层级的内容
  2094. let { number, content } = this.generateNumberedContent(
  2095. _this.comIndex,
  2096. currentLevel
  2097. );
  2098. let data = {
  2099. type: "Directory",
  2100. id: uniqueId,
  2101. name: "目录信息",
  2102. intro: "目录信息",
  2103. number: number,
  2104. content: content,
  2105. level: currentLevel,
  2106. moduleIndex: _this.comIndex,
  2107. };
  2108. // 使用 $set 来确保响应式更新
  2109. this.$set(com.attrs, com.attrs.length, data);
  2110. // 强制更新视图
  2111. this.$forceUpdate();
  2112. // 使用 nextTick 确保 DOM 更新后再检查
  2113. this.$nextTick(() => {
  2114. if (!com.attrs[com.attrs.length - 1].content) {
  2115. this.$set(com.attrs[com.attrs.length - 1], "content", content);
  2116. this.$forceUpdate();
  2117. }
  2118. });
  2119. // 使用新的唯一 ID 在插入命令中
  2120. _this.insertCmd = {
  2121. content: `{{${uniqueId}}}`,
  2122. };
  2123. },
  2124. generateNumberedContent(moduleIndex, level) {
  2125. let number = this.generateLevelPrefix(moduleIndex, level);
  2126. let content = this.coms[moduleIndex].type === "TextArea" ? "" : "";
  2127. return { number, content };
  2128. },
  2129. generateLevelPrefix(moduleIndex, level) {
  2130. let prefix = [];
  2131. let currentModule = this.coms[moduleIndex];
  2132. // 获取当前模块中已存在的目录项
  2133. let existingDirectories = currentModule.attrs.filter(
  2134. (attr) => attr.type === "Directory"
  2135. );
  2136. // 计算当前层级的序号
  2137. let currentLevelCount =
  2138. existingDirectories.filter((dir) => dir.level === level).length + 1;
  2139. // 构建多级序号
  2140. for (let i = 1; i <= level; i++) {
  2141. if (i === 1) {
  2142. prefix.push(moduleIndex + 1);
  2143. } else if (i === level) {
  2144. prefix.push(currentLevelCount);
  2145. } else {
  2146. // 对于中间层级,找到最近的上级目录项
  2147. let parentLevel = existingDirectories
  2148. .filter((dir) => dir.level === i - 1)
  2149. .pop();
  2150. prefix.push(parentLevel ? parentLevel.number.split(".")[i - 1] : 1);
  2151. }
  2152. }
  2153. return prefix.join(".");
  2154. },
  2155. onInsertProductAttr(e) {
  2156. let _this = this;
  2157. this.showProductAttr = false;
  2158. if (_this.comIndex < 0) {
  2159. _this.$alert("请选择插入图层");
  2160. return false;
  2161. }
  2162. let com = _this.coms[_this.comIndex];
  2163. let data = {
  2164. type: "ProductAttr",
  2165. id: "ProductAttr" + (com.attrs.length + 1),
  2166. dataId: e.id,
  2167. name: "商品属性",
  2168. intor: "商品属性",
  2169. content: "",
  2170. attrs: e,
  2171. };
  2172. com.attrs.push(data);
  2173. _this.insertCmd = {
  2174. content: "{{" + data.id + "}}",
  2175. };
  2176. },
  2177. //插入新记录
  2178. insertNew(e) {
  2179. let _this = this;
  2180. _this.coms.push(e);
  2181. },
  2182. //插入分页
  2183. insertPager() {
  2184. let _this = this;
  2185. if (_this.comIndex < 0) {
  2186. _this.$alert("请选择插入图层");
  2187. return false;
  2188. }
  2189. let com = _this.coms[_this.comIndex];
  2190. let data = {
  2191. type: "pager",
  2192. id: "pager" + (com.attrs.length + 1),
  2193. name: "分页符",
  2194. intor: "强制分页",
  2195. content: "",
  2196. };
  2197. com.attrs.push(data);
  2198. if (com.type == "TextArea") {
  2199. //如果是图文,更新内容
  2200. _this.insertCmd = {
  2201. content: "<div>{{" + data.id + "}}</div>",
  2202. };
  2203. }
  2204. },
  2205. //插入图文
  2206. insertArticle() {
  2207. /* let _this = this;
  2208. _this.coms.push({
  2209. type: "TextArea",
  2210. lay_id: "textArea",
  2211. code: "模块名",
  2212. name: "图文",
  2213. intro: "图文介绍",
  2214. isEdit: 2,
  2215. content: "请填写内容",
  2216. attrs: [],
  2217. });
  2218. _this.comIndex = _this.coms.length - 1; */
  2219. let _this = this;
  2220. let newArticle = {
  2221. type: "TextArea",
  2222. lay_id: "textArea",
  2223. code: "模块名",
  2224. name: "图文",
  2225. intro: "图文介绍",
  2226. isEdit: 2,
  2227. content: "请填写内容",
  2228. attrs: [],
  2229. };
  2230. _this.coms.push(newArticle);
  2231. _this.comIndex = _this.coms.length - 1;
  2232. // 添加一些日志来帮助调试
  2233. console.log("New article added:", newArticle);
  2234. console.log("Current coms:", _this.coms);
  2235. console.log("New comIndex:", _this.comIndex);
  2236. },
  2237. //插入表格
  2238. insertTable() {
  2239. let _this = this;
  2240. _this.coms.push({
  2241. type: "Table",
  2242. lay_id: "Table",
  2243. code: "模块名",
  2244. name: "图表名称",
  2245. intro: "图表介绍",
  2246. isEdit: 2,
  2247. tableHeader: this.initTableHeader(),
  2248. tableData: [{}],
  2249. htmlData: "",
  2250. attrs: [],
  2251. });
  2252. _this.comIndex = _this.coms.length - 1;
  2253. },
  2254. initTableHeader() {
  2255. var start = 65;
  2256. var data = [];
  2257. for (var i = start; i <= start + 25; i++) {
  2258. data.push(String.fromCharCode(i));
  2259. }
  2260. return data;
  2261. },
  2262. //插入变量
  2263. insertConstant(e) {
  2264. let _this = this;
  2265. // console.log("insertconstant");
  2266. if (_this.comIndex < 0) {
  2267. _this.$alert("请选择插入图层");
  2268. return false;
  2269. }
  2270. let com = _this.coms[_this.comIndex];
  2271. let data = {
  2272. type: "constant",
  2273. id: e.content.code + (com.attrs.length + 1),
  2274. dataId: e.id,
  2275. name: e.content.code,
  2276. intro: e.content.intro,
  2277. content: e.content.value,
  2278. data: e.content,
  2279. };
  2280. com.attrs.push(data);
  2281. if (com.type == "TextArea") {
  2282. //如果是图文,更新内容
  2283. _this.insertCmd = {
  2284. content: "{{" + data.id + "}}",
  2285. };
  2286. } else {
  2287. //仅对图表中插入有效
  2288. if (_this.comIndex >= 0) {
  2289. _this.setTableData(data.id);
  2290. }
  2291. }
  2292. },
  2293. //插入变量
  2294. insertVariable(e) {
  2295. let _this = this;
  2296. if (_this.comIndex < 0) {
  2297. _this.$alert("请选择插入图层");
  2298. return false;
  2299. }
  2300. let com = _this.coms[_this.comIndex];
  2301. let data = {
  2302. type: "variable",
  2303. id: e.content.code + (com.attrs.length + 1),
  2304. dataId: e.id,
  2305. name: e.content.code,
  2306. intro: e.content.intro,
  2307. content: e.content.value,
  2308. data: e.content,
  2309. };
  2310. com.attrs.push(data);
  2311. if (com.type == "TextArea") {
  2312. //如果是图文,更新内容
  2313. _this.insertCmd = {
  2314. content: "{{" + data.id + "}}",
  2315. };
  2316. } else {
  2317. //仅对图表中插入有效
  2318. if (_this.comIndex >= 0) {
  2319. _this.setTableData(data.id);
  2320. }
  2321. }
  2322. },
  2323. //插入原数据
  2324. insertSourceData(e) {
  2325. let _this = this;
  2326. if (_this.comIndex < 0) {
  2327. _this.$alert("请选择插入图层");
  2328. return false;
  2329. }
  2330. let com = _this.coms[_this.comIndex];
  2331. let data = {
  2332. type: "sourceData",
  2333. id: "sourceData" + (com.attrs.length + 1),
  2334. dataId: "",
  2335. name: "源数据",
  2336. intro: "插入源数据",
  2337. formula:
  2338. "[R][" +
  2339. e.content.tb +
  2340. "][" +
  2341. e.content.sheet +
  2342. "][" +
  2343. e.content.r +
  2344. "," +
  2345. e.content.c +
  2346. "]",
  2347. content: e.content.value,
  2348. data: e.content,
  2349. };
  2350. com.attrs.push(data);
  2351. if (com.type == "TextArea") {
  2352. //如果是图文,更新内容
  2353. _this.insertCmd = {
  2354. content: "{{" + data.id + "}}",
  2355. };
  2356. }
  2357. },
  2358. //插入公式
  2359. insertFormual(e) {
  2360. let _this = this;
  2361. if (_this.comIndex < 0) {
  2362. _this.$alert("请选择插入图层");
  2363. return false;
  2364. }
  2365. let com = _this.coms[_this.comIndex];
  2366. let data = {
  2367. type: "formual",
  2368. id: "formual" + (com.attrs.length + 1),
  2369. dataId: e.id,
  2370. name: e.content.name,
  2371. intro: e.content.intro,
  2372. formula: e.content.formula,
  2373. content: 0,
  2374. data: e.content,
  2375. };
  2376. com.attrs.push(data);
  2377. if (com.type == "TextArea") {
  2378. //如果是图文,更新内容
  2379. _this.insertCmd = {
  2380. content: "{{" + data.id + "}}",
  2381. };
  2382. } else {
  2383. //仅对图表中插入有效
  2384. if (_this.comIndex >= 0) {
  2385. _this.setTableData(data.id);
  2386. }
  2387. }
  2388. },
  2389. //获取模版分类信息
  2390. async initCategoryList() {
  2391. let _this = this;
  2392. /* let res = await getAllCategory({list:1 });
  2393. if(res.status!=200)return;
  2394. let dataList=res.data;
  2395. for(var i=0;i<dataList.length;i++){
  2396. for (var j=0;j<dataList[i].children.length;j++){
  2397. let dataId=dataList[i].children[j].id;
  2398. for(var k=0;k<dataList[i].children[j].dataList.length;k++){
  2399. dataList[i].children[j].dataList[k].attrs=JSON.parse(dataList[i].children[j].dataList[k].attrs)
  2400. }
  2401. // dataList[i].children[j].dataList=await _this.getTemplateList(dataId)
  2402. }
  2403. }
  2404. // console.log("dataList",dataList)
  2405. _this.categoryList=dataList; */
  2406. let res = await searchTemplateCategory({
  2407. page: 1,
  2408. pageSize: 99,
  2409. parent_id: 0,
  2410. status: 5,
  2411. });
  2412. if (res.status != 200) return;
  2413. _this.categoryList = res.data.dataList;
  2414. for (var i = 0; i < _this.categoryList.length; i++) {
  2415. _this.categoryList[i].dataList = await _this.getTemplateList(
  2416. _this.categoryList[i].id
  2417. );
  2418. }
  2419. },
  2420. //获取模版列表
  2421. async getTemplateList(categoryId) {
  2422. let _this = this;
  2423. let res = await searchTemplate({
  2424. page: 1,
  2425. pageSize: 999,
  2426. category_id: categoryId,
  2427. status: 5,
  2428. });
  2429. if (res.status != 200) return [];
  2430. let dataList = res.data.dataList.map((item) => {
  2431. // 添加空值检查
  2432. if (!item.attrs) {
  2433. item.attrs = "[]";
  2434. }
  2435. if (!item.content) {
  2436. item.content = "";
  2437. }
  2438. try {
  2439. // 解析 attrs,添加错误处理
  2440. item.attrs =
  2441. typeof item.attrs === "string"
  2442. ? JSON.parse(item.attrs)
  2443. : item.attrs;
  2444. // 从 content 中提取所有 {{}} 包裹的 ID,添加空值检查
  2445. const contentIds = (
  2446. (item.content || "").match(/{{([^}]+)}}/g) || []
  2447. ).map((match) => match.slice(2, -2).trim());
  2448. // 确保 attrs 是数组
  2449. item.attrs = Array.isArray(item.attrs) ? item.attrs : [];
  2450. // 过滤 attrs,只保留在 content 中出现的 ID
  2451. item.attrs = item.attrs.filter(
  2452. (attr) => attr && attr.id && contentIds.includes(attr.id)
  2453. );
  2454. } catch (error) {
  2455. console.error("Error processing template item:", error);
  2456. item.attrs = [];
  2457. }
  2458. return item;
  2459. });
  2460. return dataList;
  2461. },
  2462. //获取文档列表
  2463. searchArticle() {
  2464. let _this = this;
  2465. pageDocument({
  2466. page: 1,
  2467. pageSize: 99,
  2468. }).then((res) => {
  2469. if (res.status != 200) return;
  2470. _this.articleList = res.data.dataList.filter(
  2471. (el) => el.is_template == 0
  2472. );
  2473. _this.templateList = res.data.dataList.filter(
  2474. (el) => el.is_template == 1
  2475. );
  2476. });
  2477. },
  2478. },
  2479. };
  2480. </script>
  2481. <style lang="scss">
  2482. @import "./create.scss";
  2483. .el-collapse,
  2484. .el-collapse-item__wrap {
  2485. border: none;
  2486. }
  2487. .el-collapse,
  2488. .el-collapse-item__header {
  2489. border: none;
  2490. .el-collapse-item__arrow {
  2491. margin: 0;
  2492. }
  2493. }
  2494. .borderless-collapse {
  2495. border: none;
  2496. ::v-deep .el-collapse-item__header,
  2497. ::v-deep .el-collapse-item__wrap,
  2498. ::v-deep .el-collapse-item__content,
  2499. ::v-deep .el-collapse-item {
  2500. border: none;
  2501. }
  2502. ::v-deep .el-collapse-item__wrap {
  2503. border-bottom: none !important;
  2504. }
  2505. }
  2506. .scrollable-container {
  2507. overflow-x: auto;
  2508. white-space: nowrap;
  2509. width: 350px;
  2510. padding-bottom: 10px;
  2511. }
  2512. .min-width-content {
  2513. /* display: inline-block;
  2514. vertical-align: top; */
  2515. min-width: 150px;
  2516. white-space: normal;
  2517. }
  2518. // 树节点样式调整
  2519. ::v-deep .el-tree-node__content {
  2520. height: 32px;
  2521. &:hover {
  2522. background-color: #f5f7fa;
  2523. }
  2524. }
  2525. ::v-deep .el-tree-node.is-current > .el-tree-node__content {
  2526. background-color: #f0f7ff;
  2527. color: #409eff;
  2528. }
  2529. /*.el-collapse-item {
  2530. display: inline-block;
  2531. vertical-align: top;
  2532. } */
  2533. </style>