DataSource.vue 76 KB

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