Data.vue 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661
  1. <template>
  2. <div class="content" :draggable="false" v-if="group === '列表'">
  3. <div class="flex between">
  4. <div class="title">数据{{ group }}</div>
  5. <div class="flex between">
  6. <t-dropdown :minColumnWidth="168" :hide-after-item-click="false">
  7. <t-tooltip content="导入数据列表" placement="top">
  8. <div class="icon-box" @mouseenter="getDatasets()">
  9. <FileImportIcon />
  10. </div>
  11. </t-tooltip>
  12. <t-dropdown-menu>
  13. <t-dropdown-item :value="1">
  14. <!-- <t-dropdown
  15. :minColumnWidth="168"
  16. :maxColumnWidth="300"
  17. :trigger="'click'"
  18. :hide-after-item-click="false"
  19. > -->
  20. 我的变量列表
  21. <!-- </t-dropdown> -->
  22. <t-dropdown-menu>
  23. <t-dropdown-item v-if="!user.id"> 请先登录! </t-dropdown-item>
  24. <t-dropdown-item v-else-if="!data.datasetList.length">
  25. 暂无数据
  26. </t-dropdown-item>
  27. <template v-else>
  28. <t-dropdown-item v-for="(dataset, i) in data.datasetList">
  29. <div
  30. class="hover-background item"
  31. @click="onSelDataset(dataset.id)"
  32. >
  33. <div style="font-size: 14px">{{ dataset.name }}</div>
  34. <div v-if="dataset.url" class="desc">
  35. {{ dataset.url }}
  36. </div>
  37. <div v-else class="desc">自定义</div>
  38. <!-- <t-popconfirm
  39. content="确认删除吗?"
  40. @confirm.stop="onDelDataset(dataset, i)"
  41. @enter.stop
  42. @mouseenter.stop
  43. > -->
  44. <span class="del" @click.stop="onDelDataset(dataset, i)">
  45. <delete-icon />
  46. </span>
  47. <!-- </t-popconfirm> -->
  48. </div>
  49. </t-dropdown-item>
  50. </template>
  51. </t-dropdown-menu>
  52. </t-dropdown-item>
  53. <t-dropdown-item :value="3" :divider="true">
  54. 在线接口
  55. <t-dropdown-menu
  56. class="menu-item-input"
  57. style="max-width: 216px !important"
  58. >
  59. <t-dropdown-item
  60. :value="3 - 1"
  61. style="max-width: 216px !important"
  62. >
  63. <div
  64. class="data-input-box"
  65. style="max-width: 216px !important"
  66. >
  67. <t-input
  68. label="地址:"
  69. style="width: 216px"
  70. placeholder="请输入地址"
  71. v-model="data.dataset.url"
  72. @blur="getDatas"
  73. @enter="getDatas"
  74. >
  75. <template #suffixIcon>
  76. <CloudDownloadIcon
  77. @click="getDatas"
  78. :style="{ cursor: 'pointer' }"
  79. />
  80. </template>
  81. </t-input>
  82. </div>
  83. </t-dropdown-item>
  84. </t-dropdown-menu>
  85. </t-dropdown-item>
  86. <t-dropdown-item :value="2" @click="importDataset">
  87. 从Excel导入
  88. </t-dropdown-item>
  89. <t-dropdown-item :value="4">
  90. <a
  91. :href="
  92. isDownload
  93. ? '/v/data.xlsx'
  94. : cdn
  95. ? cdn + '/v/data.xlsx'
  96. : '/data.xlsx'
  97. "
  98. style="color: var(--td-text-color-primary)"
  99. @click.stop
  100. >
  101. 下载Excel示例
  102. </a>
  103. </t-dropdown-item>
  104. </t-dropdown-menu>
  105. </t-dropdown>
  106. <t-dropdown :minColumnWidth="168">
  107. <t-tooltip content="导出数据列表" placement="top">
  108. <div class="icon-box">
  109. <FileExportIcon />
  110. </div>
  111. </t-tooltip>
  112. <t-dropdown-menu>
  113. <t-dropdown-item @click="downloadAsJson"
  114. >下载为JSON</t-dropdown-item
  115. >
  116. <t-dropdown-item @click="downloadAsExcel"
  117. >下载为Excel</t-dropdown-item
  118. >
  119. <t-dropdown-item @click="onOkDataset()"
  120. >保存为我的数据列表</t-dropdown-item
  121. >
  122. </t-dropdown-menu>
  123. </t-dropdown>
  124. <t-popconfirm
  125. content="确认清空数据列表吗?"
  126. placement="bottom"
  127. @confirm="clearData"
  128. >
  129. <t-tooltip content="清空列表" placement="top">
  130. <div class="icon-box">
  131. <DeleteIcon />
  132. </div>
  133. </t-tooltip>
  134. </t-popconfirm>
  135. <t-tooltip content="新建变量" placement="top">
  136. <div class="icon-box">
  137. <AddIcon @click="showAddData()" />
  138. </div>
  139. </t-tooltip>
  140. </div>
  141. </div>
  142. <div class="flex between mt-8">
  143. <t-tooltip content="可批量导入数据图元到画布" placement="top">
  144. <t-checkbox v-model="data.checkAll">批量导入到画布</t-checkbox>
  145. </t-tooltip>
  146. <t-tooltip content="开启全局数据模拟" placement="top">
  147. <t-checkbox v-model="data.enableMock" @change="onChangeMock"
  148. >开启模拟</t-checkbox
  149. >
  150. </t-tooltip>
  151. </div>
  152. <div class="input-search">
  153. <div class="btn">
  154. <search-icon class="hover" />
  155. <!-- <img src="/img/icon_search_gray.svg" /> -->
  156. </div>
  157. <t-input
  158. v-model="search"
  159. @change="onSearch"
  160. @enter="onSearch"
  161. placeholder="搜索我的数据列表"
  162. />
  163. </div>
  164. <div
  165. id="dragElem"
  166. style="position: absolute; left: 0; z-index: -999"
  167. v-if="data.dataset?.devices?.length"
  168. >
  169. <div
  170. class="flex mt-4"
  171. v-for="(device, i) in data.dataset.devices"
  172. v-show="device.checked"
  173. >
  174. <div style="width: 150px; text-align: end">{{ device.label }}:</div>
  175. <div class="ml-4">{{ device.mock }}</div>
  176. </div>
  177. </div>
  178. <div
  179. class="mt-16 data-list"
  180. v-if="data.dataset?.devices?.length"
  181. :draggable="data.checkAll ? true : false"
  182. @dragstart="onAddShape($event, data.dataset?.devices)"
  183. >
  184. <div
  185. v-for="(device, i) in data.dataset.devices"
  186. v-show="!(device.show === false)"
  187. >
  188. <div
  189. class="flex between data-title"
  190. :class="
  191. (device.expend ? '' : 'data-title-hover') +
  192. ' ' +
  193. (device.checked ? 'drag-checked' : '')
  194. "
  195. :draggable="data.checkAll ? false : true"
  196. @dragstart="onAddShape($event, device)"
  197. >
  198. <div
  199. class="flex"
  200. style="height: 32px; line-height: 32px; cursor: pointer"
  201. >
  202. <!-- <MinusCircleIcon
  203. v-if="device.expend"
  204. @click="device.expend = false"
  205. />
  206. <AddCircleIcon v-else @click="device.expend = true" /> -->
  207. <t-checkbox
  208. v-if="data.checkAll"
  209. v-model="device.checked"
  210. ></t-checkbox>
  211. <template v-else>
  212. <CaretDownSmallIcon
  213. style="height: auto"
  214. v-if="device.expend"
  215. @click="device.expend = false"
  216. />
  217. <CaretRightSmallIcon
  218. style="height: auto"
  219. v-else
  220. @click="device.expend = true"
  221. />
  222. </template>
  223. <p class="title-span">{{ device.label }}</p>
  224. </div>
  225. <div class="flex">
  226. <t-tooltip content="开启单个模拟" placement="top">
  227. <div
  228. class="icon-box icon-item-box"
  229. @click="device.enableMock = !device.enableMock"
  230. >
  231. <RouterWaveIcon
  232. :style="{
  233. color: device.enableMock ? 'var(--color-primary)' : '',
  234. }"
  235. />
  236. </div>
  237. </t-tooltip>
  238. <div class="icon-box icon-item-box" @click="showAddData(device, i)">
  239. <Edit2Icon />
  240. </div>
  241. <t-popconfirm content="确认删除吗?" @confirm="deleteData(i)">
  242. <div class="icon-box icon-item-box">
  243. <DeleteIcon />
  244. </div>
  245. </t-popconfirm>
  246. </div>
  247. </div>
  248. <div class="data-body">
  249. <div v-if="device.expend" class="flex">
  250. <span class="form-line"></span>
  251. <div>
  252. <!-- <div class="form-item form-data-item mt-8">
  253. <label>显示名称</label>
  254. <div :title="device.label">{{ device.label }}</div>
  255. </div> -->
  256. <div class="form-item form-data-item">
  257. <label>变量名:</label>
  258. <div :title="device.id">{{ device.id }}</div>
  259. </div>
  260. <div class="form-item form-data-item">
  261. <label>类型:</label>
  262. <div :title="device.type">{{ device.type }}</div>
  263. </div>
  264. <div class="form-item form-data-item">
  265. <label>值范围:</label>
  266. <div :title="device.mock">{{ device.mock }}</div>
  267. </div>
  268. </div>
  269. </div>
  270. </div>
  271. </div>
  272. </div>
  273. <div class="flex column middle nodata" v-else>
  274. <img src="/img/no-data.svg" />
  275. <div class="gray center">暂无数据</div>
  276. <div class="mt-20">
  277. <t-button theme="primary" @click="showAddData()"> 新建变量 </t-button>
  278. </div>
  279. </div>
  280. </div>
  281. <div class="content" v-if="group === '获取'">
  282. <div class="flex between">
  283. <div class="title">数据{{ group }}</div>
  284. <div class="flex between">
  285. <t-tooltip content="添加数据获取" placement="top">
  286. <div class="icon-box" @click="addNetwork()">
  287. <AddIcon />
  288. </div>
  289. </t-tooltip>
  290. </div>
  291. </div>
  292. <div class="input-search select-search">
  293. <t-select
  294. v-model="data.networkId"
  295. filterable
  296. clearable
  297. placeholder="搜索我的数据获取"
  298. @focus="onInputNetwork"
  299. :on-search="onInputNetwork"
  300. @change="onSelectNetWork"
  301. >
  302. <template #prefixIcon>
  303. <SearchIcon />
  304. </template>
  305. <t-option
  306. class="network-option"
  307. v-for="(item, i) in data.networkList"
  308. :key="item.id"
  309. :value="item.id"
  310. :label="item.name"
  311. >
  312. <div class="hover-background item">
  313. <div style="font-size: 14px">{{ item.name }}</div>
  314. <div class="desc">
  315. {{ item.url }}
  316. </div>
  317. <span class="del" @click.stop="onDelNetWork(item, i)">
  318. <delete-icon />
  319. </span>
  320. </div>
  321. </t-option>
  322. </t-select>
  323. </div>
  324. <div class="mt-16 data-list" v-if="data.networks.length">
  325. <div
  326. v-for="(network, i) in data.networks"
  327. v-show="!(network.show === false)"
  328. >
  329. <div
  330. class="flex between data-title"
  331. :class="network.expend ? '' : 'data-title-hover'"
  332. >
  333. <div style="height: 32px; line-height: 32px; cursor: pointer">
  334. <CaretDownSmallIcon
  335. style="height: auto"
  336. v-if="network.expend"
  337. @click="network.expend = false"
  338. />
  339. <CaretRightSmallIcon
  340. style="height: auto"
  341. v-else
  342. @click="network.expend = true"
  343. />
  344. {{ network.name }}
  345. </div>
  346. <div class="flex">
  347. <div class="icon-box" @click="editNetwork(network, i)">
  348. <Edit2Icon />
  349. </div>
  350. <t-popconfirm content="确认删除吗?" @confirm="deleteNetwork(i)">
  351. <div class="icon-box">
  352. <DeleteIcon />
  353. </div>
  354. </t-popconfirm>
  355. </div>
  356. </div>
  357. <div class="data-body">
  358. <div v-if="network.expend" class="flex">
  359. <span class="form-line" style="height: 88px"></span>
  360. <div>
  361. <div class="form-item form-data-item mt-8">
  362. <label>显示名称:</label>
  363. <div :title="network.name">{{ network.name }}</div>
  364. </div>
  365. <div class="form-item form-data-item mt-8">
  366. <label>通信方式:</label>
  367. <div :title="network.protocol">{{ network.protocol }}</div>
  368. </div>
  369. <div class="form-item form-data-item mt-8">
  370. <label>URL地址:</label>
  371. <div :title="network.url">{{ network.url }}</div>
  372. </div>
  373. </div>
  374. </div>
  375. </div>
  376. </div>
  377. </div>
  378. <div class="flex column middle nodata" v-else>
  379. <img src="/img/no-data.svg" />
  380. <div class="gray center">暂无数据</div>
  381. <div class="mt-20">
  382. <t-button theme="primary" @click="addNetwork()">
  383. 添加数据获取
  384. </t-button>
  385. </div>
  386. </div>
  387. </div>
  388. <div class="content" v-if="group === '监听'">
  389. <div class="flex between">
  390. <div class="title">数据{{ group }}</div>
  391. </div>
  392. <div class="mt-8">
  393. <CodeEditor
  394. :key="data.randomkey"
  395. v-model="data.socketCbJs"
  396. style="min-height: 300px"
  397. @change="onSocketCbJsChange"
  398. />
  399. <div class="data-full-icon hover">
  400. <Fullscreen2Icon @click="showDataTransformation" />
  401. </div>
  402. </div>
  403. <div class="mt-16">
  404. 参考文档:
  405. <a
  406. target="_blank"
  407. 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"
  408. >
  409. 解析自定义格式数据</a
  410. >
  411. </div>
  412. </div>
  413. <!-- <div class="content" v-show="group === '数据模拟'">
  414. <div class="flex between">
  415. <div class="title">{{ group }}</div>
  416. <div class="flex between">
  417. <t-dropdown :minColumnWidth="168">
  418. <t-tooltip
  419. :content="
  420. data.dataset?.devices?.length
  421. ? '添加一条数据模拟'
  422. : '请先添加数据列表'
  423. "
  424. placement="top"
  425. >
  426. <div class="icon-box">
  427. <AddIcon />
  428. </div>
  429. </t-tooltip>
  430. <t-dropdown-menu v-if="data.dataset?.devices?.length">
  431. <t-dropdown-item >
  432. <div class="hover-background item" @click="onAddAllMock">导入所有数据列表</div>
  433. </t-dropdown-item>
  434. <t-dropdown-item v-for="(dataset, i) in data.dataset?.devices">
  435. <div class="hover-background item" @click="onAddmock(dataset)">
  436. <div style="font-size: 14px">{{ dataset.label }}</div>
  437. <div class="desc">
  438. {{ dataset.id }}
  439. </div>
  440. </div>
  441. </t-dropdown-item>
  442. </t-dropdown-menu>
  443. </t-dropdown>
  444. </div>
  445. </div>
  446. <div class="mt-16 data-list data-mock-list" v-if="data.dataMocks.length">
  447. <div v-for="(item, i) in data.dataMocks" v-show="!(item.show === false)">
  448. <div
  449. class="flex between data-title"
  450. :class="item.expend ? '' : 'data-title-hover'"
  451. >
  452. <div style="height: 32px; line-height: 32px; cursor: pointer">
  453. <MinusCircleIcon v-if="item.expend" @click="item.expend = false" />
  454. <AddCircleIcon v-else @click="item.expend = true" />
  455. {{ item.name }}
  456. </div>
  457. <div class="flex">
  458. <t-popconfirm content="确认删除吗?" @confirm="deleteMock(i)">
  459. <div class="icon-box">
  460. <DeleteIcon />
  461. </div>
  462. </t-popconfirm>
  463. </div>
  464. </div>
  465. <div class="data-body">
  466. <div v-if="item.expend" class="flex">
  467. <span class="form-line" style="height: 150px"></span>
  468. <div>
  469. <div class="form-item form-data-item mt-8">
  470. <label>显示名称</label>
  471. <div :title="item.name">{{ item.name }}</div>
  472. </div>
  473. <div class="form-item form-data-item mt-8">
  474. <label>变量名</label>
  475. <div :title="item.id">{{ item.id }}</div>
  476. </div>
  477. <div class="form-item form-data-item form-mock-item mt-8">
  478. <label>模拟值
  479. <t-tooltip placement="top">
  480. <template #content>
  481. <div style="font-size:10px;">
  482. 模拟值说明<br/>
  483. 固定值:直接填写,例如:10<br/>
  484. 随机值:值1,值2,...。例如:1,2,3,4,5<br/>
  485. 范围数字:最小值-最大值。例如:0-1.0 或 0-100<br/>
  486. 随机字符串: [长度]。例如:[8]<br/>
  487. </div>
  488. </template>
  489. <HelpCircleIcon style="font-size: 12px;"/>
  490. </t-tooltip>
  491. </label>
  492. <t-input v-model="item.mock" />
  493. </div>
  494. <div class="form-item form-data-item form-mock-item mt-8">
  495. <label>类型</label>
  496. <t-select
  497. class="w-full"
  498. :options="typeOptions"
  499. v-model="item.type"
  500. placeholder="字符串"
  501. />
  502. </div>
  503. <div class="form-item form-swicth-item mt-8">
  504. <label>开启</label>
  505. <t-switch class="mt-8" size="small" v-model="item.enableMock" />
  506. </div>
  507. </div>
  508. </div>
  509. </div>
  510. </div>
  511. </div>
  512. <div class="flex column middle nodata" v-else>
  513. <img src="/img/no-data.svg" />
  514. <div class="gray center">暂无数据</div>
  515. </div>
  516. <div class="flex between mt-24">
  517. <t-checkbox
  518. style="display: inline"
  519. v-model="data.enableMock"
  520. @change="onChangeMock"
  521. >
  522. 开启模拟数据
  523. </t-checkbox>
  524. </div>
  525. </div> -->
  526. <t-dialog
  527. v-if="addDataDialog.show"
  528. :visible="true"
  529. class="data-dialog"
  530. :header="addDataDialog.header"
  531. @close="addDataDialog.show = false"
  532. @confirm="onOkAddData"
  533. >
  534. <!-- <div class="form-item mt-16">
  535. <label>设备</label>
  536. <t-input v-model="addDataDialog.data.device" placeholder="设备名称" />
  537. </div> -->
  538. <div class="form-item mt-16">
  539. <label>显示名称</label>
  540. <t-input
  541. @change="changeDataLabel($event)"
  542. :value="addDataDialog.data.label"
  543. placeholder="变量简短描述"
  544. />
  545. </div>
  546. <div class="form-item mt-16">
  547. <label>变量名</label>
  548. <t-input
  549. @change="changeDataID($event)"
  550. :value="addDataDialog.data.id"
  551. placeholder="变量名"
  552. />
  553. </div>
  554. <div class="form-item mt-16">
  555. <label>类型</label>
  556. <t-select
  557. class="w-full"
  558. :options="typeOptions"
  559. v-model="addDataDialog.data.type"
  560. placeholder="字符串"
  561. @change="addDataDialog.data.value = null"
  562. />
  563. </div>
  564. <div class="form-item mt-16">
  565. <label
  566. >值范围
  567. <t-tooltip content="可用做数据模拟" placement="top">
  568. <HelpCircleIcon style="font-size: 12px" />
  569. </t-tooltip>
  570. </label>
  571. <div class="w-full">
  572. <t-input v-model="addDataDialog.data.mock" placeholder="值范围" />
  573. <h6 class="desc mt-8" style="font-size: 12px">值范围说明</h6>
  574. <ul class="desc ml-16" style="font-size: 12px">
  575. <li>
  576. <label class="inline" style="width: 80px">固定值:</label>
  577. 直接填写,例如:10
  578. </li>
  579. <li>
  580. <label class="inline" style="width: 80px">随机值:</label>
  581. 值1,值2,...。例如:1,2,3,4,5
  582. </li>
  583. <li>
  584. <label class="inline" style="width: 80px">范围数字:</label>
  585. 最小值-最大值。例如:0-1.0 或 0-100
  586. </li>
  587. <li>
  588. <label class="inline" style="width: 80px">随机字符串:</label>
  589. [长度]。例如:[8]
  590. </li>
  591. </ul>
  592. </div>
  593. </div>
  594. </t-dialog>
  595. <t-dialog
  596. v-if="networkDialog.show"
  597. :visible="true"
  598. width="800px"
  599. class="data-dialog"
  600. :header="networkDialog.header"
  601. @close="networkDialog.show = false"
  602. @confirm="onOkNetwork"
  603. >
  604. <template #footer>
  605. <div class="flex mr-8" style="justify-content: end">
  606. <t-checkbox v-model="networkDialog.save" class="mr-12">
  607. 同时保存到我的数据获取
  608. </t-checkbox>
  609. <t-button @click="onOkNetwork">确定</t-button>
  610. </div>
  611. </template>
  612. <div style="height: 300px; padding: 8px; overflow-y: auto">
  613. <Network v-model="networkDialog.network" />
  614. </div>
  615. </t-dialog>
  616. <t-dialog
  617. v-if="dataTransformationDialog.show"
  618. :visible="true"
  619. header="数据监听"
  620. @confirm="onOkDataTransformation"
  621. @close="dataTransformationDialog.show = false"
  622. :width="800"
  623. >
  624. <CodeEditor v-model="dataTransformationDialog.data" style="height: 300px" />
  625. <div class="mt-8">
  626. 参考文档:
  627. <a
  628. target="_blank"
  629. 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"
  630. >
  631. 解析自定义格式数据</a
  632. >
  633. </div>
  634. </t-dialog>
  635. </template>
  636. <script lang="ts" setup>
  637. import { reactive, defineComponent, ref, onMounted, toRaw } from 'vue';
  638. import {
  639. FileImportIcon,
  640. FileExportIcon,
  641. DeleteIcon,
  642. AddIcon,
  643. AddCircleIcon,
  644. MinusCircleIcon,
  645. Edit2Icon,
  646. FileExcelIcon,
  647. CloudDownloadIcon,
  648. SearchIcon,
  649. Fullscreen2Icon,
  650. FullscreenExit1Icon,
  651. HelpCircleIcon,
  652. CaretDownSmallIcon,
  653. CaretRightSmallIcon,
  654. RouterWaveIcon,
  655. ArrowUpDown3Icon,
  656. } from 'tdesign-icons-vue-next';
  657. import { typeOptions } from '@/services/common';
  658. import { MessagePlugin } from 'tdesign-vue-next';
  659. import { Pen, deepClone } from '@meta2d/core';
  660. import { useDot } from '@/services/common';
  661. import { isDownload } from '@/services/defaults';
  662. import { cdn } from '@/services/api';
  663. import { importExcel, saveAsExcel } from '@/services/excel';
  664. import axios from 'axios';
  665. import { transformData } from '@/services/utils';
  666. import { debounce } from '@/services/debouce';
  667. import Network from '@/views/components/Network.vue';
  668. import CodeEditor from '@/views/components/common/CodeEditor.vue';
  669. import { s8 } from '@/services/random';
  670. import { useUser } from '@/services/user';
  671. const props = defineProps<{
  672. group: string;
  673. }>();
  674. const { user } = useUser();
  675. const { dot, setDot } = useDot();
  676. const data = reactive({
  677. //列表
  678. datesetBak: {},
  679. datasetId: '',
  680. networks: [],
  681. datasetList: [],
  682. dataset: {
  683. name: '',
  684. id: '',
  685. url: '',
  686. devices: [],
  687. } as any,
  688. checkAll: false,
  689. //获取
  690. networkList: [],
  691. input: '',
  692. popupVisible: false,
  693. networkId: '',
  694. //监听
  695. socketCbJs: '',
  696. full: false,
  697. dataMocks: [
  698. // {
  699. // name: '',
  700. // id: '',
  701. // enableMock: true,
  702. // mock: 'aaa',
  703. // type: 'string',
  704. // expend: true,
  705. // show: false,
  706. // },
  707. ],
  708. enableMock: false,
  709. randomkey: s8(),
  710. });
  711. onMounted(() => {
  712. data.networks = meta2d.store.data.networks || [];
  713. data.dataset = (meta2d.store.data as any).dataset || {};
  714. data.socketCbJs = meta2d.store.data.socketCbJs || '';
  715. // data.dataMocks = meta2d.store.data.dataMocks || [];
  716. data.enableMock = meta2d.store.data.enableMock || false;
  717. // getNetworks();
  718. // getDatasets();
  719. });
  720. const addDataDialog = reactive<any>({});
  721. const showAddData = (row?: any, index?: number) => {
  722. if (row) {
  723. addDataDialog.header = '编辑数据';
  724. addDataDialog.data = JSON.parse(JSON.stringify(row));
  725. addDataDialog.index = index;
  726. } else {
  727. addDataDialog.header = '添加数据';
  728. addDataDialog.data = { type: 'string', expend: true };
  729. }
  730. addDataDialog.show = true;
  731. };
  732. const deleteData = (row: any) => {
  733. data.dataset.devices.splice(row, 1);
  734. (meta2d.store.data as any).dataset = data.dataset;
  735. setDot(true);
  736. };
  737. const clearData = () => {
  738. data.datasetId = undefined;
  739. data.dataset.id = undefined;
  740. data.dataset.name = undefined;
  741. data.dataset.url = undefined;
  742. data.dataset.devices = [];
  743. setDot(true);
  744. };
  745. const changeDataLabel = (value) => {
  746. if (!value) {
  747. MessagePlugin.error('显示名称不能为空!');
  748. return;
  749. }
  750. let item = data.dataset.devices?.filter((item) => item.label === value);
  751. if (item && item.length) {
  752. MessagePlugin.error('显示名称重复!');
  753. return;
  754. }
  755. addDataDialog.data.label = value;
  756. };
  757. const changeDataID = (value) => {
  758. if (!value) {
  759. MessagePlugin.error('变量名不能为空!');
  760. return;
  761. }
  762. let item = data.dataset.devices?.filter((item) => item.id === value);
  763. if (item && item.length) {
  764. MessagePlugin.error('变量名重复!');
  765. return;
  766. }
  767. addDataDialog.data.id = value;
  768. };
  769. const onOkAddData = () => {
  770. if (!addDataDialog.data.label) {
  771. MessagePlugin.error('请填写名称');
  772. return;
  773. }
  774. if (!addDataDialog.data.id) {
  775. MessagePlugin.error('请填写数据ID');
  776. return;
  777. }
  778. if (!data.dataset.devices) {
  779. data.dataset.devices = [];
  780. }
  781. if (addDataDialog.header === '添加数据') {
  782. data.dataset.devices.push(addDataDialog.data);
  783. } else {
  784. data.dataset.devices[addDataDialog.index] = addDataDialog.data;
  785. //更新所有绑定该id的pen label
  786. let binds = meta2d.store.bind[addDataDialog.data.id];
  787. if (binds) {
  788. binds.forEach((item) => {
  789. const pen: Pen = meta2d.findOne(item.id);
  790. pen.realTimes &&
  791. pen.realTimes.forEach((_realTime) => {
  792. if (_realTime.key === item.key) {
  793. _realTime.bind.label = addDataDialog.data.label;
  794. }
  795. });
  796. });
  797. }
  798. }
  799. (meta2d.store.data as any).dataset = data.dataset;
  800. addDataDialog.show = false;
  801. };
  802. const importDataset = async () => {
  803. let columns: any = [
  804. {
  805. header: '设备',
  806. key: 'device',
  807. },
  808. {
  809. header: '显示名称',
  810. key: 'label',
  811. },
  812. {
  813. header: '变量名',
  814. key: 'id',
  815. },
  816. {
  817. header: '类型',
  818. key: 'type',
  819. },
  820. {
  821. header: '值范围',
  822. key: 'mock',
  823. },
  824. ];
  825. const _data: any = await importExcel(columns);
  826. _data.forEach((item) => {
  827. if (item.device) {
  828. item.label = item.device + '-' + item.label;
  829. delete item.device;
  830. }
  831. });
  832. mergeDataset(data.dataset, _data);
  833. (meta2d.store.data as any).dataset = data.dataset;
  834. };
  835. const downloadAsExcel = () => {
  836. if (!(data.dataset.devices && data.dataset.devices.length)) {
  837. MessagePlugin.error('变量列表不能为空!');
  838. return;
  839. }
  840. const name = meta2d.store.data.name;
  841. const columns: any[] = [
  842. {
  843. key: 'label',
  844. header: '显示名称',
  845. },
  846. {
  847. key: 'id',
  848. header: '变量名',
  849. },
  850. {
  851. key: 'type',
  852. header: '类型',
  853. },
  854. {
  855. key: 'mock',
  856. header: '值范围',
  857. },
  858. ];
  859. saveAsExcel(name, columns, data.dataset.devices);
  860. };
  861. const downloadAsJson = () => {
  862. if (!(data.dataset.devices && data.dataset.devices.length)) {
  863. MessagePlugin.error('变量列表不能为空!');
  864. return;
  865. }
  866. import('file-saver').then(({ saveAs }) => {
  867. saveAs(
  868. new Blob([JSON.stringify(data.dataset)], {
  869. type: 'text/plain;charset=utf-8',
  870. }),
  871. `${data.dataset.name || '未命名'}.json`
  872. );
  873. });
  874. };
  875. const onOkDataset = async (saveas = false) => {
  876. // if (!dataDialog.dataset.name) {
  877. // MessagePlugin.error('名称不能为空');
  878. // return;
  879. // }
  880. if (!(data.dataset.devices && data.dataset.devices.length)) {
  881. MessagePlugin.error('变量列表不能为空');
  882. return;
  883. }
  884. const dataset = JSON.parse(JSON.stringify(data.dataset));
  885. let _data = dataset;
  886. _data.type = 'dataset';
  887. if (!_data.name) {
  888. _data.name = meta2d.store.data.name;
  889. }
  890. _data = transformData(dataset, 'toNetwork');
  891. // 保存到我的数据源
  892. if (saveas || !dataset.id) {
  893. delete dataset.id;
  894. delete dataset._id;
  895. dataset.type = 'dataset';
  896. const ret: any = await axios.post(`/api/data/datasource/add`, _data);
  897. if (!ret) {
  898. return;
  899. }
  900. ret.id = ret.id || ret._id;
  901. data.datasetId = ret.id;
  902. dataset.id = ret.id;
  903. data.dataset.id = ret.id;
  904. data.datasetList.push(dataset);
  905. } else {
  906. const ret: any = await axios.post(`/api/data/datasource/update`, _data);
  907. if (!ret) {
  908. return;
  909. }
  910. data.datasetList.forEach((item: any, index: number) => {
  911. if (
  912. item.id === dataset.id ||
  913. (item._id === dataset._id && dataset._id != undefined)
  914. ) {
  915. data.datasetList.splice(index, 1, dataset);
  916. }
  917. });
  918. }
  919. delete dataset.devices;
  920. // @ts-ignore
  921. // console.log("dataset",dataset);
  922. // meta2d.store.data.dataset = dataset;
  923. // setDot(true);
  924. data.editDataset = false;
  925. delete data.datesetBak;
  926. };
  927. const mergeDataset = (arr1: any, arr2: any[]) => {
  928. if (!(arr2 && arr2.length)) {
  929. return;
  930. }
  931. if (!arr1.devices) {
  932. arr1.devices = [];
  933. }
  934. arr2.forEach((item) => {
  935. let index = arr1.devices.findIndex((elem) => elem.id === item.id);
  936. if (index >= 0) {
  937. Object.assign(arr1.devices[index], item);
  938. } else {
  939. arr1.devices.push(item);
  940. }
  941. });
  942. };
  943. const getDatas = async () => {
  944. if (!data.dataset.url) {
  945. return;
  946. }
  947. const ret = await axios.get(data.dataset.url);
  948. let flattenRet = flattenTree(ret);
  949. if (flattenRet) {
  950. mergeDataset(data.dataset, flattenRet);
  951. (meta2d.store.data as any).dataset = data.dataset;
  952. }
  953. };
  954. //展开树
  955. const flattenTree = (root) => {
  956. if (!root) return []; // 空树返回空数组
  957. const result = []; // 存储展开后的数组
  958. // 递归遍历树
  959. function dfs(node) {
  960. result.push({
  961. id: node.id,
  962. label: node.label || node.name,
  963. device: node.device || node.id,
  964. type: node.type,
  965. mock: node.mock,
  966. // children: node.children,
  967. }); // 将当前节点值添加到结果数组
  968. // 遍历当前节点的子节点
  969. if (node.children) {
  970. for (let child of node.children) {
  971. dfs(child); // 递归调用DFS
  972. }
  973. }
  974. }
  975. root.forEach((item) => {
  976. dfs(item);
  977. });
  978. // dfs(root); // 从根节点开始遍历
  979. return result;
  980. };
  981. const onSelDataset = async (datasetId = false) => {
  982. if (datasetId) {
  983. const dataset = data.datasetList.find((item: any) => {
  984. return item.id === datasetId;
  985. });
  986. if (!dataset) {
  987. return;
  988. }
  989. if (dataset.url) {
  990. const ret = await axios.get(dataset.url);
  991. if (ret) {
  992. dataset.devices = ret;
  993. }
  994. } else {
  995. const ret = await axios.post(`/api/data/datasource/get`, {
  996. id: dataset.id,
  997. });
  998. if (ret?.data) {
  999. Object.assign(dataset, { ...ret.data });
  1000. }
  1001. }
  1002. mergeDataset(data.dataset, dataset.devices);
  1003. (meta2d.store.data as any).dataset = data.dataset;
  1004. // dataDialog.dataset = dataset;
  1005. // if (!init) {
  1006. // const d = JSON.parse(JSON.stringify(dataset));
  1007. // delete d.devices;
  1008. // // @ts-ignore
  1009. // meta2d.store.data.dataset = d;
  1010. // setDot(true);
  1011. // }
  1012. }
  1013. };
  1014. // 请求我的数据模型
  1015. const getDatasets = async (name?: string) => {
  1016. // console.log("进入")
  1017. if (!user.id) {
  1018. MessagePlugin.error('请先登录');
  1019. return;
  1020. }
  1021. const body: any = {
  1022. type: 'dataset',
  1023. projection: 'id,data,name,type',
  1024. };
  1025. if (name) {
  1026. body.name = name;
  1027. }
  1028. const ret: any = await axios.post(`/api/data/datasource/list`, body, {
  1029. params: {
  1030. current: 1,
  1031. pageSize: 10,
  1032. },
  1033. });
  1034. if (ret?.list) {
  1035. const list = [];
  1036. let found = false;
  1037. for (const item of ret.list) {
  1038. item.id = item.id || item._id;
  1039. list.push(transformData(item, 'toMetaNetwork'));
  1040. if (data.dataset?.id === item.id) {
  1041. found = true;
  1042. }
  1043. }
  1044. if (data.dataset?.id && !found) {
  1045. list.push(data.dataset);
  1046. }
  1047. data.datasetList = list;
  1048. }
  1049. };
  1050. const onDelDataset = async (item: any, i: number) => {
  1051. const ret: any = await axios.post(`/api/data/datasource/delete`, {
  1052. id: item.id,
  1053. });
  1054. if (
  1055. (meta2d.store.data as any).dataset &&
  1056. (meta2d.store.data as any).dataset.id === item.id
  1057. ) {
  1058. //@ts-ignore
  1059. meta2d.store.data.dataset = {};
  1060. data.dataset = {};
  1061. data.datasetId = undefined;
  1062. }
  1063. if (ret) {
  1064. data.datasetList.splice(i, 1);
  1065. }
  1066. };
  1067. const search = ref('');
  1068. const onSearch = () => {
  1069. // if (!search.value) {
  1070. // return;
  1071. // }
  1072. data.dataset.devices.forEach((item) => {
  1073. if (
  1074. item.label.indexOf(search.value) !== -1 ||
  1075. item.id.indexOf(search.value) !== -1
  1076. ) {
  1077. item.show = true;
  1078. } else {
  1079. item.show = false;
  1080. }
  1081. });
  1082. };
  1083. const onInputNetwork = (e) => {
  1084. debounce(getNetworks, 300, e);
  1085. };
  1086. const onSelectNetWork = (value) => {
  1087. if (!value) {
  1088. return;
  1089. }
  1090. const network: any = data.networks.find((elem: any) => value === elem.id);
  1091. if (!network) {
  1092. const item = data.networkList.find((elem: any) => value === elem.id);
  1093. data.networks.push(item);
  1094. meta2d.store.data.networks = toRaw(data.networks);
  1095. meta2d.connectNetwork();
  1096. setDot(true);
  1097. }
  1098. // data.input = null;
  1099. data.popupVisible = false;
  1100. };
  1101. // 请求我的实时数据
  1102. const getNetworks = async (e?) => {
  1103. const ret: any = await axios.post(
  1104. `/api/data/datasource/list`,
  1105. {
  1106. // q: {
  1107. name: e,
  1108. // },
  1109. type: 'subscribe',
  1110. projection: 'id,data,name,type',
  1111. },
  1112. {
  1113. params: {
  1114. current: 1,
  1115. pageSize: 10,
  1116. },
  1117. }
  1118. );
  1119. if (ret?.list) {
  1120. const list = [];
  1121. for (const item of ret.list) {
  1122. item.id = item.id || item._id;
  1123. list.push(transformData(item, 'toMetaNetwork'));
  1124. }
  1125. data.networkList = list;
  1126. }
  1127. };
  1128. const onDelNetWork = async (item: any, i: number) => {
  1129. const ret: any = await axios.post(`/api/data/datasource/delete`, {
  1130. id: item.id || item._id,
  1131. });
  1132. if (ret) {
  1133. data.networkList.splice(i, 1);
  1134. }
  1135. };
  1136. const deleteNetwork = (index: number) => {
  1137. data.networks.splice(index, 1);
  1138. meta2d.store.data.networks = toRaw(data.networks);
  1139. meta2d.connectNetwork();
  1140. setDot(true);
  1141. };
  1142. const networkDialog = reactive<any>({
  1143. save: true,
  1144. });
  1145. const editNetwork = (network: any, index: number) => {
  1146. networkDialog.network = JSON.parse(JSON.stringify(network));
  1147. networkDialog.editNetwork = 2;
  1148. networkDialog.editNetworkIndex = index;
  1149. networkDialog.header = '编辑数据获取';
  1150. networkDialog.show = true;
  1151. };
  1152. const addNetwork = () => {
  1153. networkDialog.network = {
  1154. name: '',
  1155. type: 'subscribe',
  1156. protocol: 'mqtt',
  1157. url: '',
  1158. options: {
  1159. clientId: '',
  1160. username: '',
  1161. password: '',
  1162. customClientId: false,
  1163. },
  1164. };
  1165. networkDialog.editNetwork = 1;
  1166. networkDialog.header = '添加数据获取';
  1167. networkDialog.show = true;
  1168. };
  1169. const onOkNetwork = async () => {
  1170. const _data = transformData(networkDialog.network, 'toNetwork');
  1171. if (networkDialog.editNetwork === 1) {
  1172. if (!networkDialog.network.url) {
  1173. MessagePlugin.error('URL地址不能为空!');
  1174. return;
  1175. }
  1176. if (!networkDialog.network.name) {
  1177. MessagePlugin.error('名称不能为空!');
  1178. return;
  1179. }
  1180. if (networkDialog.save) {
  1181. const ret: any = await axios.post(`/api/data/datasource/add`, _data);
  1182. if (!ret) {
  1183. return;
  1184. }
  1185. ret.id = ret.id || ret._id;
  1186. networkDialog.network.id = ret.id;
  1187. }
  1188. data.networks.push(networkDialog.network);
  1189. data.networkList.push(networkDialog.network);
  1190. } else if (networkDialog.editNetwork === 2) {
  1191. if (networkDialog.save) {
  1192. const ret: any = await axios.post(`/api/data/datasource/update`, _data);
  1193. if (!ret) {
  1194. return;
  1195. }
  1196. }
  1197. //替换
  1198. let index = networkDialog.editNetworkIndex;
  1199. if (index !== undefined) {
  1200. data.networks.splice(index, 1, networkDialog.network);
  1201. }
  1202. }
  1203. networkDialog.show = false;
  1204. networkDialog.editNetwork = 0;
  1205. meta2d.store.data.networks = toRaw(data.networks);
  1206. meta2d.connectNetwork();
  1207. setDot(true);
  1208. };
  1209. const dataTransformationDialog = reactive<any>({
  1210. show: false,
  1211. data: '',
  1212. });
  1213. const showDataTransformation = () => {
  1214. dataTransformationDialog.data = meta2d.store.data.socketCbJs;
  1215. dataTransformationDialog.show = true;
  1216. };
  1217. const onOkDataTransformation = () => {
  1218. meta2d.store.data.socketCbJs = dataTransformationDialog.data;
  1219. data.randomkey = s8();
  1220. data.socketCbJs = dataTransformationDialog.data;
  1221. meta2d.listenSocket();
  1222. dataTransformationDialog.show = false;
  1223. };
  1224. let timer: any = 0;
  1225. const onSocketCbJsChange = (e) => {
  1226. clearTimeout(timer);
  1227. timer = setTimeout(() => {
  1228. meta2d.store.data.socketCbJs = data.socketCbJs;
  1229. meta2d.listenSocket();
  1230. }, 3000);
  1231. };
  1232. const onChangeMock = () => {
  1233. // @ts-ignore
  1234. meta2d.store.data.enableMock = data.enableMock;
  1235. if (data.enableMock) {
  1236. meta2d.startDataMock();
  1237. } else {
  1238. meta2d.stopDataMock();
  1239. }
  1240. };
  1241. const onAddShape = (e, _data) => {
  1242. e.stopPropagation();
  1243. let data: any;
  1244. if (Array.isArray(_data)) {
  1245. const dragElem = document.getElementById('dragElem');
  1246. let width = dragElem.offsetWidth;
  1247. e.dataTransfer.setDragImage(dragElem, width / 2, 10);
  1248. const checked = _data.filter((item) => item.checked);
  1249. if(!checked.length){
  1250. MessagePlugin.error('请先选择数据');
  1251. return;
  1252. }
  1253. data = [];
  1254. checked.forEach((item) => {
  1255. data.push(
  1256. ...[
  1257. {
  1258. text: item.label + ':',
  1259. width: 150,
  1260. height: 20,
  1261. name: 'text',
  1262. dataset: true,
  1263. textAlign: 'right',
  1264. },
  1265. {
  1266. text: item.mock,
  1267. width: 100,
  1268. height: 20,
  1269. name: 'text',
  1270. dataset: true,
  1271. textAlign: 'left',
  1272. realTimes: [
  1273. {
  1274. label: '文字',
  1275. key: 'text',
  1276. type: 'string',
  1277. bind: deepClone(item),
  1278. },
  1279. ],
  1280. },
  1281. ]
  1282. );
  1283. });
  1284. } else {
  1285. data = [
  1286. {
  1287. text: _data.label + ':',
  1288. width: 150,
  1289. height: 20,
  1290. name: 'text',
  1291. dataset: true,
  1292. textAlign: 'right',
  1293. },
  1294. {
  1295. text: _data.mock,
  1296. width: 100,
  1297. height: 20,
  1298. name: 'text',
  1299. dataset: true,
  1300. textAlign: 'left',
  1301. realTimes: [
  1302. {
  1303. label: '文字',
  1304. key: 'text',
  1305. type: 'string',
  1306. bind: deepClone(_data),
  1307. },
  1308. ],
  1309. },
  1310. ];
  1311. }
  1312. meta2d.canvas.addCaches = deepClone(data);
  1313. };
  1314. const onAddmock = (item: any) => {
  1315. if (data.dataMocks.find((elem) => elem.id === item.id)) {
  1316. return;
  1317. }
  1318. item.name = item.label;
  1319. data.dataMocks.push(deepClone(item));
  1320. (meta2d.store.data as any).dataMocks = data.dataMocks;
  1321. meta2d.startDataMock();
  1322. };
  1323. const onAddAllMock = () => {
  1324. if (!data.dataset.devices) {
  1325. return;
  1326. }
  1327. data.dataset.devices.forEach((item) => {
  1328. if (data.dataMocks.find((elem) => elem.id === item.id)) {
  1329. return;
  1330. }
  1331. item.name = item.label;
  1332. data.dataMocks.push(deepClone(item));
  1333. });
  1334. (meta2d.store.data as any).dataMocks = data.dataMocks;
  1335. meta2d.startDataMock();
  1336. };
  1337. const deleteMock = (index: number) => {
  1338. data.dataMocks.splice(index, 1);
  1339. (meta2d.store.data as any).dataMocks = data.dataMocks;
  1340. setDot(true);
  1341. };
  1342. </script>
  1343. <style lang="postcss" scoped>
  1344. /* :deep(.data-input-box){
  1345. position: absolute;
  1346. left: 193px;
  1347. width: 501px;
  1348. top: 80px;
  1349. } */
  1350. .content {
  1351. background: var(--color-background-active);
  1352. padding: 16px;
  1353. .input-search {
  1354. flex-shrink: 0;
  1355. color: #878f9c;
  1356. padding: 0px;
  1357. margin-top: 10px;
  1358. .btn {
  1359. background: #fff0;
  1360. left: 12px;
  1361. img {
  1362. background-color: #fff0;
  1363. margin-top: 9px;
  1364. }
  1365. }
  1366. :deep(.t-select) {
  1367. .t-input {
  1368. padding-left: 8px !important;
  1369. }
  1370. }
  1371. }
  1372. .select-search {
  1373. .t-input {
  1374. padding-left: 8px !important;
  1375. .t-icon {
  1376. font-size: 12px;
  1377. }
  1378. }
  1379. }
  1380. .title {
  1381. height: 32px;
  1382. line-height: 32px;
  1383. }
  1384. .title-span {
  1385. display: inline-block;
  1386. margin-left: 4px;
  1387. max-width: 108px;
  1388. overflow: hidden;
  1389. white-space: nowrap;
  1390. text-overflow: ellipsis;
  1391. }
  1392. .data-list {
  1393. /* padding: 12px 6px; */
  1394. /* background: var(--color-background-active); */
  1395. max-height: calc(100vh - 200px);
  1396. margin-bottom: 24px;
  1397. overflow-y: auto;
  1398. .data-title {
  1399. /* padding: 4px; */
  1400. }
  1401. .data-body {
  1402. margin-bottom: 8px;
  1403. }
  1404. .data-title-hover {
  1405. &:hover {
  1406. background: var(--color-background-input);
  1407. border-radius: 4px;
  1408. }
  1409. }
  1410. width: 234px;
  1411. & > div {
  1412. width: 218px;
  1413. }
  1414. }
  1415. .data-mock-list {
  1416. height: auto;
  1417. max-height: calc(100vh - 220px);
  1418. }
  1419. .icon-box {
  1420. width: 24px;
  1421. height: 24px;
  1422. margin: 4px;
  1423. text-align: center;
  1424. line-height: 24px;
  1425. border-radius: 4px;
  1426. &:hover {
  1427. background: var(--td-brand-color-light);
  1428. }
  1429. .t-icon {
  1430. width: 14px;
  1431. height: 14px;
  1432. }
  1433. }
  1434. .icon-item-box {
  1435. height: 30px;
  1436. line-height: 30px;
  1437. margin: 1px;
  1438. }
  1439. .nodata {
  1440. padding-top: 80px;
  1441. img {
  1442. width: 80px;
  1443. }
  1444. .gray {
  1445. margin-top: 8px;
  1446. }
  1447. .t-button {
  1448. //width: 64px;
  1449. height: 24px;
  1450. padding-left: 8px;
  1451. padding-right: 8px;
  1452. }
  1453. }
  1454. .form-line {
  1455. margin-left: 12px;
  1456. width: 11px;
  1457. /* height: 120px; */
  1458. /* border-bottom: 1px solid var(--color-background-input); */
  1459. /* border-left: 1px solid var(--color-background-input); */
  1460. }
  1461. .form-data-item {
  1462. margin-left: 4px;
  1463. margin-top: 4px;
  1464. /* margin-right: 12px; */
  1465. label {
  1466. /* color: #ffffff80; */
  1467. height: 24px;
  1468. line-height: 24px;
  1469. width: 60px;
  1470. }
  1471. & > div {
  1472. width: 118px;
  1473. height: 24px;
  1474. line-height: 24px;
  1475. /* background: var(--color-background-input); */
  1476. border-radius: 4px;
  1477. /* color: #e3e8f459; */
  1478. padding-left: 8px;
  1479. padding-right: 8px;
  1480. overflow: hidden;
  1481. white-space: nowrap;
  1482. text-overflow: ellipsis;
  1483. }
  1484. }
  1485. .form-mock-item {
  1486. & > div {
  1487. padding: 0px;
  1488. :deep(.t-input) {
  1489. height: 24px !important;
  1490. border: 0px;
  1491. }
  1492. }
  1493. }
  1494. .form-swicth-item {
  1495. margin-left: 4px;
  1496. label {
  1497. /* color: #ffffff80; */
  1498. height: 24px;
  1499. width: 56px;
  1500. }
  1501. }
  1502. .data-code {
  1503. width: 218px;
  1504. .code-editor {
  1505. height: 126px;
  1506. }
  1507. }
  1508. .data-code-full {
  1509. position: absolute;
  1510. /* right: calc(50% - 250px); */
  1511. width: 100%;
  1512. height: 100vh;
  1513. background: var(--td-mask-active);
  1514. right: 0px;
  1515. top: 0px;
  1516. .code-editor {
  1517. width: 800px;
  1518. margin: 0 auto;
  1519. height: 80%;
  1520. margin-top: 16vh;
  1521. }
  1522. .data-full-icon {
  1523. .t-icon {
  1524. margin-right: calc(50% - 384px);
  1525. }
  1526. }
  1527. }
  1528. .data-full-icon {
  1529. margin-top: -20px;
  1530. /* z-index: 10000; */
  1531. position: relative;
  1532. display: flex;
  1533. justify-content: flex-end;
  1534. width: 100%;
  1535. .t-icon {
  1536. margin-right: 16px;
  1537. cursor: pointer;
  1538. height: 16px;
  1539. width: 16px;
  1540. }
  1541. }
  1542. ul {
  1543. list-style-type: none;
  1544. }
  1545. }
  1546. </style>
  1547. <style lang="postcss">
  1548. .menu-item-a {
  1549. &:hover {
  1550. color: var(--td-brand-color);
  1551. }
  1552. }
  1553. .network-option {
  1554. height: 100%;
  1555. padding: 0px;
  1556. }
  1557. </style>