DataSource.vue 77 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869
  1. <template>
  2. <div
  3. class="content"
  4. style="height: calc(100vh - 82px); overflow-y: auto"
  5. v-if="group === '数据'"
  6. >
  7. <div class="data-header">
  8. <div
  9. class="flex mb-16"
  10. style="justify-content: space-between; padding-right: 8px"
  11. >
  12. <div style="line-height: 32px">数据列表</div>
  13. <div class="flex">
  14. <t-tooltip content="批量导入数据图元到画布" placement="top">
  15. <div @click="onCheckAllChange" class="icon-box">
  16. <DragDropIcon :style="{
  17. color: data.checkAll ? 'var(--color-primary)' : '',
  18. }"/>
  19. </div>
  20. </t-tooltip>
  21. <t-tooltip content="开启全局数据模拟" placement="top">
  22. <div @click="onChangeMock" class="icon-box">
  23. <RouterWaveIcon
  24. :style="{
  25. color: data.enableMock ? 'var(--color-primary)' : '',
  26. }"
  27. />
  28. </div>
  29. </t-tooltip>
  30. <t-dropdown :minColumnWidth="168">
  31. <div class="icon-box">
  32. <AddIcon />
  33. </div>
  34. <t-dropdown-menu>
  35. <t-dropdown-item @click="onShowIot">
  36. <div style="width:100%"> 物联网平台
  37. <t-tooltip content="需配合乐吾乐物联网平台使用此功能" placement="right">
  38. <HelpCircleIcon style="font-size: 14px" class="ml-4 hover"/>
  39. </t-tooltip>
  40. </div>
  41. </t-dropdown-item>
  42. <t-dropdown-item @click="addSql">
  43. <div style="width:100%">SQL数据源
  44. <t-tooltip content="需配合乐吾乐物联网平台使用此功能" placement="right">
  45. <HelpCircleIcon style="font-size: 14px" class="ml-4 hover"/>
  46. </t-tooltip>
  47. </div>
  48. </t-dropdown-item>
  49. <t-dropdown-item @click="addNetwork('mqtt')"> MQTT </t-dropdown-item>
  50. <t-dropdown-item @click="addNetwork('websocket')"> Websocket </t-dropdown-item>
  51. <t-dropdown-item @click="addNetwork('http')"> HTTP </t-dropdown-item>
  52. <t-dropdown-item @click="addNetwork('SSE')"> SSE </t-dropdown-item>
  53. </t-dropdown-menu>
  54. </t-dropdown>
  55. </div>
  56. </div>
  57. <div class="flex">
  58. <!-- <t-tooltip content="可批量导入数据图元到画布" placement="top">
  59. <t-checkbox v-model="data.checkAll" @change="onCheckAllChange"
  60. >批量导入到画布</t-checkbox
  61. >
  62. </t-tooltip> -->
  63. <!-- <t-tooltip content="开启全局数据模拟" placement="top">
  64. <t-checkbox v-model="data.enableMock" @change="onChangeMock"
  65. >开启</t-checkbox
  66. >
  67. </t-tooltip> -->
  68. <div class="input-search" style="width: 100%;margin-top: 0px;">
  69. <div class="btn">
  70. <search-icon class="hover" />
  71. </div>
  72. <t-input
  73. v-model="dataSearch"
  74. @change="onSearchData"
  75. @enter="onSearchData"
  76. placeholder="搜索我的数据列表"
  77. />
  78. </div>
  79. </div>
  80. </div>
  81. <div v-if="data.iotTree?.length">
  82. <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
  83. <!-- <div class="flex"> -->
  84. <!-- <ApplicationIcon class="tree-icon mt-8" /> -->
  85. <div class="datasource-title">物联网平台</div>
  86. <!-- </div> -->
  87. <!-- <div>
  88. <Edit2Icon class="mr-12 hover" style="width: 14px;height: 14px;" @click="onShowIot" />
  89. </div> -->
  90. </div>
  91. <!-- <div> -->
  92. <div
  93. :draggable="data.checkAll ? true : false"
  94. @dragstart="onAddShape($event, data.iotTree,'iot')"
  95. @dragend="onAddShapeEnd"
  96. >
  97. <t-tree
  98. :draggable="false"
  99. v-model="allChecked"
  100. style="overflow-y: hidden"
  101. activeMultiple
  102. :data="data.iotTree"
  103. :expand-parent="true"
  104. :checkable="data.checkAll"
  105. :checkStrictly="false"
  106. :filter="dataFilter"
  107. />
  108. </div>
  109. <!-- </div> -->
  110. <div
  111. id="dragElem-iot"
  112. style="position: absolute; left: 0; z-index: -999"
  113. v-if="data.iotTree.length"
  114. >
  115. <div v-for="device in data.iotTree">
  116. <div
  117. class="flex mt-4"
  118. v-for="(prop, i) in device.children"
  119. v-show="allChecked.includes(prop.value)"
  120. >
  121. <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
  122. <div class="ml-4">{{ prop.mock }}</div>
  123. </div>
  124. </div>
  125. </div>
  126. </div>
  127. <div v-if="data.sqls?.length">
  128. <div class="flex mt-16" style="height: 32px">
  129. <!-- <DataIcon class="tree-icon" /> -->
  130. <div class="datasource-title">SQL数据源</div>
  131. </div>
  132. <div
  133. :draggable="data.checkAll ? true : false"
  134. @dragstart="onAddShape($event, data.sqls,'sql')"
  135. @dragend="onAddShapeEnd"
  136. >
  137. <t-tree
  138. :draggable="false"
  139. :key="sqlTreeKey"
  140. hover
  141. style="overflow-y: hidden"
  142. activeMultiple
  143. :data="data.sqls"
  144. :expand-parent="true"
  145. :checkable="data.checkAll"
  146. :checkStrictly="false"
  147. >
  148. <template #operations="{ node }">
  149. <tepmlate v-if="!node.getParent()">
  150. <Edit2Icon
  151. class="mr-12"
  152. @click="editSql(node.data, node.getIndex())"
  153. />
  154. <DeleteIcon class="mr-8" @click="deleteSql(node.getIndex())" />
  155. </tepmlate>
  156. </template>
  157. </t-tree>
  158. </div>
  159. <div
  160. id="dragElem-sql"
  161. style="position: absolute; left: 0; z-index: -999"
  162. v-if="data.sqls.length"
  163. >
  164. <div v-for="item in data.sqls">
  165. <div
  166. class="flex mt-4"
  167. v-for="(prop, i) in item.children"
  168. v-show="sqlsCheked.includes(prop.value)"
  169. >
  170. <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
  171. <div class="ml-4">{{ prop.mock }}</div>
  172. </div>
  173. </div>
  174. </div>
  175. </div>
  176. <!-- <div v-if="data.networks?.length">
  177. <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
  178. <div class="flex">
  179. <ControlPlatformIcon class="tree-icon mt-8" />
  180. <div class="ml-8">Mqtt</div>
  181. </div>
  182. <div>
  183. </div>
  184. </div>
  185. <div
  186. :draggable="data.checkAll ? true : false"
  187. @dragstart="onAddShape($event, data.networks,'network')"
  188. @dragend="onAddShapeEnd"
  189. >
  190. <t-tree
  191. :draggable="false"
  192. class="ml-16"
  193. v-model="networksCheked"
  194. ref="networkTree"
  195. :key="networkTreeKey"
  196. style="overflow-y: hidden"
  197. activeMultiple
  198. :data="data.networks"
  199. :expand-parent="true"
  200. :checkable="data.checkAll"
  201. :checkStrictly="false"
  202. >
  203. <template #operations="{ node }">
  204. <template v-if="node.getParent()">
  205. <Edit2Icon
  206. class="mr-12"
  207. @click="showAddData(node.getParent().data, node)"
  208. />
  209. <DeleteIcon
  210. class="mr-8"
  211. @click="
  212. deleteData(node.getParent().data, node.getIndex());
  213. node.remove();
  214. "
  215. />
  216. </template>
  217. <template v-else>
  218. <t-dropdown :minColumnWidth="168" :hide-after-item-click="false">
  219. <AddIcon class="mr-12" />
  220. <t-dropdown-menu>
  221. <t-dropdown-item
  222. :value="2"
  223. :divider="true"
  224. @click="showAddData(node.data)"
  225. >
  226. 新建属性
  227. </t-dropdown-item>
  228. <t-dropdown-item :value="2" @click="importDataset(node.data)">
  229. 从Excel导入
  230. </t-dropdown-item>
  231. <t-dropdown-item :value="4">
  232. <a
  233. :href="
  234. isDownload
  235. ? '/v/data.xlsx'
  236. : cdn
  237. ? cdn + '/v/data.xlsx?r=' + Math.random()
  238. : '/data.xlsx'
  239. "
  240. style="color: var(--td-text-color-primary)"
  241. @click.stop
  242. >
  243. 下载Excel示例
  244. </a>
  245. </t-dropdown-item>
  246. </t-dropdown-menu>
  247. </t-dropdown>
  248. <Edit2Icon
  249. class="mr-12"
  250. @click="editNetwork(node.data, node.getIndex())"
  251. />
  252. <DeleteIcon
  253. class="mr-8"
  254. @click="
  255. deleteNetwork(node.getIndex());
  256. node.remove();
  257. "
  258. />
  259. </template>
  260. </template>
  261. </t-tree>
  262. </div>
  263. <div
  264. id="dragElem-network"
  265. style="position: absolute; left: 0; z-index: -999"
  266. v-if="data.networks.length"
  267. >
  268. <div v-for="item in data.networks">
  269. <div
  270. class="flex mt-4"
  271. v-for="(prop, i) in item.children"
  272. v-show="networksCheked.includes(prop.value)"
  273. >
  274. <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
  275. <div class="ml-4">{{ prop.mock }}</div>
  276. </div>
  277. </div>
  278. </div>
  279. </div> -->
  280. <div v-if="data.mqtt_networks?.length">
  281. <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
  282. <!-- <div class="flex"> -->
  283. <!-- <ControlPlatformIcon class="tree-icon mt-8" /> -->
  284. <div class="datasource-title">MQTT</div>
  285. <!-- </div> -->
  286. <div>
  287. </div>
  288. </div>
  289. <div
  290. :draggable="data.checkAll ? true : false"
  291. @dragstart="onAddShape($event, data.networks,'network')"
  292. @dragend="onAddShapeEnd"
  293. >
  294. <t-tree
  295. :draggable="false"
  296. v-model="networksCheked"
  297. ref="mqttTree"
  298. :key="mqttTreeKey"
  299. style="overflow-y: hidden"
  300. activeMultiple
  301. :data="data.mqtt_networks"
  302. :expand-parent="true"
  303. :checkable="data.checkAll"
  304. :checkStrictly="false"
  305. >
  306. <template #operations="{ node }">
  307. <template v-if="node.getParent()">
  308. <Edit2Icon
  309. class="mr-12"
  310. @click="showAddData(node.getParent().data, node)"
  311. />
  312. <DeleteIcon
  313. class="mr-8"
  314. @click="
  315. deleteData(node.getParent().data, node.getIndex());
  316. node.remove();
  317. "
  318. />
  319. </template>
  320. <template v-else>
  321. <t-dropdown :minColumnWidth="168" :hide-after-item-click="false">
  322. <AddIcon class="mr-12 hover" />
  323. <t-dropdown-menu>
  324. <t-dropdown-item
  325. :value="2"
  326. :divider="true"
  327. @click="showAddData(node.data)"
  328. >
  329. 新建属性
  330. </t-dropdown-item>
  331. <t-dropdown-item :value="3" :divider="true">
  332. 在线接口
  333. <t-dropdown-menu
  334. class="menu-item-input"
  335. style="max-width: 216px !important"
  336. >
  337. <t-dropdown-item
  338. :value="3 - 1"
  339. style="max-width: 216px !important"
  340. >
  341. <div
  342. class="data-input-box"
  343. style="max-width: 216px !important"
  344. >
  345. <t-input
  346. label="地址:"
  347. style="width: 216px"
  348. placeholder="请输入地址"
  349. v-model="data.dataset.url"
  350. @blur="getDatas(node.data)"
  351. @enter="getDatas(node.data)"
  352. >
  353. <template #suffixIcon>
  354. <CloudDownloadIcon
  355. @click="getDatas(node.data)"
  356. :style="{ cursor: 'pointer' }"
  357. />
  358. </template>
  359. </t-input>
  360. </div>
  361. </t-dropdown-item>
  362. </t-dropdown-menu>
  363. </t-dropdown-item>
  364. <t-dropdown-item :value="2" @click="importDataset(node.data)">
  365. 从Excel导入
  366. </t-dropdown-item>
  367. <t-dropdown-item :value="4">
  368. <a
  369. :href="'/data.xlsx'
  370. "
  371. style="color: var(--td-text-color-primary)"
  372. @click.stop
  373. >
  374. 下载Excel示例
  375. </a>
  376. </t-dropdown-item>
  377. </t-dropdown-menu>
  378. </t-dropdown>
  379. <Edit2Icon
  380. class="mr-12 hover"
  381. @click="editNetwork(node.data, node.data.tem_index)"
  382. />
  383. <DeleteIcon
  384. class="mr-8"
  385. @click="
  386. deleteNetwork(node.data.tem_index);
  387. node.remove();
  388. "
  389. />
  390. </template>
  391. </template>
  392. </t-tree>
  393. </div>
  394. <div
  395. id="dragElem-network"
  396. style="position: absolute; left: 0; z-index: -999"
  397. v-if="data.networks.length"
  398. >
  399. <div v-for="item in data.networks">
  400. <div
  401. class="flex mt-4"
  402. v-for="(prop, i) in item.children"
  403. v-show="networksCheked.includes(prop.value)"
  404. >
  405. <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
  406. <div class="ml-4">{{ prop.mock }}</div>
  407. </div>
  408. </div>
  409. </div>
  410. </div>
  411. <div v-if="data.ws_networks?.length">
  412. <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
  413. <!-- <div class="flex"> -->
  414. <!-- <ControlPlatformIcon class="tree-icon mt-8" /> -->
  415. <div class="datasource-title">Websocket</div>
  416. <!-- </div> -->
  417. <div>
  418. </div>
  419. </div>
  420. <div
  421. :draggable="data.checkAll ? true : false"
  422. @dragstart="onAddShape($event, data.networks,'network')"
  423. @dragend="onAddShapeEnd"
  424. >
  425. <t-tree
  426. :draggable="false"
  427. v-model="networksCheked"
  428. ref="wsTree"
  429. :key="wsTreeKey"
  430. style="overflow-y: hidden"
  431. activeMultiple
  432. :data="data.ws_networks"
  433. :expand-parent="true"
  434. :checkable="data.checkAll"
  435. :checkStrictly="false"
  436. >
  437. <template #operations="{ node }">
  438. <template v-if="node.getParent()">
  439. <Edit2Icon
  440. class="mr-12"
  441. @click="showAddData(node.getParent().data, node)"
  442. />
  443. <DeleteIcon
  444. class="mr-8"
  445. @click="
  446. deleteData(node.getParent().data, node.getIndex());
  447. node.remove();
  448. "
  449. />
  450. </template>
  451. <template v-else>
  452. <t-dropdown :minColumnWidth="168" :hide-after-item-click="false">
  453. <AddIcon class="mr-12" />
  454. <t-dropdown-menu>
  455. <t-dropdown-item
  456. :value="2"
  457. :divider="true"
  458. @click="showAddData(node.data)"
  459. >
  460. 新建属性
  461. </t-dropdown-item>
  462. <t-dropdown-item :value="3" :divider="true">
  463. 在线接口
  464. <t-dropdown-menu
  465. class="menu-item-input"
  466. style="max-width: 216px !important"
  467. >
  468. <t-dropdown-item
  469. :value="3 - 1"
  470. style="max-width: 216px !important"
  471. >
  472. <div
  473. class="data-input-box"
  474. style="max-width: 216px !important"
  475. >
  476. <t-input
  477. label="地址:"
  478. style="width: 216px"
  479. placeholder="请输入地址"
  480. v-model="data.dataset.url"
  481. @blur="getDatas(node.data)"
  482. @enter="getDatas(node.data)"
  483. >
  484. <template #suffixIcon>
  485. <CloudDownloadIcon
  486. @click="getDatas(node.data)"
  487. :style="{ cursor: 'pointer' }"
  488. />
  489. </template>
  490. </t-input>
  491. </div>
  492. </t-dropdown-item>
  493. </t-dropdown-menu>
  494. </t-dropdown-item>
  495. <t-dropdown-item :value="2" @click="importDataset(node.data)">
  496. 从Excel导入
  497. </t-dropdown-item>
  498. <t-dropdown-item :value="4">
  499. <a
  500. :href="'/data.xlsx'"
  501. style="color: var(--td-text-color-primary)"
  502. @click.stop
  503. >
  504. 下载Excel示例
  505. </a>
  506. </t-dropdown-item>
  507. </t-dropdown-menu>
  508. </t-dropdown>
  509. <Edit2Icon
  510. class="mr-12"
  511. @click="editNetwork(node.data, node.data.tem_index)"
  512. />
  513. <DeleteIcon
  514. class="mr-8"
  515. @click="
  516. deleteNetwork(node.data.tem_index);
  517. node.remove();
  518. "
  519. />
  520. </template>
  521. </template>
  522. </t-tree>
  523. </div>
  524. <div
  525. id="dragElem-network"
  526. style="position: absolute; left: 0; z-index: -999"
  527. v-if="data.networks.length"
  528. >
  529. <div v-for="item in data.networks">
  530. <div
  531. class="flex mt-4"
  532. v-for="(prop, i) in item.children"
  533. v-show="networksCheked.includes(prop.value)"
  534. >
  535. <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
  536. <div class="ml-4">{{ prop.mock }}</div>
  537. </div>
  538. </div>
  539. </div>
  540. </div>
  541. <div v-if="data.http_networks?.length">
  542. <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
  543. <!-- <div class="flex"> -->
  544. <!-- <ControlPlatformIcon class="tree-icon mt-8" /> -->
  545. <div class="datasource-title">HTTP</div>
  546. <!-- </div> -->
  547. <div>
  548. </div>
  549. </div>
  550. <div
  551. :draggable="data.checkAll ? true : false"
  552. @dragstart="onAddShape($event, data.networks,'network')"
  553. @dragend="onAddShapeEnd"
  554. >
  555. <t-tree
  556. :draggable="false"
  557. v-model="networksCheked"
  558. ref="httpTree"
  559. :key="httpTreeKey"
  560. style="overflow-y: hidden"
  561. activeMultiple
  562. :data="data.http_networks"
  563. :expand-parent="true"
  564. :checkable="data.checkAll"
  565. :checkStrictly="false"
  566. :filter="dataFilter"
  567. >
  568. <template #operations="{ node }">
  569. <template v-if="node.getParent()">
  570. <Edit2Icon
  571. class="mr-12"
  572. @click="showAddData(node.getParent().data, node)"
  573. />
  574. <DeleteIcon
  575. class="mr-8"
  576. @click="
  577. deleteData(node.getParent().data, node.getIndex());
  578. node.remove();
  579. "
  580. />
  581. </template>
  582. <template v-else>
  583. <t-dropdown :minColumnWidth="168" :hide-after-item-click="false">
  584. <AddIcon class="mr-12" />
  585. <t-dropdown-menu>
  586. <t-dropdown-item
  587. :value="2"
  588. :divider="true"
  589. @click="showAddData(node.data)"
  590. >
  591. 新建属性
  592. </t-dropdown-item>
  593. <t-dropdown-item :value="3" :divider="true">
  594. 在线接口
  595. <t-dropdown-menu
  596. class="menu-item-input"
  597. style="max-width: 216px !important"
  598. >
  599. <t-dropdown-item
  600. :value="3 - 1"
  601. style="max-width: 216px !important"
  602. >
  603. <div
  604. class="data-input-box"
  605. style="max-width: 216px !important"
  606. >
  607. <t-input
  608. label="地址:"
  609. style="width: 216px"
  610. placeholder="请输入地址"
  611. v-model="data.dataset.url"
  612. @blur="getDatas(node.data)"
  613. @enter="getDatas(node.data)"
  614. >
  615. <template #suffixIcon>
  616. <CloudDownloadIcon
  617. @click="getDatas(node.data)"
  618. :style="{ cursor: 'pointer' }"
  619. />
  620. </template>
  621. </t-input>
  622. </div>
  623. </t-dropdown-item>
  624. </t-dropdown-menu>
  625. </t-dropdown-item>
  626. <t-dropdown-item :value="2" @click="importDataset(node.data)">
  627. 从Excel导入
  628. </t-dropdown-item>
  629. <t-dropdown-item :value="4">
  630. <a
  631. :href="'/data.xlsx'"
  632. style="color: var(--td-text-color-primary)"
  633. @click.stop
  634. >
  635. 下载Excel示例
  636. </a>
  637. </t-dropdown-item>
  638. </t-dropdown-menu>
  639. </t-dropdown>
  640. <Edit2Icon
  641. class="mr-12"
  642. @click="editNetwork(node.data, node.data.tem_index)"
  643. />
  644. <DeleteIcon
  645. class="mr-8"
  646. @click="
  647. deleteNetwork(node.data.tem_index);
  648. node.remove();
  649. "
  650. />
  651. </template>
  652. </template>
  653. </t-tree>
  654. </div>
  655. <div
  656. id="dragElem-network"
  657. style="position: absolute; left: 0; z-index: -999"
  658. v-if="data.networks.length"
  659. >
  660. <div v-for="item in data.networks">
  661. <div
  662. class="flex mt-4"
  663. v-for="(prop, i) in item.children"
  664. v-show="networksCheked.includes(prop.value)"
  665. >
  666. <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
  667. <div class="ml-4">{{ prop.mock }}</div>
  668. </div>
  669. </div>
  670. </div>
  671. </div>
  672. <div v-if="data.SSE_networks?.length">
  673. <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
  674. <!-- <div class="flex"> -->
  675. <!-- <ControlPlatformIcon class="tree-icon mt-8" /> -->
  676. <div class="datasource-title">SSE</div>
  677. <!-- </div> -->
  678. <div>
  679. </div>
  680. </div>
  681. <div
  682. :draggable="data.checkAll ? true : false"
  683. @dragstart="onAddShape($event, data.networks,'network')"
  684. @dragend="onAddShapeEnd"
  685. >
  686. <t-tree
  687. :draggable="false"
  688. v-model="networksCheked"
  689. ref="SSETree"
  690. :key="SSETreeKey"
  691. style="overflow-y: hidden"
  692. activeMultiple
  693. :data="data.SSE_networks"
  694. :expand-parent="true"
  695. :checkable="data.checkAll"
  696. :checkStrictly="false"
  697. >
  698. <template #operations="{ node }">
  699. <template v-if="node.getParent()">
  700. <Edit2Icon
  701. class="mr-12"
  702. @click="showAddData(node.getParent().data, node)"
  703. />
  704. <DeleteIcon
  705. class="mr-8"
  706. @click="
  707. deleteData(node.getParent().data, node.getIndex());
  708. node.remove();
  709. "
  710. />
  711. </template>
  712. <template v-else>
  713. <t-dropdown :minColumnWidth="168" :hide-after-item-click="false">
  714. <AddIcon class="mr-12" />
  715. <t-dropdown-menu>
  716. <t-dropdown-item
  717. :value="2"
  718. :divider="true"
  719. @click="showAddData(node.data)"
  720. >
  721. 新建属性
  722. </t-dropdown-item>
  723. <t-dropdown-item :value="3" :divider="true">
  724. 在线接口
  725. <t-dropdown-menu
  726. class="menu-item-input"
  727. style="max-width: 216px !important"
  728. >
  729. <t-dropdown-item
  730. :value="3 - 1"
  731. style="max-width: 216px !important"
  732. >
  733. <div
  734. class="data-input-box"
  735. style="max-width: 216px !important"
  736. >
  737. <t-input
  738. label="地址:"
  739. style="width: 216px"
  740. placeholder="请输入地址"
  741. v-model="data.dataset.url"
  742. @blur="getDatas(node.data)"
  743. @enter="getDatas(node.data)"
  744. >
  745. <template #suffixIcon>
  746. <CloudDownloadIcon
  747. @click="getDatas(node.data)"
  748. :style="{ cursor: 'pointer' }"
  749. />
  750. </template>
  751. </t-input>
  752. </div>
  753. </t-dropdown-item>
  754. </t-dropdown-menu>
  755. </t-dropdown-item>
  756. <t-dropdown-item :value="2" @click="importDataset(node.data)">
  757. 从Excel导入
  758. </t-dropdown-item>
  759. <t-dropdown-item :value="4">
  760. <a
  761. :href="'/data.xlsx'"
  762. style="color: var(--td-text-color-primary)"
  763. @click.stop
  764. >
  765. 下载Excel示例
  766. </a>
  767. </t-dropdown-item>
  768. </t-dropdown-menu>
  769. </t-dropdown>
  770. <Edit2Icon
  771. class="mr-12"
  772. @click="editNetwork(node.data, node.data.tem_index)"
  773. />
  774. <DeleteIcon
  775. class="mr-8"
  776. @click="
  777. deleteNetwork(node.data.tem_index);
  778. node.remove();
  779. "
  780. />
  781. </template>
  782. </template>
  783. </t-tree>
  784. </div>
  785. <div
  786. id="dragElem-network"
  787. style="position: absolute; left: 0; z-index: -999"
  788. v-if="data.networks.length"
  789. >
  790. <div v-for="item in data.networks">
  791. <div
  792. class="flex mt-4"
  793. v-for="(prop, i) in item.children"
  794. v-show="networksCheked.includes(prop.value)"
  795. >
  796. <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
  797. <div class="ml-4">{{ prop.mock }}</div>
  798. </div>
  799. </div>
  800. </div>
  801. </div>
  802. <div
  803. class="flex column middle nodata"
  804. v-if="!data.iotTree.length && !data.sqls.length && !data.networks.length"
  805. >
  806. <img src="/img/no-data.png" />
  807. <div class="gray center">暂无数据</div>
  808. <!-- <div class="mt-20">
  809. <t-button theme="primary" @click="addNetwork()">
  810. 添加数据源
  811. </t-button>
  812. </div> -->
  813. </div>
  814. </div>
  815. <div class="content" v-if="group === '解析'">
  816. <div class="flex between">
  817. <div class="title">数据{{ group }}</div>
  818. </div>
  819. <div class="mt-8">
  820. <CodeEditor
  821. :key="data.randomkey"
  822. v-model="data.socketCbJs"
  823. style="min-height: 300px"
  824. @change="onSocketCbJsChange"
  825. />
  826. <div class="data-full-icon hover">
  827. <Fullscreen2Icon @click="showDataTransformation" />
  828. </div>
  829. </div>
  830. <div class="mt-16">
  831. 参考文档:
  832. <a
  833. target="_blank"
  834. href="https://doc.le5le.com/document/136233394#%E8%A7%A3%E6%9E%90%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F"
  835. >
  836. 解析自定义格式数据</a
  837. >
  838. </div>
  839. </div>
  840. <t-dialog
  841. v-if="addDataDialog.show"
  842. :visible="true"
  843. class="data-dialog"
  844. :header="addDataDialog.header"
  845. @close="addDataDialog.show = false"
  846. @confirm="onOkAddData"
  847. >
  848. <!-- <div class="form-item mt-16">
  849. <label>设备</label>
  850. <t-input v-model="addDataDialog.data.device" placeholder="设备名称" />
  851. </div> -->
  852. <div class="form-item mt-16">
  853. <label>显示名称</label>
  854. <t-input
  855. @change="changeDataLabel($event)"
  856. :value="addDataDialog.data.label"
  857. placeholder="属性简短描述"
  858. />
  859. </div>
  860. <div class="form-item mt-16">
  861. <label>属性名</label>
  862. <t-input
  863. @change="changeDataID($event)"
  864. :value="addDataDialog.data.id"
  865. placeholder="属性名"
  866. />
  867. </div>
  868. <div class="form-item mt-16">
  869. <label>类型</label>
  870. <t-select
  871. class="w-full"
  872. :options="typeOptions"
  873. v-model="addDataDialog.data.type"
  874. placeholder="字符串"
  875. @change="addDataDialog.data.value = null"
  876. />
  877. </div>
  878. <!--
  879. <div class="form-item mt-16">
  880. <label
  881. >值范围
  882. <t-tooltip content="可用做数据模拟" placement="top">
  883. <HelpCircleIcon style="font-size: 12px" />
  884. </t-tooltip>
  885. </label>
  886. <div class="w-full">
  887. <t-input v-model="addDataDialog.data.mock" placeholder="值范围" />
  888. <h6 class="desc mt-8" style="font-size: 12px">值范围说明</h6>
  889. <ul class="desc ml-16" style="font-size: 12px">
  890. <li>
  891. <label class="inline" style="width: 80px">固定值:</label>
  892. 直接填写,例如:10
  893. </li>
  894. <li>
  895. <label class="inline" style="width: 80px">随机值:</label>
  896. 值1,值2,...。例如:1,2,3,4,5
  897. </li>
  898. <li>
  899. <label class="inline" style="width: 80px">范围数字:</label>
  900. 最小值-最大值。例如:0-1.0 或 0-100
  901. </li>
  902. <li>
  903. <label class="inline" style="width: 80px">随机字符串:</label>
  904. [长度]。例如:[8]
  905. </li>
  906. </ul>
  907. </div>
  908. </div> -->
  909. </t-dialog>
  910. <t-dialog
  911. v-if="networkDialog.show"
  912. :visible="true"
  913. width="800px"
  914. class="data-dialog"
  915. :header="networkDialog.header"
  916. @close="networkDialog.show = false"
  917. @confirm="onOkNetwork"
  918. >
  919. <template #footer>
  920. <div class="flex mr-8" style="justify-content: end">
  921. <!-- <t-checkbox v-model="networkDialog.save" class="mr-12">
  922. 同时保存到我的数据源
  923. </t-checkbox> -->
  924. <t-button @click="onOkNetwork">确定</t-button>
  925. </div>
  926. </template>
  927. <div style="max-height: 450px; padding: 8px; overflow-y: auto">
  928. <Net v-model="networkDialog.network" />
  929. </div>
  930. </t-dialog>
  931. <t-dialog
  932. v-if="dataTransformationDialog.show"
  933. :visible="true"
  934. header="数据监听"
  935. @confirm="onOkDataTransformation"
  936. @close="dataTransformationDialog.show = false"
  937. :width="800"
  938. >
  939. <CodeEditor v-model="dataTransformationDialog.data" style="height: 300px" />
  940. <div class="mt-8">
  941. 参考文档:
  942. <a
  943. target="_blank"
  944. href="https://doc.le5le.com/document/136233394#%E8%A7%A3%E6%9E%90%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F"
  945. >
  946. 解析自定义格式数据</a
  947. >
  948. </div>
  949. </t-dialog>
  950. <t-dialog
  951. v-if="sqlDialog.show"
  952. :visible="true"
  953. width="800px"
  954. class="data-dialog"
  955. :header="sqlDialog.header"
  956. @close="sqlDialog.show = false"
  957. @confirm="onOkSql"
  958. >
  959. <div style="max-height: 450px; padding: 8px">
  960. <div class="form-item mt-8">
  961. <label>sql数据源</label>
  962. <t-select v-model="sqlDialog.sql.dbid" placeholder="请选择数据源">
  963. <t-option
  964. v-for="sql in sqlList"
  965. @click="sqlChange(sql)"
  966. :key="sql.id"
  967. :value="sql.id"
  968. :label="sql.name + '(' + sql.dbType + ')'"
  969. />
  970. </t-select>
  971. </div>
  972. <div class="form-item mt-8">
  973. <label>sql轮询间隔</label>
  974. <t-input-number
  975. theme="column"
  976. v-model="sqlDialog.sql.interval"
  977. placeholder="不填,仅初始执行一次"
  978. />
  979. </div>
  980. <div class="form-item mt-8">
  981. <label>查询方式</label>
  982. <t-select v-model="sqlDialog.sql.method">
  983. <t-option key="get" value="get" label="单条" />
  984. <t-option key="list" value="list" label="列表" />
  985. </t-select>
  986. </div>
  987. <div class="form-item mt-8">
  988. <label>sql语句</label>
  989. <CodeEditor
  990. :json="false"
  991. :language="'sql'"
  992. v-model="sqlDialog.sql.sql"
  993. class="mt-4"
  994. style="height: 100px"
  995. />
  996. </div>
  997. <div v-if="sqlDialog.sql.method === 'list'" class="form-item mt-8">
  998. <label>第几页</label>
  999. <t-input-number
  1000. v-model="sqlDialog.sql.current"
  1001. theme="normal"
  1002. :min="1"
  1003. placeholder="默认1"
  1004. />
  1005. </div>
  1006. <div v-if="sqlDialog.sql.method === 'list'" class="form-item mt-8">
  1007. <label>每页数量</label>
  1008. <t-input-number
  1009. v-model="sqlDialog.sql.pageSize"
  1010. theme="normal"
  1011. placeholder="默认20"
  1012. :min="1"
  1013. />
  1014. </div>
  1015. <div class="form-item mt-8">
  1016. <label>关联属性名</label>
  1017. <t-input v-model="sqlDialog.sql.bindId" placeholder="关联属性名" />
  1018. </div>
  1019. <div class="flex mt-8">
  1020. <!-- <label> -->
  1021. <t-button style="width: 75px" @click="sqlTest">连接测试</t-button>
  1022. <!-- </label> -->
  1023. <p class="ml-8" style="width: 700px">{{ sqlDialog.result }}</p>
  1024. </div>
  1025. </div>
  1026. </t-dialog>
  1027. <t-dialog
  1028. v-if="iotDialog.show"
  1029. :visible="true"
  1030. width="472px"
  1031. dialogClassName="iot-dialog"
  1032. :header="iotDialog.header"
  1033. @close="iotDialog.show = false"
  1034. @confirm="onOkIot"
  1035. >
  1036. <!-- <t-input
  1037. v-model="iotSearch"
  1038. @change="onSearchIot"
  1039. @enter="onSearchIot"
  1040. placeholder="设备属性搜索"
  1041. /> -->
  1042. <div class="input-search" style="padding: 0px 4px">
  1043. <div class="btn" style="left: 14px">
  1044. <img src="/img/icon_search_gray.svg" />
  1045. </div>
  1046. <t-input
  1047. style="height: 32px"
  1048. v-model="iotSearch"
  1049. @change="onSearchIot"
  1050. @enter="onSearchIot"
  1051. placeholder="搜索设备属性"
  1052. />
  1053. </div>
  1054. <div style="height: 320px; margin-top: 8px; overflow-y: scroll">
  1055. <t-tree
  1056. style="overflow-y: hidden"
  1057. activeMultiple
  1058. v-model="checkedIots"
  1059. :data="iots"
  1060. :expand-parent="true"
  1061. :checkable="true"
  1062. :checkStrictly="false"
  1063. allow-fold-node-on-filter
  1064. :filter="iotFilter"
  1065. :scroll="{
  1066. // rowHeight: 34,
  1067. bufferSize: 50,
  1068. threshold: 30,
  1069. type: 'virtual',
  1070. }"
  1071. />
  1072. </div>
  1073. </t-dialog>
  1074. </template>
  1075. <script lang="ts" setup>
  1076. import { reactive, defineComponent, ref, onMounted, toRaw, watch } from 'vue';
  1077. import {
  1078. FileImportIcon,
  1079. FileExportIcon,
  1080. DeleteIcon,
  1081. AddIcon,
  1082. AddCircleIcon,
  1083. MinusCircleIcon,
  1084. Edit2Icon,
  1085. FileExcelIcon,
  1086. CloudDownloadIcon,
  1087. SearchIcon,
  1088. Fullscreen2Icon,
  1089. FullscreenExit1Icon,
  1090. HelpCircleIcon,
  1091. CaretDownSmallIcon,
  1092. CaretRightSmallIcon,
  1093. RouterWaveIcon,
  1094. ArrowUpDown3Icon,
  1095. Download1Icon,
  1096. ApplicationIcon,
  1097. DataIcon,
  1098. ControlPlatformIcon,
  1099. DragDropIcon
  1100. } from 'tdesign-icons-vue-next';
  1101. import { typeOptions } from '@/services/common';
  1102. import { MessagePlugin } from 'tdesign-vue-next';
  1103. import { Pen, deepClone } from '@meta2d/core';
  1104. import { useDot } from '@/services/common';
  1105. import { cdn } from '@/services/api';
  1106. import { importExcel, saveAsExcel } from '@/services/excel';
  1107. import axios from 'axios';
  1108. import { transformData } from '@/services/utils';
  1109. import { debounce } from '@/services/debouce';
  1110. import Net from '@/views/components/Net.vue';
  1111. import CodeEditor from '@/views/components/common/CodeEditor.vue';
  1112. import { s8 } from '@/services/random';
  1113. import { useUser } from '@/services/user';
  1114. import {
  1115. getSqlSourceList,
  1116. getDevices,
  1117. getDeviceProperties,
  1118. getMqttUrl,
  1119. doSqlCode,
  1120. } from '@/services/iot';
  1121. const props = defineProps<{
  1122. group: string;
  1123. }>();
  1124. const { user } = useUser();
  1125. const { dot, setDot } = useDot();
  1126. const data = reactive({
  1127. //列表
  1128. datesetBak: {},
  1129. datasetId: '',
  1130. networks: [],
  1131. http_networks:[],
  1132. ws_networks:[],
  1133. mqtt_networks:[],
  1134. SSE_networks:[],
  1135. datasetList: [],
  1136. dataset: {
  1137. name: '',
  1138. id: '',
  1139. url: '',
  1140. devices: [],
  1141. } as any,
  1142. checkAll: false,
  1143. //获取
  1144. networkList: [],
  1145. input: '',
  1146. popupVisible: false,
  1147. networkId: '',
  1148. //监听
  1149. socketCbJs: '',
  1150. full: false,
  1151. dataMocks: [
  1152. // {
  1153. // name: '',
  1154. // id: '',
  1155. // enableMock: true,
  1156. // mock: 'aaa',
  1157. // type: 'string',
  1158. // expend: true,
  1159. // show: false,
  1160. // },
  1161. ],
  1162. enableMock: false,
  1163. randomkey: s8(),
  1164. sqls: [],
  1165. iotList: [],
  1166. iotTree: [],
  1167. });
  1168. onMounted(() => {
  1169. meta2d.store.data.networks?.forEach((network:any)=>
  1170. {
  1171. if(!network.label){
  1172. network.label = network.name;
  1173. }
  1174. if(!network.value){
  1175. network.value = s8();
  1176. }
  1177. network.checkable = false
  1178. });
  1179. data.networks = meta2d.store.data.networks || [];
  1180. data.dataset = (meta2d.store.data as any).dataset || {};
  1181. if( data.networks?.length&&data.dataset?.devices){
  1182. if(!data.networks[0].children?.length){
  1183. data.dataset.devices.forEach((item)=>item.value = item.id);
  1184. data.networks[0].children = deepClone(data.dataset.devices);
  1185. }
  1186. }
  1187. data.socketCbJs = meta2d.store.data.socketCbJs || '';
  1188. // data.dataMocks = meta2d.store.data.dataMocks || [];
  1189. data.enableMock = meta2d.store.data.enableMock || false;
  1190. // getNetworks();
  1191. // getDatasets();
  1192. // getIot();
  1193. data.sqls = meta2d.store.data.sqls || [];
  1194. data.iotList = meta2d.store.data.iot?.list || [];
  1195. data.iotTree = meta2d.store.data.iot?.tree || [];
  1196. getThirdNetwork();
  1197. });
  1198. const dataSearch = ref('');
  1199. const dataFilter = ref(null);
  1200. const onSearchData = () => {
  1201. dataFilter.value = dataSearch.value ? (node) => { return node.data.label?.indexOf(dataSearch.value) >= 0|| node.data.value?.indexOf(dataSearch.value) >= 0 }: null;
  1202. };
  1203. const getThirdNetwork = (key?:string)=>{
  1204. if(!meta2d.store.data.networks?.length){
  1205. return;
  1206. }
  1207. meta2d.store.data.networks.forEach((item:any,index)=>{
  1208. item.tem_index = index;
  1209. });
  1210. if(!key||key==='http'){
  1211. data.http_networks = meta2d.store.data.networks.filter((item)=>item.protocol==='http') || [];
  1212. }
  1213. if(!key||key==='websocket'){
  1214. data.ws_networks = meta2d.store.data.networks.filter((item)=>item.protocol==='websocket') || [];
  1215. }
  1216. if(!key||key==='mqtt'){
  1217. data.mqtt_networks = meta2d.store.data.networks.filter((item)=>item.protocol==='mqtt') || [];
  1218. }
  1219. if(!key||key==='SSE'){
  1220. data.SSE_networks = meta2d.store.data.networks.filter((item)=>item.protocol==='SSE') || [];
  1221. }
  1222. }
  1223. const iotDialog = ref({
  1224. show: false,
  1225. header: '添加物联网平台',
  1226. });
  1227. const onOkIot = () => {
  1228. let _iots = [];
  1229. iots.value.forEach((item) => {
  1230. if (checkedIots.value.includes(item.value)) {
  1231. _iots.push(deepClone(item));
  1232. } else {
  1233. if (item.children?.length) {
  1234. const child = item.children.filter((child) =>
  1235. checkedIots.value.includes(child.value)
  1236. );
  1237. if (child.length) {
  1238. _iots.push({
  1239. label: item.label,
  1240. value: item.value,
  1241. deviceId: item.deviceId, //item.id
  1242. token: item.token,
  1243. children: deepClone(child),
  1244. });
  1245. }
  1246. }
  1247. }
  1248. });
  1249. _iots.forEach((item)=>{item.checkable = false});
  1250. data.iotTree = _iots;
  1251. if (!meta2d.store.data.iot) {
  1252. meta2d.store.data.iot = {};
  1253. }
  1254. meta2d.store.data.iot.tree = _iots;
  1255. iotDialog.value.show = false;
  1256. };
  1257. const onShowIot = async () => {
  1258. await getIotTree();
  1259. getCheckedIots();
  1260. iotDialog.value.show = true;
  1261. };
  1262. const iots = ref([]);
  1263. const getIotTree = async () => {
  1264. if (iots.value.length) {
  1265. return;
  1266. }
  1267. let ret = await getDevices();
  1268. const type = ret.type;
  1269. const list = ret.list;
  1270. for (let i = 0; i < list.length; i++) {
  1271. const item = list[i];
  1272. item.label = item.name;
  1273. item.value = item.id;
  1274. item.deviceId = item.id; //item.id
  1275. item.token = item.token;
  1276. // item.children = true;
  1277. // item.checkable = false;
  1278. let properties = await getDeviceProperties(item.id);
  1279. item.children = properties.map((prop: any) => {
  1280. return {
  1281. label: prop.name,
  1282. value: type?prop.key:item.deviceId + '#' + prop.key,
  1283. _label: item.name + '#' + prop.name,
  1284. token: item.token,
  1285. class: 'iot',
  1286. type: prop.type
  1287. };
  1288. });
  1289. if (!item.children.length) {
  1290. item.checkable = false;
  1291. }
  1292. }
  1293. // setTimeout(()=>{
  1294. iots.value = deepClone(list);
  1295. // },3000);
  1296. };
  1297. const getCheckedIots = ()=>{
  1298. let arr = [];
  1299. meta2d.store.data?.iot?.tree.forEach((item)=>{
  1300. arr.push(...item.children?.map((_item)=>_item.value));
  1301. });
  1302. checkedIots.value = arr;
  1303. }
  1304. const iotSearch = ref('');
  1305. const iotFilter = ref(null);
  1306. const onSearchIot = () => {
  1307. iotFilter.value = iotSearch.value
  1308. ? (node) =>
  1309. node.data.label.indexOf(iotSearch.value) >= 0 ||
  1310. node.data.value.indexOf(iotSearch.value) >= 0
  1311. : null;
  1312. };
  1313. const checkedIots = ref([]);
  1314. const onShowSql = async () => {
  1315. addSql();
  1316. };
  1317. const iotLoad = async (node) => {
  1318. let properties = await getDeviceProperties(node.value);
  1319. return properties.map((item: any) => {
  1320. item.label = item.name;
  1321. item.value = node.data.deviceId + '#' + item.key;
  1322. item._label = node.data.name + '#' + item.name;
  1323. // item.sn = item.sn;
  1324. item.token = node.data.token;
  1325. return item;
  1326. });
  1327. };
  1328. const doBind = (node) => {
  1329. };
  1330. const iotMqtt = ref({});
  1331. const iotProtocol = ref('');
  1332. const getIot = async () => {
  1333. let canmqtt: any = await getMqttUrl();
  1334. if (canmqtt && canmqtt.host) {
  1335. iotMqtt.value = canmqtt;
  1336. }
  1337. if (meta2d.store.data.iot) {
  1338. iotProtocol.value = meta2d.store.data.iot.protocol;
  1339. }
  1340. };
  1341. const selectIot = (protocol: any) => {
  1342. if (iotProtocol.value === protocol) {
  1343. meta2d.store.data.iot = {};
  1344. iotProtocol.value = '';
  1345. } else {
  1346. if (protocol === 'mqtt') {
  1347. meta2d.store.data.iot = {
  1348. protocol: protocol,
  1349. ...iotMqtt.value,
  1350. };
  1351. } else {
  1352. meta2d.store.data.iot = {
  1353. protocol: protocol,
  1354. // host: iotMqtt.value.host
  1355. };
  1356. }
  1357. iotProtocol.value = protocol;
  1358. }
  1359. meta2d.connectNetwork();
  1360. };
  1361. const addSql = async () => {
  1362. sqlList.value = await getSqlSourceList();
  1363. sqlDialog.header = '添加sql数据源';
  1364. sqlDialog.show = true;
  1365. sqlDialog.edit = false;
  1366. sqlDialog.sql = {
  1367. interval: undefined,
  1368. sql: '-- eg:SELECT * FROM "directory"',
  1369. };
  1370. sqlDialog.result = '';
  1371. };
  1372. const editSql = (sql: any, index: number) => {
  1373. sqlDialog.header = '编辑sql数据源';
  1374. sqlDialog.show = true;
  1375. sqlDialog.edit = true;
  1376. sqlDialog.index = index;
  1377. sqlDialog.sql = deepClone(sql);
  1378. };
  1379. const deleteSql = (index: number) => {
  1380. data.sqls.splice(index, 1);
  1381. (meta2d.store.data as any).sqls = data.sqls;
  1382. sqlTreeKey.value = s8();
  1383. setDot(true);
  1384. };
  1385. const sqlTreeKey = ref(s8());
  1386. const onOkSql = async () => {
  1387. if (!sqlDialog.sql.dbid) {
  1388. MessagePlugin.error('请选择数据源');
  1389. return;
  1390. }
  1391. if (!sqlDialog.sql.sql) {
  1392. MessagePlugin.error('请填写sql语句');
  1393. return;
  1394. }
  1395. if (!sqlDialog.sql.interval) {
  1396. sqlDialog.sql.interval = undefined;
  1397. }
  1398. if (!sqlDialog.sql.bindId) {
  1399. MessagePlugin.error('关联属性名必填');
  1400. return;
  1401. }
  1402. sqlDialog.sql.label = sqlDialog.sql.bindId;
  1403. sqlDialog.sql.value = sqlDialog.sql.bindId;
  1404. // let sql = sqlDialog.value.sql+' LIMIT '+(sqlDialog.value.pageSize||20)+(sqlDialog.value.current>1?(' OFFSET '+(sqlDialog.value.current-1)*sqlDialog.value.pageSize):'');
  1405. if (!sqlDialog.sql.children) {
  1406. await sqlTest();
  1407. sqlTreeKey.value = s8();
  1408. }
  1409. if (!sqlDialog.edit) {
  1410. data.sqls.push(sqlDialog.sql);
  1411. // meta2d.store.data.sqls = data.sqls;
  1412. } else {
  1413. data.sqls[sqlDialog.index] = sqlDialog.sql;
  1414. }
  1415. meta2d.store.data.sqls = toRaw(data.sqls);
  1416. sqlTreeKey.value = s8();
  1417. // data.sqls = deepClone(data.sqls);
  1418. meta2d.connectNetwork();
  1419. sqlDialog.show = false;
  1420. };
  1421. const sqlDialog = reactive<any>({
  1422. show: false,
  1423. edit: false,
  1424. index: -1,
  1425. header: '添加sql数据源',
  1426. sql: {
  1427. interval: undefined,
  1428. sql: '',
  1429. },
  1430. });
  1431. const sqlList = ref([]);
  1432. const sqlChange = (sql: any) => {
  1433. sqlDialog.sql.dbid = sql.id;
  1434. sqlDialog.sql.dbType = sql.dbType;
  1435. sqlDialog.sql.name = sql.name;
  1436. };
  1437. const sqlTest = async () => {
  1438. let ret: any = await doSqlCode(sqlDialog.sql);
  1439. if (ret.error) {
  1440. MessagePlugin.error('连接错误:' + ret.error);
  1441. sqlDialog.result = '连接错误:' + ret.error;
  1442. } else {
  1443. if (sqlDialog.sql.method === 'list') {
  1444. sqlDialog.result = '连接成功:[' + JSON.stringify(ret[0]) + ',...]';
  1445. // sqlDialog.sql.columns = ret[0];
  1446. const columnsKeys = Object.keys(ret[0]);
  1447. const children = new Array(ret.length).fill(0).map((item, index) => {
  1448. return {
  1449. label: index + 1 + '',
  1450. value: sqlDialog.sql.bindId + '#' + index,
  1451. _label: sqlDialog.sql.bindId + '#' + index + 1,
  1452. class: 'sql',
  1453. children: columnsKeys.map((key) => {
  1454. return {
  1455. label: key,
  1456. value: sqlDialog.sql.bindId + '#' + index + '#' + key,
  1457. _label: sqlDialog.sql.bindId + '#' + (index + 1) + '#' + key,
  1458. class: 'sql',
  1459. };
  1460. }),
  1461. };
  1462. });
  1463. sqlDialog.sql.class = 'sql';
  1464. sqlDialog.sql.children = children;
  1465. } else {
  1466. sqlDialog.result = '连接成功:' + JSON.stringify(ret);
  1467. // sqlDialog.sql.columns = ret;
  1468. const children = [];
  1469. for (let key in ret) {
  1470. children.push({
  1471. label: key,
  1472. value: sqlDialog.sql.bindId + '#' + key,
  1473. _label: sqlDialog.sql.bindId + '#' + key,
  1474. class: 'sql',
  1475. });
  1476. }
  1477. sqlDialog.sql.class = 'sql';
  1478. sqlDialog.sql.children = children;
  1479. }
  1480. }
  1481. };
  1482. const addDataDialog = reactive<any>({});
  1483. const showAddData = (network: any, node?: any) => {
  1484. addDataDialog.network = network;
  1485. const row = node?.data;
  1486. const index = node?.getIndex();
  1487. addDataDialog.node = node;
  1488. if (row) {
  1489. addDataDialog.header = '编辑数据';
  1490. addDataDialog.data = JSON.parse(JSON.stringify(row));
  1491. addDataDialog.index = index;
  1492. } else {
  1493. addDataDialog.header = '添加数据';
  1494. addDataDialog.data = { type: 'string', expend: true };
  1495. }
  1496. addDataDialog.show = true;
  1497. };
  1498. const deleteData = (network: any, index: number) => {
  1499. network.children.splice(index, 1);
  1500. meta2d.store.data.networks = toRaw(data.networks);
  1501. // data.dataset.devices.splice(row, 1);
  1502. // (meta2d.store.data as any).dataset = data.dataset;
  1503. setDot(true);
  1504. };
  1505. const clearData = () => {
  1506. data.datasetId = undefined;
  1507. data.dataset.id = undefined;
  1508. data.dataset.name = undefined;
  1509. data.dataset.url = undefined;
  1510. data.dataset.devices = [];
  1511. setDot(true);
  1512. };
  1513. const changeDataLabel = (value) => {
  1514. if (!value) {
  1515. MessagePlugin.error('显示名称不能为空!');
  1516. return;
  1517. }
  1518. let item = data.dataset.devices?.filter((item) => item.label === value);
  1519. if (item && item.length) {
  1520. MessagePlugin.error('显示名称重复!');
  1521. return;
  1522. }
  1523. addDataDialog.data.label = value;
  1524. };
  1525. const changeDataID = (value) => {
  1526. if (!value) {
  1527. MessagePlugin.error('属性名不能为空!');
  1528. return;
  1529. }
  1530. let item = data.dataset.devices?.filter((item) => item.id === value);
  1531. if (item && item.length) {
  1532. MessagePlugin.error('属性名重复!');
  1533. return;
  1534. }
  1535. addDataDialog.data.id = value;
  1536. };
  1537. const onOkAddData = () => {
  1538. if (!addDataDialog.data.label) {
  1539. MessagePlugin.error('请填写名称');
  1540. return;
  1541. }
  1542. if (!addDataDialog.data.id) {
  1543. MessagePlugin.error('请填写数据ID');
  1544. return;
  1545. }
  1546. if (!addDataDialog.network.children) {
  1547. addDataDialog.network.children = [];
  1548. }
  1549. addDataDialog.data.value = addDataDialog.data.id;
  1550. if (addDataDialog.header === '添加数据') {
  1551. addDataDialog.network.children.push(addDataDialog.data);
  1552. if(addDataDialog.network.protocol === 'http'){
  1553. httpTree.value.appendTo(addDataDialog.network.value, addDataDialog.data);
  1554. }else if(addDataDialog.network.protocol === 'websocket'){
  1555. wsTree.value.appendTo(addDataDialog.network.value, addDataDialog.data);
  1556. }else if(addDataDialog.network.protocol === 'mqtt'){
  1557. mqttTree.value.appendTo(addDataDialog.network.value, addDataDialog.data);
  1558. }else if(addDataDialog.network.protocol === 'SSE'){
  1559. SSETree.value.appendTo(addDataDialog.network.value, addDataDialog.data);
  1560. }
  1561. } else {
  1562. // addDataDialog.network.children[addDataDialog.index] = addDataDialog.data;
  1563. let beforeId = addDataDialog.network.children[addDataDialog.index].id;
  1564. addDataDialog.network.children.splice(
  1565. addDataDialog.index,
  1566. 1,
  1567. addDataDialog.data
  1568. );
  1569. if(beforeId !== addDataDialog.data.id){
  1570. addDataDialog.node?.insertAfter(deepClone(addDataDialog.data));
  1571. addDataDialog.node?.remove();
  1572. }else{
  1573. addDataDialog.node?.setData(deepClone(addDataDialog.data));
  1574. }
  1575. // mqttTreeKey.value = s8();
  1576. // wsTreeKey.value = s8();
  1577. // httpTreeKey.value = s8();
  1578. // networkTree.value.setItem(addDataDialog.network.value, {children:deepClone(addDataDialog.network.children)});
  1579. // addDataDialog.node?.setData(deepClone(addDataDialog.data));
  1580. //更新所有绑定该id的pen label
  1581. // let binds = meta2d.store.bind[addDataDialog.data.id];
  1582. // if (binds) {
  1583. // binds.forEach((item) => {
  1584. // const pen: Pen = meta2d.findOne(item.id);
  1585. // pen.realTimes &&
  1586. // pen.realTimes.forEach((_realTime) => {
  1587. // if (_realTime.key === item.key) {
  1588. // _realTime.bind.label = addDataDialog.data.label;
  1589. // }
  1590. // });
  1591. // });
  1592. // }
  1593. }
  1594. // (meta2d.store.data as any).dataset = data.dataset;
  1595. meta2d.store.data.networks = toRaw(data.networks);
  1596. addDataDialog.show = false;
  1597. };
  1598. const importDataset = async (network) => {
  1599. let columns: any = [
  1600. {
  1601. header: '设备',
  1602. key: 'device',
  1603. },
  1604. {
  1605. header: '显示名称',
  1606. key: 'label',
  1607. },
  1608. {
  1609. header: '属性名',
  1610. key: 'id',
  1611. },
  1612. {
  1613. header: '类型',
  1614. key: 'type',
  1615. },
  1616. {
  1617. header: '值范围',
  1618. key: 'mock',
  1619. },
  1620. ];
  1621. const _data: any = await importExcel(columns);
  1622. _data.forEach((item) => {
  1623. if (item.device) {
  1624. item.label = item.device + '-' + item.label;
  1625. delete item.device;
  1626. }
  1627. item.value = item.id;
  1628. });
  1629. if (!network.children) {
  1630. network.children = [];
  1631. }
  1632. mergeDataset(network.children, _data);
  1633. if(network.protocol === 'http'){
  1634. httpTree.value.appendTo(network.value, network.children);
  1635. }else if(network.protocol === 'websocket'){
  1636. wsTree.value.appendTo(network.value, network.children);
  1637. }else if(network.protocol === 'mqtt'){
  1638. mqttTree.value.appendTo(network.value, network.children);
  1639. }else if(network.protocol === 'SSE'){
  1640. SSETree.value.appendTo(network.value, network.children);
  1641. }
  1642. // networkTree.value.appendTo(network.value, network.children);
  1643. // (meta2d.store.data as any).dataset = data.dataset;
  1644. };
  1645. const downloadAsExcel = () => {
  1646. if (!(data.dataset.devices && data.dataset.devices.length)) {
  1647. MessagePlugin.error('属性列表不能为空!');
  1648. return;
  1649. }
  1650. const name = meta2d.store.data.name;
  1651. const columns: any[] = [
  1652. {
  1653. key: 'label',
  1654. header: '显示名称',
  1655. },
  1656. {
  1657. key: 'id',
  1658. header: '属性名',
  1659. },
  1660. {
  1661. key: 'type',
  1662. header: '类型',
  1663. },
  1664. {
  1665. key: 'mock',
  1666. header: '值范围',
  1667. },
  1668. ];
  1669. saveAsExcel(name, columns, data.dataset.devices);
  1670. };
  1671. const downloadAsJson = () => {
  1672. if (!(data.dataset.devices && data.dataset.devices.length)) {
  1673. MessagePlugin.error('属性列表不能为空!');
  1674. return;
  1675. }
  1676. import('file-saver').then(({ saveAs }) => {
  1677. saveAs(
  1678. new Blob([JSON.stringify(data.dataset)], {
  1679. type: 'text/plain;charset=utf-8',
  1680. }),
  1681. `${data.dataset.name || '未命名'}.json`
  1682. );
  1683. });
  1684. };
  1685. const onOkDataset = async (saveas = false) => {
  1686. // if (!dataDialog.dataset.name) {
  1687. // MessagePlugin.error('名称不能为空');
  1688. // return;
  1689. // }
  1690. if (!(data.dataset.devices && data.dataset.devices.length)) {
  1691. MessagePlugin.error('属性列表不能为空');
  1692. return;
  1693. }
  1694. const dataset = JSON.parse(JSON.stringify(data.dataset));
  1695. let _data = dataset;
  1696. _data.type = 'dataset';
  1697. if (!_data.name) {
  1698. _data.name = meta2d.store.data.name;
  1699. }
  1700. _data = transformData(dataset, 'toNetwork');
  1701. // 保存到我的数据源
  1702. if (saveas || !dataset.id) {
  1703. delete dataset.id;
  1704. delete dataset._id;
  1705. dataset.type = 'dataset';
  1706. const ret: any = await axios.post(`/api/data/datasource/add`, _data);
  1707. if (!ret) {
  1708. return;
  1709. }
  1710. ret.id = ret.id || ret._id;
  1711. data.datasetId = ret.id;
  1712. dataset.id = ret.id;
  1713. data.dataset.id = ret.id;
  1714. data.datasetList.push(dataset);
  1715. } else {
  1716. const ret: any = await axios.post(`/api/data/datasource/update`, _data);
  1717. if (!ret) {
  1718. return;
  1719. }
  1720. data.datasetList.forEach((item: any, index: number) => {
  1721. if (
  1722. item.id === dataset.id ||
  1723. (item._id === dataset._id && dataset._id != undefined)
  1724. ) {
  1725. data.datasetList.splice(index, 1, dataset);
  1726. }
  1727. });
  1728. }
  1729. delete dataset.devices;
  1730. // @ts-ignore
  1731. // meta2d.store.data.dataset = dataset;
  1732. // setDot(true);
  1733. data.editDataset = false;
  1734. delete data.datesetBak;
  1735. };
  1736. const mergeDataset = (arr1: any, arr2: any[]) => {
  1737. if (!(arr2 && arr2.length)) {
  1738. return;
  1739. }
  1740. if (!arr1) {
  1741. arr1 = [];
  1742. }
  1743. arr2.forEach((item) => {
  1744. let index = arr1.findIndex((elem) => elem.id === item.id);
  1745. if (index >= 0) {
  1746. Object.assign(arr1[index], item);
  1747. } else {
  1748. arr1.push(item);
  1749. }
  1750. });
  1751. };
  1752. const getDatas = async (network) => {
  1753. // return;
  1754. if (!data.dataset.url) {
  1755. return;
  1756. }
  1757. const ret = await axios.get(data.dataset.url);
  1758. let flattenRet = flattenTree(ret);
  1759. if (flattenRet?.length) {
  1760. flattenRet.forEach((item) => {
  1761. if(!item.value){
  1762. item.value = item.id;
  1763. }
  1764. });
  1765. if (!network.children) {
  1766. network.children = [];
  1767. }
  1768. // mergeDataset(data.dataset, flattenRet);
  1769. // (meta2d.store.data as any).dataset = data.dataset;
  1770. mergeDataset(network.children, flattenRet);
  1771. if(network.protocol === 'http'){
  1772. httpTree.value.appendTo(network.value, network.children);
  1773. }else if(network.protocol === 'websocket'){
  1774. wsTree.value.appendTo(network.value, network.children);
  1775. }else if(network.protocol === 'mqtt'){
  1776. mqttTree.value.appendTo(network.value, network.children);
  1777. }else if(network.protocol === 'SSE'){
  1778. SSETree.value.appendTo(network.value, network.children);
  1779. }
  1780. }
  1781. };
  1782. //展开树
  1783. const flattenTree = (root) => {
  1784. if (!root) return []; // 空树返回空数组
  1785. const result = []; // 存储展开后的数组
  1786. // 递归遍历树
  1787. function dfs(node) {
  1788. result.push({
  1789. id: node.id,
  1790. label: node.label || node.name,
  1791. device: node.device || node.id,
  1792. type: node.type,
  1793. mock: node.mock,
  1794. // children: node.children,
  1795. }); // 将当前节点值添加到结果数组
  1796. // 遍历当前节点的子节点
  1797. if (node.children) {
  1798. for (let child of node.children) {
  1799. dfs(child); // 递归调用DFS
  1800. }
  1801. }
  1802. }
  1803. root.forEach((item) => {
  1804. dfs(item);
  1805. });
  1806. // dfs(root); // 从根节点开始遍历
  1807. return result;
  1808. };
  1809. const onSelDataset = async (datasetId = false) => {
  1810. if (datasetId) {
  1811. const dataset = data.datasetList.find((item: any) => {
  1812. return item.id === datasetId;
  1813. });
  1814. if (!dataset) {
  1815. return;
  1816. }
  1817. if (dataset.url) {
  1818. const ret = await axios.get(dataset.url);
  1819. if (ret) {
  1820. dataset.devices = ret;
  1821. }
  1822. } else {
  1823. const ret = await axios.post(`/api/data/datasource/get`, {
  1824. id: dataset.id,
  1825. });
  1826. if (ret?.data) {
  1827. Object.assign(dataset, { ...ret.data });
  1828. }
  1829. }
  1830. mergeDataset(data.dataset, dataset.devices);
  1831. (meta2d.store.data as any).dataset = data.dataset;
  1832. // dataDialog.dataset = dataset;
  1833. // if (!init) {
  1834. // const d = JSON.parse(JSON.stringify(dataset));
  1835. // delete d.devices;
  1836. // // @ts-ignore
  1837. // meta2d.store.data.dataset = d;
  1838. // setDot(true);
  1839. // }
  1840. }
  1841. };
  1842. // 请求我的数据模型
  1843. const getDatasets = async (name?: string) => {
  1844. if (!user.id) {
  1845. MessagePlugin.error('请先登录');
  1846. return;
  1847. }
  1848. const body: any = {
  1849. type: 'dataset',
  1850. projection: 'id,data,name,type',
  1851. };
  1852. if (name) {
  1853. body.name = name;
  1854. }
  1855. const ret: any = await axios.post(`/api/data/datasource/list`, body, {
  1856. params: {
  1857. current: 1,
  1858. pageSize: 10,
  1859. },
  1860. });
  1861. if (ret?.list) {
  1862. const list = [];
  1863. let found = false;
  1864. for (const item of ret.list) {
  1865. item.id = item.id || item._id;
  1866. list.push(transformData(item, 'toMetaNetwork'));
  1867. if (data.dataset?.id === item.id) {
  1868. found = true;
  1869. }
  1870. }
  1871. if (data.dataset?.id && !found) {
  1872. list.push(data.dataset);
  1873. }
  1874. data.datasetList = list;
  1875. }
  1876. };
  1877. const onDelDataset = async (item: any, i: number) => {
  1878. const ret: any = await axios.post(`/api/data/datasource/delete`, {
  1879. id: item.id,
  1880. });
  1881. if (
  1882. (meta2d.store.data as any).dataset &&
  1883. (meta2d.store.data as any).dataset.id === item.id
  1884. ) {
  1885. //@ts-ignore
  1886. meta2d.store.data.dataset = {};
  1887. data.dataset = {};
  1888. data.datasetId = undefined;
  1889. }
  1890. if (ret) {
  1891. data.datasetList.splice(i, 1);
  1892. }
  1893. };
  1894. const search = ref('');
  1895. const onSearch = () => {
  1896. // if (!search.value) {
  1897. // return;
  1898. // }
  1899. data.dataset.devices.forEach((item) => {
  1900. if (
  1901. item.label.indexOf(search.value) !== -1 ||
  1902. item.id.indexOf(search.value) !== -1
  1903. ) {
  1904. item.show = true;
  1905. } else {
  1906. item.show = false;
  1907. }
  1908. });
  1909. };
  1910. const onInputNetwork = (e) => {
  1911. debounce(getNetworks, 300, e);
  1912. };
  1913. const onSelectNetWork = (value) => {
  1914. if (!value) {
  1915. return;
  1916. }
  1917. const network: any = data.networks.find((elem: any) => value === elem.id);
  1918. if (!network) {
  1919. const item = data.networkList.find((elem: any) => value === elem.id);
  1920. data.networks.push(item);
  1921. meta2d.store.data.networks = toRaw(data.networks);
  1922. meta2d.connectNetwork();
  1923. setDot(true);
  1924. }
  1925. // data.input = null;
  1926. data.popupVisible = false;
  1927. };
  1928. // 请求我的实时数据
  1929. const getNetworks = async (e?) => {
  1930. const ret: any = await axios.post(
  1931. `/api/data/datasource/list`,
  1932. {
  1933. // q: {
  1934. name: e,
  1935. // },
  1936. type: 'subscribe',
  1937. projection: 'id,data,name,type',
  1938. },
  1939. {
  1940. params: {
  1941. current: 1,
  1942. pageSize: 10,
  1943. },
  1944. }
  1945. );
  1946. if (ret?.list) {
  1947. const list = [];
  1948. for (const item of ret.list) {
  1949. item.id = item.id || item._id;
  1950. list.push(transformData(item, 'toMetaNetwork'));
  1951. }
  1952. data.networkList = list;
  1953. }
  1954. };
  1955. const onDelNetWork = async (item: any, i: number) => {
  1956. const ret: any = await axios.post(`/api/data/datasource/delete`, {
  1957. id: item.id || item._id,
  1958. });
  1959. if (ret) {
  1960. data.networkList.splice(i, 1);
  1961. }
  1962. };
  1963. const networkTree = ref();
  1964. const networkTreeKey = ref(s8());
  1965. const mqttTree = ref();
  1966. const mqttTreeKey = ref(s8());
  1967. const wsTree = ref();
  1968. const wsTreeKey = ref(s8());
  1969. const httpTree = ref();
  1970. const httpTreeKey = ref(s8());
  1971. const SSETree = ref();
  1972. const SSETreeKey = ref(s8());
  1973. const deleteNetwork = (index: number) => {
  1974. data.networks.splice(index, 1);
  1975. meta2d.store.data.networks = toRaw(data.networks);
  1976. getThirdNetwork('xxx');
  1977. meta2d.connectNetwork();
  1978. setDot(true);
  1979. };
  1980. const networkDialog = reactive<any>({
  1981. save: true,
  1982. });
  1983. const editNetwork = (network: any, index: number) => {
  1984. networkDialog.network = JSON.parse(JSON.stringify(data.networks[index]));
  1985. networkDialog.editNetwork = 2;
  1986. networkDialog.editNetworkIndex = index;
  1987. networkDialog.header = `编辑${networkDialog.network.protocol}数据源`;
  1988. networkDialog.show = true;
  1989. };
  1990. const addNetwork = (protocol:string) => {
  1991. networkDialog.network = {
  1992. name: '',
  1993. type: 'subscribe',
  1994. protocol,
  1995. url: '',
  1996. // options: {
  1997. // clientId: '',
  1998. // username: '',
  1999. // password: '',
  2000. // customClientId: false,
  2001. // },
  2002. };
  2003. if(protocol === 'mqtt'){
  2004. networkDialog.network.options = {
  2005. clientId: '',
  2006. username: '',
  2007. password: '',
  2008. customClientId: false,
  2009. };
  2010. }else if(protocol === 'websocket'){
  2011. networkDialog.network.options = {protocols:''}
  2012. }
  2013. networkDialog.editNetwork = 1;
  2014. networkDialog.header = `添加${protocol}数据源`;
  2015. networkDialog.show = true;
  2016. };
  2017. const onOkNetwork = async () => {
  2018. const _data = transformData(networkDialog.network, 'toNetwork');
  2019. networkDialog.network.label = networkDialog.network.name;
  2020. // networkDialog.network.value = networkDialog.network.url;
  2021. networkDialog.network.value = s8();
  2022. networkDialog.network.checkable = false;
  2023. if (networkDialog.editNetwork === 1) {
  2024. if (
  2025. ['mqtt', 'websocket', 'http'].includes(networkDialog.network.protocol) &&
  2026. !networkDialog.network.url
  2027. ) {
  2028. MessagePlugin.error('URL地址不能为空!');
  2029. return;
  2030. }
  2031. if (!networkDialog.network.name) {
  2032. MessagePlugin.error('名称不能为空!');
  2033. return;
  2034. }
  2035. // if (networkDialog.save) {
  2036. // const ret: any = await axios.post(`/api/data/datasource/add`, _data);
  2037. // if (!ret) {
  2038. // return;
  2039. // }
  2040. // ret.id = ret.id || ret._id;
  2041. // networkDialog.network.id = ret.id;
  2042. // }
  2043. data.networks.push(networkDialog.network);
  2044. // getThirdNetwork(networkDialog.network.protocol);
  2045. // data.networkList.push(networkDialog.network);
  2046. // networkTree.value?.appendTo('', networkDialog.network);
  2047. } else if (networkDialog.editNetwork === 2) {
  2048. // if (networkDialog.save) {
  2049. // const ret: any = await axios.post(`/api/data/datasource/update`, _data);
  2050. // if (!ret) {
  2051. // return;
  2052. // }
  2053. // }
  2054. //替换
  2055. let index = networkDialog.editNetworkIndex;
  2056. if (index !== undefined) {
  2057. data.networks.splice(index, 1, networkDialog.network);
  2058. // getThirdNetwork(networkDialog.network.protocol);
  2059. // networkTreeKey.value = s8();
  2060. if(networkDialog.network.protocol==='http'){
  2061. httpTreeKey.value = s8();
  2062. }else if(networkDialog.network.protocol==='websocket'){
  2063. wsTreeKey.value = s8();
  2064. }else if(networkDialog.network.protocol==='mqtt'){
  2065. mqttTreeKey.value = s8();
  2066. }else if(networkDialog.network.protocol==='SSE'){
  2067. SSETreeKey.value = s8();
  2068. }
  2069. // networkTree.value.setItem(networkDialog.network.value,networkDialog.network);
  2070. }
  2071. }
  2072. networkDialog.show = false;
  2073. networkDialog.editNetwork = 0;
  2074. meta2d.store.data.networks = toRaw(data.networks);
  2075. getThirdNetwork(networkDialog.network.protocol);
  2076. meta2d.connectNetwork();
  2077. setDot(true);
  2078. };
  2079. const dataTransformationDialog = reactive<any>({
  2080. show: false,
  2081. data: '',
  2082. });
  2083. const showDataTransformation = () => {
  2084. dataTransformationDialog.data = meta2d.store.data.socketCbJs;
  2085. dataTransformationDialog.show = true;
  2086. };
  2087. const onOkDataTransformation = () => {
  2088. meta2d.store.data.socketCbJs = dataTransformationDialog.data;
  2089. data.randomkey = s8();
  2090. data.socketCbJs = dataTransformationDialog.data;
  2091. meta2d.listenSocket();
  2092. dataTransformationDialog.show = false;
  2093. };
  2094. let timer: any = 0;
  2095. const onSocketCbJsChange = (e) => {
  2096. clearTimeout(timer);
  2097. timer = setTimeout(() => {
  2098. meta2d.store.data.socketCbJs = data.socketCbJs;
  2099. meta2d.listenSocket();
  2100. }, 3000);
  2101. };
  2102. const onChangeMock = () => {
  2103. // @ts-ignore
  2104. data.enableMock = !data.enableMock;
  2105. meta2d.store.data.enableMock = data.enableMock;
  2106. if (data.enableMock) {
  2107. meta2d.startDataMock();
  2108. } else {
  2109. meta2d.stopDataMock();
  2110. }
  2111. };
  2112. const onCheckAllChange = (e) => {
  2113. if(data.checkAll){
  2114. allChecked.value = [];
  2115. networksCheked.value = [];
  2116. sqlsCheked.value = [];
  2117. }
  2118. data.checkAll =!data.checkAll;
  2119. // if (!e) {
  2120. // data.dataset?.devices?.forEach((item) => {
  2121. // item.checked = false;
  2122. // });
  2123. // }
  2124. };
  2125. const allChecked = ref([]);
  2126. const networksCheked = ref([]);
  2127. const sqlsCheked = ref([]);
  2128. const onAddShape = (e, _data,type) => {
  2129. e.stopPropagation();
  2130. let data: any;
  2131. if (Array.isArray(_data)) {
  2132. const dragElem = document.getElementById(`dragElem-${type}`);
  2133. let width = dragElem.offsetWidth;
  2134. e.dataTransfer.setDragImage(dragElem, width / 2, 10);
  2135. const checked = [];
  2136. if(type === 'iot'){
  2137. _data.forEach((item) => {
  2138. item.children?.forEach((_item) => {
  2139. if (allChecked.value.includes(_item.value)) {
  2140. checked.push(_item);
  2141. }
  2142. });
  2143. });
  2144. }else if(type === 'network'){
  2145. _data.forEach((item) => {
  2146. item.children?.forEach((_item) => {
  2147. if (networksCheked.value.includes(_item.value)) {
  2148. checked.push(_item);
  2149. }
  2150. });
  2151. });
  2152. }else if(type === 'sql'){
  2153. _data.forEach((item) => {
  2154. item.children?.forEach((_item) => {
  2155. if (sqlsCheked.value.includes(_item.value)) {
  2156. checked.push(_item);
  2157. }
  2158. });
  2159. });
  2160. }
  2161. // const checked = _data.filter((item) => item.checked);
  2162. if (!checked.length) {
  2163. MessagePlugin.error('请先选择数据');
  2164. return;
  2165. }
  2166. data = [];
  2167. checked.forEach((item) => {
  2168. let bind:any = {
  2169. class: 'iot',
  2170. id: item.value,
  2171. label: item._label,
  2172. token: item.token,
  2173. };
  2174. if(type === 'network'){
  2175. bind = {
  2176. id: item.id||item.value,
  2177. label: item.label,
  2178. }
  2179. }else if(type === 'sql'){
  2180. //TODO
  2181. bind = {
  2182. id: item.id||item.value,
  2183. label: item.label,
  2184. }
  2185. }
  2186. if (globalThis.style1) {
  2187. data.push(
  2188. ...[
  2189. {
  2190. text: item.label,
  2191. width: 150,
  2192. height: 20,
  2193. name: 'text',
  2194. dataset: true,
  2195. textAlign: 'right',
  2196. },
  2197. {
  2198. text: item.mock || 0,
  2199. width: 58,
  2200. height: 28,
  2201. name: 'rectangle',
  2202. dataset: true,
  2203. // textAlign: 'left',
  2204. color: '#478BFFFF',
  2205. textColor: '#A9C9FFFF',
  2206. background: '#478BFF1F',
  2207. fontWeight: 'bold',
  2208. borderRadius: 0.1,
  2209. lineWidth: 1,
  2210. realTimes: [
  2211. {
  2212. label: '文字',
  2213. key: 'text',
  2214. type: 'string',
  2215. bind: deepClone(item),
  2216. },
  2217. ],
  2218. },
  2219. ]
  2220. );
  2221. } else {
  2222. data.push(
  2223. ...[
  2224. {
  2225. text: item.label + ':',
  2226. width: 150,
  2227. height: 28,
  2228. name: 'text',
  2229. dataset: true,
  2230. textAlign: 'right',
  2231. },
  2232. {
  2233. text: item.mock,
  2234. width: 58,
  2235. height: 20,
  2236. name: 'text',
  2237. dataset: true,
  2238. textAlign: 'left',
  2239. realTimes: [
  2240. {
  2241. label: '文字',
  2242. key: 'text',
  2243. type: 'string',
  2244. bind: bind,
  2245. },
  2246. ],
  2247. },
  2248. ]
  2249. );
  2250. }
  2251. });
  2252. } else {
  2253. if (globalThis.style1) {
  2254. data = [
  2255. {
  2256. text: _data.label,
  2257. width: 150,
  2258. height: 28,
  2259. name: 'text',
  2260. dataset: true,
  2261. textAlign: 'right',
  2262. },
  2263. {
  2264. text: _data.mock || 0,
  2265. width: 58,
  2266. height: 28,
  2267. name: 'rectangle',
  2268. dataset: true,
  2269. // textAlign: 'left',
  2270. color: '#478BFFFF',
  2271. textColor: '#A9C9FFFF',
  2272. background: '#478BFF1F',
  2273. fontWeight: 'bold',
  2274. borderRadius: 0.1,
  2275. lineWidth: 1,
  2276. realTimes: [
  2277. {
  2278. label: '文字',
  2279. key: 'text',
  2280. type: 'string',
  2281. bind: deepClone(_data),
  2282. },
  2283. ],
  2284. },
  2285. ];
  2286. } else {
  2287. data = [
  2288. {
  2289. text: _data.label + ':',
  2290. width: 150,
  2291. height: 20,
  2292. name: 'text',
  2293. dataset: true,
  2294. textAlign: 'right',
  2295. },
  2296. {
  2297. text: _data.mock,
  2298. width: 58,
  2299. height: 20,
  2300. name: 'text',
  2301. dataset: true,
  2302. textAlign: 'left',
  2303. realTimes: [
  2304. {
  2305. label: '文字',
  2306. key: 'text',
  2307. type: 'string',
  2308. bind: deepClone(_data),
  2309. },
  2310. ],
  2311. },
  2312. ];
  2313. }
  2314. }
  2315. meta2d.canvas.addCaches = deepClone(data);
  2316. };
  2317. const onAddShapeEnd = () => {
  2318. setTimeout(() => {
  2319. meta2d.initBinds();
  2320. }, 1000);
  2321. };
  2322. let lastIndex = -1;
  2323. const onCheckChange = (e, i) => {
  2324. if (lastIndex > -1) {
  2325. if (e.shiftKey) {
  2326. let start = Math.min(i, lastIndex);
  2327. let end = Math.max(i, lastIndex);
  2328. data.dataset?.devices?.forEach((item, index) => {
  2329. if (index >= start && index <= end) {
  2330. item.checked = true;
  2331. }
  2332. });
  2333. e.stopPropagation();
  2334. e.preventDefault();
  2335. }
  2336. }
  2337. lastIndex = i;
  2338. };
  2339. const checkChange = (e, device, i) => {
  2340. data.checkAll && (device.checked = !device.checked);
  2341. if (lastIndex > -1) {
  2342. if (e.shiftKey) {
  2343. let start = Math.min(i, lastIndex);
  2344. let end = Math.max(i, lastIndex);
  2345. data.dataset?.devices?.forEach((item, index) => {
  2346. if (index >= start && index <= end) {
  2347. item.checked = true;
  2348. }
  2349. });
  2350. }
  2351. }
  2352. lastIndex = i;
  2353. };
  2354. const onAddmock = (item: any) => {
  2355. if (data.dataMocks.find((elem) => elem.id === item.id)) {
  2356. return;
  2357. }
  2358. item.name = item.label;
  2359. data.dataMocks.push(deepClone(item));
  2360. (meta2d.store.data as any).dataMocks = data.dataMocks;
  2361. meta2d.startDataMock();
  2362. };
  2363. const onAddAllMock = () => {
  2364. if (!data.dataset.devices) {
  2365. return;
  2366. }
  2367. data.dataset.devices.forEach((item) => {
  2368. if (data.dataMocks.find((elem) => elem.id === item.id)) {
  2369. return;
  2370. }
  2371. item.name = item.label;
  2372. data.dataMocks.push(deepClone(item));
  2373. });
  2374. (meta2d.store.data as any).dataMocks = data.dataMocks;
  2375. meta2d.startDataMock();
  2376. };
  2377. const deleteMock = (index: number) => {
  2378. data.dataMocks.splice(index, 1);
  2379. (meta2d.store.data as any).dataMocks = data.dataMocks;
  2380. setDot(true);
  2381. };
  2382. </script>
  2383. <style lang="postcss" scoped>
  2384. /* :deep(.data-input-box){
  2385. position: absolute;
  2386. left: 193px;
  2387. width: 501px;
  2388. top: 80px;
  2389. } */
  2390. .content {
  2391. background: var(--color-background-active);
  2392. padding: 0px 16px;
  2393. .data-header{
  2394. position: sticky;
  2395. top:0;
  2396. background: var(--color-background-active);
  2397. z-index: 2;
  2398. padding-top: 16px;
  2399. }
  2400. .tree-icon {
  2401. width: 14px;
  2402. height: 14px;
  2403. }
  2404. .datasource-title{
  2405. color: #6e7e99;
  2406. }
  2407. .prop-title {
  2408. white-space: nowrap;
  2409. overflow: hidden;
  2410. text-overflow: ellipsis;
  2411. }
  2412. :deep(.t-collapse) {
  2413. border: none;
  2414. }
  2415. :deep(.t-collapse-panel__header) {
  2416. border: none;
  2417. font-size: 12px;
  2418. font-weight: 400;
  2419. padding: 8px 0px;
  2420. background: var(--color-background-active);
  2421. }
  2422. :deep(.t-collapse-panel__body) {
  2423. border: none;
  2424. }
  2425. :deep(.t-collapse-panel__content) {
  2426. background-color: var(--color-background-active);
  2427. color: var(--color);
  2428. padding: 8px 0px;
  2429. }
  2430. .btn-select {
  2431. height: 32px;
  2432. line-height: 32px;
  2433. color: #fff;
  2434. border: 1px solid var(--color-border);
  2435. border-radius: 4px;
  2436. padding: 0px 8px;
  2437. background-color: var(--color-background-input);
  2438. cursor: pointer;
  2439. }
  2440. .btn-select-active {
  2441. background-color: var(--color-primary);
  2442. }
  2443. .input-search {
  2444. flex-shrink: 0;
  2445. color: #878f9c;
  2446. padding: 0px;
  2447. margin-top: 10px;
  2448. .btn {
  2449. background: #fff0;
  2450. left: 12px;
  2451. img {
  2452. background-color: #fff0;
  2453. margin-top: 9px;
  2454. }
  2455. }
  2456. :deep(.t-select) {
  2457. .t-input {
  2458. padding-left: 8px !important;
  2459. }
  2460. }
  2461. }
  2462. .select-search {
  2463. .t-input {
  2464. padding-left: 8px !important;
  2465. .t-icon {
  2466. font-size: 12px;
  2467. }
  2468. }
  2469. }
  2470. .title {
  2471. height: 32px;
  2472. line-height: 32px;
  2473. }
  2474. .title-span {
  2475. display: inline-block;
  2476. margin-left: 4px;
  2477. max-width: 108px;
  2478. overflow: hidden;
  2479. white-space: nowrap;
  2480. text-overflow: ellipsis;
  2481. }
  2482. .data-list {
  2483. /* padding: 12px 6px; */
  2484. /* background: var(--color-background-active); */
  2485. max-height: calc(100vh - 200px);
  2486. margin-bottom: 24px;
  2487. overflow-y: auto;
  2488. .data-title {
  2489. /* padding: 4px; */
  2490. }
  2491. .data-body {
  2492. margin-bottom: 8px;
  2493. }
  2494. .data-title-hover {
  2495. &:hover {
  2496. background: var(--color-background-input);
  2497. border-radius: 4px;
  2498. }
  2499. }
  2500. width: 234px;
  2501. & > div {
  2502. width: 218px;
  2503. }
  2504. }
  2505. .data-mock-list {
  2506. height: auto;
  2507. max-height: calc(100vh - 220px);
  2508. }
  2509. .icon-box {
  2510. width: 24px;
  2511. height: 24px;
  2512. margin: 4px;
  2513. text-align: center;
  2514. line-height: 24px;
  2515. border-radius: 4px;
  2516. &:hover {
  2517. background: var(--td-brand-color-light);
  2518. }
  2519. .t-icon {
  2520. width: 14px;
  2521. height: 14px;
  2522. }
  2523. }
  2524. .icon-item-box {
  2525. height: 30px;
  2526. line-height: 30px;
  2527. margin: 1px;
  2528. }
  2529. .nodata {
  2530. padding-top: 50px;
  2531. img {
  2532. width: 80px;
  2533. }
  2534. .gray {
  2535. margin-top: 8px;
  2536. }
  2537. .t-button {
  2538. height: 24px;
  2539. padding-left: 8px;
  2540. padding-right: 8px;
  2541. }
  2542. }
  2543. .form-line {
  2544. margin-left: 12px;
  2545. width: 11px;
  2546. /* height: 120px; */
  2547. /* border-bottom: 1px solid var(--color-background-input); */
  2548. /* border-left: 1px solid var(--color-background-input); */
  2549. }
  2550. .form-data-item {
  2551. margin-left: 4px;
  2552. margin-top: 4px;
  2553. /* margin-right: 12px; */
  2554. label {
  2555. /* color: #ffffff80; */
  2556. height: 24px;
  2557. line-height: 24px;
  2558. width: 60px;
  2559. }
  2560. & > div {
  2561. width: 118px;
  2562. height: 24px;
  2563. line-height: 24px;
  2564. /* background: var(--color-background-input); */
  2565. border-radius: 4px;
  2566. /* color: #e3e8f459; */
  2567. padding-left: 8px;
  2568. padding-right: 8px;
  2569. overflow: hidden;
  2570. white-space: nowrap;
  2571. text-overflow: ellipsis;
  2572. }
  2573. }
  2574. .form-mock-item {
  2575. & > div {
  2576. padding: 0px;
  2577. :deep(.t-input) {
  2578. height: 24px !important;
  2579. border: 0px;
  2580. }
  2581. }
  2582. }
  2583. .form-swicth-item {
  2584. margin-left: 4px;
  2585. label {
  2586. /* color: #ffffff80; */
  2587. height: 24px;
  2588. width: 56px;
  2589. }
  2590. }
  2591. .data-code {
  2592. width: 218px;
  2593. .code-editor {
  2594. height: 126px;
  2595. }
  2596. }
  2597. .data-code-full {
  2598. position: absolute;
  2599. /* right: calc(50% - 250px); */
  2600. width: 100%;
  2601. height: 100vh;
  2602. background: var(--td-mask-active);
  2603. right: 0px;
  2604. top: 0px;
  2605. .code-editor {
  2606. width: 800px;
  2607. margin: 0 auto;
  2608. height: 80%;
  2609. margin-top: 16vh;
  2610. }
  2611. .data-full-icon {
  2612. .t-icon {
  2613. margin-right: calc(50% - 384px);
  2614. }
  2615. }
  2616. }
  2617. .data-full-icon {
  2618. margin-top: -20px;
  2619. /* z-index: 10000; */
  2620. position: relative;
  2621. display: flex;
  2622. justify-content: flex-end;
  2623. width: 100%;
  2624. .t-icon {
  2625. margin-right: 16px;
  2626. cursor: pointer;
  2627. height: 16px;
  2628. width: 16px;
  2629. }
  2630. }
  2631. ul {
  2632. list-style-type: none;
  2633. }
  2634. }
  2635. :deep(.t-tree) {
  2636. .t-icon {
  2637. width: 14px;
  2638. height: 14px;
  2639. }
  2640. .t-tree__label {
  2641. font-size: 12px;
  2642. color: #bdc7db;
  2643. }
  2644. .t-tree__item[data-level='0'] {
  2645. .t-tree__operations{
  2646. visibility: hidden;
  2647. }
  2648. &:hover{
  2649. .t-tree__operations{
  2650. visibility: visible;
  2651. }
  2652. }
  2653. }
  2654. .t-tree__item[data-level='1'] {
  2655. padding: 0 0 0 16px;
  2656. .t-checkbox__label {
  2657. max-width: 148px;
  2658. overflow: hidden;
  2659. white-space: nowrap;
  2660. text-overflow: ellipsis;
  2661. }
  2662. .t-tree__operations{
  2663. display: none;
  2664. }
  2665. &:hover{
  2666. .t-checkbox__label {
  2667. max-width: 94px;
  2668. }
  2669. .t-tree__operations{
  2670. display: block;
  2671. }
  2672. }
  2673. }
  2674. .t-tree__item[data-level='2'] {
  2675. padding: 0 0 0 16px;
  2676. .t-checkbox__label {
  2677. max-width: 50px;
  2678. overflow: hidden;
  2679. white-space: nowrap;
  2680. text-overflow: ellipsis;
  2681. }
  2682. }
  2683. /* .t-tree__item{
  2684. .t-tree__operations{
  2685. display: none;
  2686. }
  2687. }
  2688. .t-tree__item:hover{
  2689. .t-tree__operations{
  2690. display: block;
  2691. }
  2692. } */
  2693. .t-tree__item .t-icon {
  2694. color: #bdc7db;
  2695. }
  2696. .t-tree__label.t-is-checked {
  2697. background: none;
  2698. }
  2699. }
  2700. :deep(.t-tree--checkable){
  2701. .t-tree__item[data-level='1'] {
  2702. padding: 0 0 0 0px;
  2703. }
  2704. }
  2705. </style>
  2706. <style lang="postcss">
  2707. .menu-item-a {
  2708. &:hover {
  2709. color: var(--td-brand-color);
  2710. }
  2711. }
  2712. .network-option {
  2713. height: 100%;
  2714. padding: 0px;
  2715. }
  2716. .iot-dialog{
  2717. .t-tree--checkable{
  2718. .t-tree__item[data-level='1'] {
  2719. padding: 0 0 0 16px;
  2720. }
  2721. }
  2722. }
  2723. </style>