PenDatas.vue 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236
  1. <template>
  2. <div class="props">
  3. <t-collapse
  4. :defaultValue="['1', '2', '3']"
  5. expandIconPlacement="right"
  6. :borderless="true"
  7. >
  8. <!-- <t-collapse-panel value="1" header="通信">
  9. <t-space direction="vertical" size="small" class="w-full">
  10. <div class="form-item">
  11. <label title="http地址">http地址 </label>
  12. <t-input
  13. class="w-full"
  14. v-model="props.pen.apiUrl"
  15. @change="changeValue('apiUrl')"
  16. />
  17. </div>
  18. <div class="form-item">
  19. <label title="请求方式">请求方式</label>
  20. <t-select
  21. v-model="props.pen.apiMethod"
  22. @change="changeValue('apiMethod')"
  23. >
  24. <t-option key="GET" value="GET" label="GET" />
  25. <t-option key="POST" value="POST" label="POST" />
  26. </t-select>
  27. </div>
  28. <div class="form-item">
  29. <label title="请求头">请求头</label>
  30. <t-button
  31. class="ml-8"
  32. shape="square"
  33. variant="outline"
  34. style="width: 24px"
  35. @click="preShowPropsEdit('apiHeaders')"
  36. >
  37. <ellipsis-icon slot="icon"/>
  38. </t-button>
  39. </div>
  40. <div class="form-item" v-if="props.pen.apiMethod === 'POST'">
  41. <label title="请求体">请求体</label>
  42. <t-button
  43. class="ml-8"
  44. shape="square"
  45. variant="outline"
  46. style="width: 24px"
  47. @click="preShowPropsEdit('apiBody')"
  48. >
  49. <ellipsis-icon slot="icon"/>
  50. </t-button>
  51. </div>
  52. <div class="form-item">
  53. <label title="开启轮询">开启轮询</label>
  54. <t-switch
  55. class="mt-8 ml-8"
  56. v-model="props.pen.apiEnable"
  57. size="small"
  58. @change="changeValue('apiEnable')"
  59. />
  60. </div>
  61. </t-space>
  62. </t-collapse-panel> -->
  63. <!-- <t-collapse-panel v-if="props.pen.props.custom" value="2" header="属性">
  64. <t-space direction="vertical" size="small" class="w-full">
  65. <div v-for="item in props.pen.props.custom" class="form-item">
  66. <label :title="item.label">{{ item.label }}</label>
  67. <t-checkbox
  68. class="ml-8"
  69. v-if="item.type === 'bool'"
  70. v-model="props.pen[item.key]"
  71. @change="changeValue(item.key)"
  72. />
  73. <t-input-number
  74. class="w-full"
  75. v-else-if="item.type === 'number'"
  76. v-model.number="props.pen[item.key]"
  77. theme="column"
  78. :max="item.max"
  79. :min="item.min"
  80. @change="changeValue(item.key)"
  81. :placeholder="item.placeholder"
  82. :allowInputOverLimit="false"
  83. :decimalPlaces="2"
  84. />
  85. <t-color-picker
  86. class="w-full"
  87. v-else-if="item.type === 'color'"
  88. :enable-alpha="true"
  89. :recent-colors="null"
  90. format="CSS"
  91. :swatch-colors="defaultPureColor"
  92. :color-modes="['monochrome']"
  93. :show-primary-color-preview="false"
  94. v-model="props.pen[item.key]"
  95. @change="changeValue(item.key)"
  96. :placeholder="item.placeholder"
  97. />
  98. <t-select
  99. class="w-full"
  100. v-else-if="item.type === 'select'"
  101. size="small"
  102. :options="item.options"
  103. v-model="props.pen[item.key]"
  104. @change="changeValue(item.key)"
  105. :placeholder="item.placeholder"
  106. />
  107. <t-button
  108. class="ml-8"
  109. v-else-if="item.type === 'code'"
  110. shape="square"
  111. variant="outline"
  112. style="width: 24px"
  113. @click="showDrawer(item)"
  114. >
  115. <ChevronLeftDoubleIcon slot="icon"/>
  116. </t-button>
  117. <t-slider
  118. v-else-if="item.type === 'slider'"
  119. v-model="props.pen[item.key]"
  120. :min="0"
  121. :max="1"
  122. :step="0.01"
  123. @change="changeValue(item.key)"
  124. />
  125. <t-switch
  126. size="small"
  127. class="mt-8 ml-8"
  128. v-else-if="item.type === 'switch'"
  129. v-model="props.pen[item.key]"
  130. @change="changeValue(item.key)"
  131. />
  132. <t-input
  133. class="w-full"
  134. v-else
  135. v-model="props.pen[item.key]"
  136. @change="changeValue(item.key)"
  137. :placeholder="item.placeholder"
  138. />
  139. </div>
  140. </t-space>
  141. </t-collapse-panel> -->
  142. <t-collapse-panel value="3" header="数据">
  143. <div class="form-item" v-if="props.pen.name==='tablePlus'">
  144. <label class="label">数据源</label>
  145. <t-select
  146. v-model="dataSource"
  147. placeholder="请选择"
  148. @change="getDataSource"
  149. >
  150. <t-option key="api" value="api" label="API接口"/>
  151. <t-option key="csv" value="csv" label="CSV文件"/>
  152. <t-option key="excel" value="excel" label="从Excel导入"/>
  153. </t-select>
  154. </div>
  155. <div class="t-space-item" v-if="props.pen.name==='tablePlus'">
  156. <div v-if="cell.row!==undefined" class="flex between form-item py-12">
  157. <div v-if="cell.col!==undefined" style="line-height: 30px">
  158. 当前选中单元格 (第{{ cell.row }}行,第{{ cell.col}}列)
  159. </div>
  160. <div v-else style="line-height: 30px">
  161. 当前选中行 (第{{ cell.row }}行)
  162. </div>
  163. <div>
  164. <t-tooltip content="快捷绑定" placement="top">
  165. <link-icon style="width: 13px;margin-right: 26px"class="hover ml-4" @click="onQuickBind()"/>
  166. </t-tooltip>
  167. </div>
  168. </div>
  169. </div>
  170. <div class="t-space-item">
  171. <div class="form-item py-12">
  172. <label style="width: 76px">关联设备</label>
  173. <t-input
  174. class="w-full"
  175. placeholder="设备ID"
  176. v-model="props.pen.deviceId"
  177. @change="changeValue('deviceId')"
  178. />
  179. </div>
  180. </div>
  181. <div
  182. class="real-times"
  183. v-if="props.pen.realTimes && props.pen.realTimes.length||pen.children?.length"
  184. >
  185. <div class="grid head">
  186. <div class="title">数据名</div>
  187. <div class="title">值</div>
  188. <div class="title" style="text-align: center;">绑定</div>
  189. <div class="title" style="text-align: center;">操作</div>
  190. <!-- <div class="actions">
  191. <more-icon />
  192. </div> -->
  193. </div>
  194. <div class="grid" v-for="(item, i) in props.pen.realTimes">
  195. <t-tooltip :content="item.key" placement="top">
  196. <label class="label">{{ item.label }}</label>
  197. </t-tooltip>
  198. <div class="value">
  199. <t-input
  200. v-if="item.type === 'integer'"
  201. v-model.number="props.pen[item.key]"
  202. placeholder="整数"
  203. @change="changeValue(item.key)"
  204. />
  205. <t-input-number
  206. v-else-if="item.type === 'float'"
  207. v-model="props.pen[item.key]"
  208. placeholder="浮点数"
  209. theme="normal"
  210. @change="changeValue(item.key)"
  211. />
  212. <t-switch
  213. v-else-if="item.type === 'bool'"
  214. v-model="props.pen[item.key]"
  215. class="ml-8"
  216. size="small"
  217. @change="changeValue(item.key)"
  218. />
  219. <t-button
  220. v-else-if="item.type === 'array' || item.type === 'object'"
  221. variant="outline"
  222. style="padding: 0px 2px 0 4px; margin: 0 4px"
  223. @click="editObject(item)"
  224. >
  225. <ellipsis-icon />
  226. <!-- <t-icon name="ellipsis" /> -->
  227. </t-button>
  228. <t-input
  229. v-else
  230. v-model="props.pen[item.key]"
  231. placeholder="字符串"
  232. @change="changeValue(item.key)"
  233. />
  234. </div>
  235. <div style="text-align: center;">
  236. <t-tooltip :content="getBindsDesc(item)" placement="top">
  237. <link-icon class="hover ml-4"
  238. :class="{ primary: item.enableMock || item.bind?.id }"
  239. @click="onBind(item)"/>
  240. </t-tooltip>
  241. </div>
  242. <div style="text-align: center;">
  243. <!-- <t-tooltip :content="item.triggers?.length || '状态'">
  244. <t-badge
  245. :count="item.triggers?.length"
  246. size="small"
  247. dot
  248. :offset="[0, 5]"
  249. >
  250. <relativity-icon class="hover"
  251. @click="onTrigger(item)"/>
  252. </t-badge>
  253. </t-tooltip> -->
  254. <t-dropdown
  255. :options="triggerOptions"
  256. @click="addTrigger(item, $event, i)"
  257. :minColumnWidth="120"
  258. >
  259. <ViewListIcon class="hover"/>
  260. </t-dropdown>
  261. </div>
  262. <!-- <div class="actions">
  263. <t-dropdown
  264. :options="moreOptions"
  265. @click="onMenuMore($event, item, i)"
  266. :minColumnWidth="80"
  267. >
  268. <more-icon class="more hover" />
  269. </t-dropdown>
  270. </div> -->
  271. </div>
  272. <div class="mt-8 pb-16">
  273. <t-dropdown
  274. :options="options"
  275. @click="addRealTime"
  276. :minColumnWidth="150"
  277. >
  278. <a class="ml-12">
  279. <add-rectangle-icon />
  280. <!-- <t-icon name="add-rectangle" /> -->
  281. 添加动态数据
  282. </a>
  283. </t-dropdown>
  284. </div>
  285. </div>
  286. <div class="flex column center blank" v-else>
  287. <img src="/img/blank.png" />
  288. <div class="gray center">还没有动态数据</div>
  289. <div class="mt-8">
  290. <t-dropdown
  291. :options="options"
  292. @click="addRealTime"
  293. :minColumnWidth="150"
  294. >
  295. <t-button style="height: 30px"> 添加动态数据 </t-button>
  296. </t-dropdown>
  297. </div>
  298. </div>
  299. <div v-if="props.pen.children?.length" class="c-titile">
  300. <t-tooltip content="ctrl+shift+点击,可选中子图元">
  301. 子节点数据
  302. </t-tooltip>
  303. </div>
  304. <template v-for="(cPen) in childrenPens">
  305. <div
  306. class="real-times"
  307. >
  308. <t-divider align="left c-head"> {{ cPen.description||cPen.name }}</t-divider>
  309. <div class="grid" v-for="(item, i) in cPen.realTimes">
  310. <t-tooltip :content="item.key" placement="top">
  311. <label class="label">{{ item.label }}</label>
  312. </t-tooltip>
  313. <div class="value">
  314. <t-input
  315. v-if="item.type === 'integer'"
  316. v-model.number="cPen[item.key]"
  317. placeholder="整数"
  318. @change="changeCValue(item.key,cPen)"
  319. />
  320. <t-input-number
  321. v-else-if="item.type === 'float'"
  322. v-model="cPen[item.key]"
  323. placeholder="浮点数"
  324. theme="normal"
  325. @change="changeCValue(item.key,cPen)"
  326. />
  327. <t-switch
  328. v-else-if="item.type === 'bool'"
  329. v-model="cPen[item.key]"
  330. class="ml-8"
  331. size="small"
  332. @change="changeCValue(item.key,cPen)"
  333. />
  334. <t-button
  335. v-else-if="item.type === 'array' || item.type === 'object'"
  336. variant="outline"
  337. style="padding: 0px 2px 0 4px; margin: 0 4px"
  338. @click="editCObject(item,cPen)"
  339. >
  340. <ellipsis-icon />
  341. </t-button>
  342. <t-input
  343. v-else
  344. v-model="cPen[item.key]"
  345. placeholder="字符串"
  346. @change="changeCValue(item.key,cPen)"
  347. />
  348. </div>
  349. <div style="text-align: center;">
  350. <t-tooltip :content="getBindsDesc(item)" placement="top">
  351. <link-icon class="hover ml-4"
  352. :class="{ primary: item.enableMock || item.bind?.id }"
  353. @click="onBind(item)"/>
  354. </t-tooltip>
  355. </div>
  356. <!-- <div>
  357. <t-tooltip :content="item.triggers?.length || '状态'">
  358. <t-badge
  359. :count="item.triggers?.length"
  360. size="small"
  361. dot
  362. :offset="[0, 5]"
  363. >
  364. <relativity-icon class="hover"
  365. @click="onTrigger(item)"/>
  366. </t-badge>
  367. </t-tooltip>
  368. </div> -->
  369. <div class="actions" style="text-align: center;">
  370. <t-dropdown
  371. :options="moreOptions"
  372. @click="onCMenuMore($event, item, i, cPen)"
  373. :minColumnWidth="80"
  374. >
  375. <ViewListIcon class="hover"/>
  376. </t-dropdown>
  377. </div>
  378. </div>
  379. <div class="mt-8 pb-16">
  380. <t-dropdown
  381. :options="options"
  382. @click="addCRealTime($event,cPen)"
  383. :minColumnWidth="150"
  384. >
  385. <a class="ml-12">
  386. <add-rectangle-icon />
  387. 添加动态数据
  388. </a>
  389. </t-dropdown>
  390. </div>
  391. </div>
  392. </template>
  393. </t-collapse-panel>
  394. </t-collapse>
  395. </div>
  396. <!-- <t-drawer
  397. v-model:visible="drawer.visible"
  398. :header="drawer.header"
  399. cancelBtn="关闭"
  400. confirmBtn="运行"
  401. @confirm="onConfirmDrawer"
  402. :closeOnOverlayClick="false"
  403. :sizeDraggable="true"
  404. >
  405. <div style="height:100%">
  406. <CodeEditor
  407. style="height: 100%"
  408. :key="drawer.randomkey"
  409. :json="true"
  410. :language="'json'"
  411. v-model="drawer.value"
  412. />
  413. </div>
  414. <div class="gray" style="font-size: 12px">
  415. {{ drawer.placeholder }}
  416. </div>
  417. </t-drawer> -->
  418. <t-dialog
  419. v-if="addDataDialog.show"
  420. :visible="true"
  421. class="data-dialog"
  422. :header="addDataDialog.header"
  423. @close="addDataDialog.show = false"
  424. @confirm="onConfirmData"
  425. >
  426. <div class="form-item mt-16">
  427. <label>数据名</label>
  428. <t-input
  429. v-model="addDataDialog.data.label"
  430. placeholder="简短描述"
  431. :disabled="!!addDataDialog.data.keywords"
  432. @blur="onChangeLabel"
  433. />
  434. </div>
  435. <div class="form-item mt-16">
  436. <label>属性名</label>
  437. <t-input
  438. v-model="addDataDialog.data.key"
  439. placeholder="关键字"
  440. @blur="onKeyBlur"
  441. :disabled="!!addDataDialog.data.keywords"
  442. />
  443. </div>
  444. <div class="form-item mt-16">
  445. <label>类型</label>
  446. <t-select
  447. class="w-full"
  448. :options="typeOptions"
  449. v-model="addDataDialog.data.type"
  450. placeholder="字符串"
  451. :disabled="!!addDataDialog.data.keywords"
  452. @change="onKeyBlur"
  453. />
  454. </div>
  455. </t-dialog>
  456. <t-dialog
  457. v-if="dataBindDialog.show"
  458. :visible="true"
  459. class="data-link-dialog"
  460. header="动态数据设置"
  461. @close="
  462. dataBindDialog.datasetList = undefined;
  463. dataBindDialog.show = false;
  464. "
  465. @confirm="dataBindonConfirm"
  466. :top="70"
  467. :width="700"
  468. >
  469. <t-tabs :defaultValue="1">
  470. <t-tab-panel
  471. :value="1"
  472. label="绑定变量"
  473. :destroy-on-hide="false"
  474. style="height: 420px"
  475. >
  476. <div class="form-item mt-12">
  477. <label>当前绑定:</label>
  478. <div class="label" v-if="dataBindDialog.data.bind?.id">
  479. <t-tooltip :content="dataBindDialog.data.bind?.id">
  480. <t-tag class="mr-8 mb-8" closable @close="onRemoveBind()">
  481. {{ dataBindDialog.data.bind?.label }}
  482. </t-tag>
  483. </t-tooltip>
  484. </div>
  485. <div class="label gray" v-else>无</div>
  486. </div>
  487. <div class="form-item flex middle mt-8">
  488. <!-- <t-input
  489. v-if="dataBindDialog.url"
  490. v-model="dataBindDialog.device"
  491. placeholder="设备"
  492. style="width: 200px"
  493. />
  494. <t-select
  495. v-else
  496. class="mr-16"
  497. style="width: 200px"
  498. v-model="dataBindDialog.device"
  499. clearable
  500. placeholder="设备"
  501. @change="getDataset"
  502. >
  503. <t-option
  504. v-for="(item, i) in dataBindDialog.devices"
  505. :key="item"
  506. :value="item"
  507. :label="item"
  508. />
  509. </t-select> -->
  510. <t-input
  511. style="width:250px;"
  512. placeholder="搜索"
  513. v-model="dataBindDialog.input"
  514. @change="onSearchDataset"
  515. @enter="onSearchDataset"
  516. >
  517. <template #suffixIcon>
  518. <search-icon class="hover" @click="onSearchDataset"/>
  519. <!-- <t-icon name="search" class="hover" @click="onSearchDataset" /> -->
  520. </template>
  521. </t-input>
  522. </div>
  523. <t-table
  524. class="mt-12 data-list"
  525. row-key="id"
  526. :data="dataBindDialog.dataset"
  527. :columns="dataSetColumns"
  528. size="small"
  529. bordered
  530. rowSelectionAllowUncheck
  531. :loading="dataBindDialog.loading"
  532. :pagination="query"
  533. @page-change="onChangePagination"
  534. :selected-row-keys="dataBindDialog.selectedIds"
  535. @select-change="onSelectBindsChange"
  536. :max-height="270"
  537. >
  538. </t-table>
  539. </t-tab-panel>
  540. <t-tab-panel
  541. :value="2"
  542. label="本地调试"
  543. :destroy-on-hide="false"
  544. style="height: 420px"
  545. >
  546. <div class="form-item mt-20">
  547. <label>模拟值:</label>
  548. <t-input v-model="dataBindDialog.data.mock" />
  549. </div>
  550. <div class="form-item mt-20">
  551. <label>类型:</label>
  552. <t-select
  553. class="w-full"
  554. :options="typeOptions"
  555. v-model="dataBindDialog.data.type"
  556. placeholder="字符串"
  557. />
  558. </div>
  559. <div class="form-item mt-12">
  560. <label>开启:</label>
  561. <t-switch
  562. class="mt-8"
  563. size="small"
  564. v-model="dataBindDialog.data.enableMock"
  565. />
  566. </div>
  567. <h6 class="desc mt-20">模拟值说明</h6>
  568. <ul class="desc mt-4">
  569. <li class="mt-4">
  570. <label class="inline" style="width: 80px">固定值:</label>
  571. 直接填写,例如:10
  572. </li>
  573. <li class="mt-4">
  574. <label class="inline" style="width: 80px">随机值:</label>
  575. 值1,值2,...。例如:1,2,3,4,5
  576. </li>
  577. <li class="mt-4">
  578. <label class="inline" style="width: 80px">范围数字:</label>
  579. 最小值-最大值。例如:0-1.0 或 0-100
  580. </li>
  581. <li class="mt-4">
  582. <label class="inline" style="width: 80px">随机字符串:</label>
  583. [长度]。例如:[8]
  584. </li>
  585. </ul>
  586. </t-tab-panel>
  587. </t-tabs>
  588. </t-dialog>
  589. <t-dialog
  590. v-if="triggersDialog.show"
  591. :visible="true"
  592. class="data-events-dialog"
  593. header="数据状态"
  594. @confirm="triggersDialog.show = false"
  595. @close="triggersDialog.show = false"
  596. :width="700"
  597. >
  598. <div class="body">
  599. <t-collapse
  600. v-model="triggersDialog.openedCollapses"
  601. :borderless="true"
  602. :expand-on-row-click="false"
  603. >
  604. <t-collapse-panel
  605. v-for="(trigger, i) in triggersDialog.data.triggers"
  606. :value="i"
  607. >
  608. <template #header>
  609. <t-input v-model="trigger.name" class="mr-12" />
  610. </template>
  611. <template #headerRightContent>
  612. <t-popconfirm
  613. content="确认删除该状态吗?"
  614. @confirm="triggersDialog.data.triggers.splice(i, 1)"
  615. >
  616. <delete-icon class="hover"/>
  617. <!-- <t-icon name="delete" class="hover" /> -->
  618. </t-popconfirm>
  619. </template>
  620. <section>
  621. <div class="form-item banner">
  622. <label>满足条件</label>
  623. <div class="w-full flex middle between">
  624. <div></div>
  625. <t-radio-group v-model="trigger.conditionType">
  626. <t-radio value="and"> 所有 </t-radio>
  627. <t-radio value="or"> 任意 </t-radio>
  628. </t-radio-group>
  629. </div>
  630. </div>
  631. <div v-for="(c, index) in trigger.conditions" class="mb-12">
  632. <div class="flex middle between head">
  633. <div class="flex middle">
  634. <arrow-right-icon class="mr-4"/>
  635. <!-- <t-icon name="arrow-right" class="mr-4" /> -->
  636. 条件{{ index + 1 }}
  637. </div>
  638. <close-icon class="hover"
  639. @click="trigger.conditions.splice(index, 1)"/>
  640. <!-- <t-icon
  641. name="close"
  642. class="hover"
  643. @click="trigger.conditions.splice(index, 1)"
  644. /> -->
  645. </div>
  646. <div class="px-16 py-4">
  647. <div class="form-item mt-4">
  648. <label>条件类型</label>
  649. <t-radio-group v-model="c.type">
  650. <t-radio value=""> 关系条件 </t-radio>
  651. <t-radio value="fn"> 高级条件 </t-radio>
  652. </t-radio-group>
  653. </div>
  654. <template v-if="!c.type">
  655. <div class="form-item mt-8">
  656. <label>比较条件</label>
  657. <div class="flex middle">
  658. <label class="shrink-0 mr-8">数据</label>
  659. <t-select
  660. v-model="c.operator"
  661. placeholder="关系运算"
  662. :options="operatorOptions"
  663. class="shrink-0 mr-8"
  664. style="width: 80px"
  665. />
  666. <t-select
  667. v-model="c.valueType"
  668. class="shrink-0 mr-8"
  669. style="width: 110px"
  670. placeholder="固定值"
  671. >
  672. <t-option key="" value="" label="固定值">
  673. 固定值
  674. </t-option>
  675. <t-option key="prop" value="prop" label="对象属性值">
  676. 对象属性值
  677. </t-option>
  678. </t-select>
  679. <template v-if="!c.valueType">
  680. <t-input
  681. @change="valueChange($event,c)"
  682. v-model="c.value"
  683. class="shrink-0"
  684. style="width: 320px"
  685. />
  686. </template>
  687. <template v-else>
  688. <t-tree-select
  689. v-model="c.target"
  690. :data="penTree"
  691. filterable
  692. placeholder="对象"
  693. class="shrink-0 mr-8"
  694. style="width: 160px"
  695. @change="onChangeTriggerTarget(c)"
  696. />
  697. <t-select-input
  698. v-model:inputValue="c.value"
  699. :value="c.label"
  700. v-model:popupVisible="c.popupVisible"
  701. allow-input
  702. clearable
  703. @clear="c.label = undefined"
  704. @focus="c.popupVisible = true"
  705. @blur="c.popupVisible = false"
  706. @input-change="onInput(c)"
  707. class="shrink-0"
  708. style="width: 152px"
  709. >
  710. <template #panel>
  711. <ul style="padding: 8px 12px">
  712. <li
  713. v-for="item in cProps"
  714. :key="item.value"
  715. @click="
  716. c.value = item.value;
  717. c.label = item.label;
  718. c.popupVisible = false;
  719. "
  720. >
  721. {{ item.label }}
  722. </li>
  723. </ul>
  724. </template>
  725. </t-select-input>
  726. </template>
  727. </div>
  728. </div>
  729. </template>
  730. <template v-else>
  731. <div>function condition(pen) {</div>
  732. <CodeEditor class="mt-4" @change="codeChange($event,c)" v-model="c.fnJs" />
  733. <div class="mt-4">}</div>
  734. </template>
  735. </div>
  736. </div>
  737. <div class="mt-8">
  738. <a @click="addTriggerCondition(trigger)"> + 添加条件 </a>
  739. </div>
  740. <div class="form-item banner mt-16">
  741. <label>执行动作</label>
  742. </div>
  743. <Actions class="mt-8" :data="trigger" />
  744. </section>
  745. </t-collapse-panel>
  746. </t-collapse>
  747. <div class="mt-8">
  748. <!-- <a @click="onAddTrigger"> + 添加状态 </a> -->
  749. <t-button @click="onAddTrigger" style="width: 100%;" variant="outline">
  750. <template #icon><add-icon /></template>
  751. 添加状态
  752. </t-button>
  753. </div>
  754. </div>
  755. </t-dialog>
  756. <t-dialog
  757. v-if="ojbectDialog.show"
  758. :visible="true"
  759. header="数据编辑"
  760. @confirm="onOkEditOjbect"
  761. @close="ojbectDialog.show = false"
  762. :width="700"
  763. >
  764. <div class="py-8">
  765. <CodeEditor
  766. :json="true"
  767. v-model="ojbectDialog.data"
  768. style="height: 300px"
  769. />
  770. </div>
  771. </t-dialog>
  772. <t-dialog
  773. v-if="propsDialog.show"
  774. :visible="true"
  775. :header="propsDialog.header"
  776. @confirm="onOkPropsEdit"
  777. @close="propsDialog.show = false"
  778. :width="700"
  779. >
  780. <div class="py-8">
  781. <CodeEditor
  782. :json="true"
  783. :language="'json'"
  784. v-model="propsDialog.value"
  785. style="height: 300px"
  786. />
  787. </div>
  788. <div class="gray" style="font-size: 12px">
  789. {{ propsDialog.placeholder }}
  790. </div>
  791. </t-dialog>
  792. <t-dialog
  793. v-if="apiDialog.show"
  794. :visible="true"
  795. class="data-dialog"
  796. header="API接口"
  797. @close="apiDialog.show = false"
  798. @confirm="onConfirmAPI"
  799. >
  800. <div class="form-item mt-8">
  801. <label>http地址</label>
  802. <t-input
  803. placeholder="请输入(临时请求,不会保存)"
  804. v-model="apiDialog.url"
  805. />
  806. </div>
  807. <div class="form-item mt-8">
  808. <label>请求方式</label>
  809. <t-select v-model="apiDialog.method">
  810. <t-option key="GET" value="GET" label="GET" />
  811. <t-option key="POST" value="POST" label="POST" />
  812. </t-select>
  813. </div>
  814. <div class="form-item mt-8">
  815. <label>请求头</label>
  816. <CodeEditor
  817. :json="true"
  818. :language="'json'"
  819. v-model="apiDialog.headers"
  820. class="mt-4"
  821. style="height: 50px"
  822. />
  823. </div>
  824. <div v-if="apiDialog.method === 'POST'" class="form-item mt-8">
  825. <label>请求体</label>
  826. <CodeEditor
  827. :json="true"
  828. :language="'json'"
  829. v-model="apiDialog.body"
  830. class="mt-4"
  831. style="height: 50px"
  832. />
  833. </div>
  834. </t-dialog>
  835. </template>
  836. <script lang="ts" setup>
  837. import {
  838. getCurrentInstance,
  839. onBeforeMount,
  840. onUnmounted,
  841. reactive,
  842. ref,
  843. toRaw,
  844. watch,
  845. onMounted,
  846. computed
  847. } from 'vue';
  848. import { useRoute, useRouter } from 'vue-router';
  849. import { MessagePlugin } from 'tdesign-vue-next';
  850. import axios from 'axios';
  851. import { debounce } from '@/services/debouce';
  852. import { getPenTree, typeOptions, changeType } from '@/services/common';
  853. import { searchPinyin } from '@/services/pinyin';
  854. import { updatePen } from './pen';
  855. import { getter, setter, queryURLParams, deepClone, getAllChildren, Pen } from '@meta2d/core';
  856. import CodeEditor from '@/views/components/common/CodeEditor.vue';
  857. import Actions from './Actions.vue';
  858. import { useSelection } from '@/services/selections';
  859. import { defaultGradientColor, defaultPureColor } from '@/services/defaults';
  860. import { getLe5le3d, getLe5leV, getLe5le2d } from '@/services/api';
  861. import { EllipsisIcon, MoreIcon, LinkIcon, RelativityIcon, AddRectangleIcon, SearchIcon ,DeleteIcon, ArrowRightIcon, CloseIcon, ChevronLeftDoubleIcon, AddIcon, ViewListIcon } from 'tdesign-icons-vue-next';
  862. import { s8 } from '@/services/random';
  863. import { importExcel } from '@/services/excel';
  864. import { importCSV } from '@/services/file';
  865. const route = useRoute();
  866. const router = useRouter();
  867. const {
  868. proxy: { $forceUpdate },
  869. }: any = getCurrentInstance();
  870. const props = defineProps<{
  871. pen: any;
  872. }>();
  873. const options = ref<any>([
  874. {
  875. value: '',
  876. content: '自定义',
  877. divider: true,
  878. },
  879. {
  880. value: 'x',
  881. content: 'X',
  882. type: 'float',
  883. keywords: true,
  884. },
  885. {
  886. value: 'y',
  887. content: 'Y',
  888. type: 'float',
  889. keywords: true,
  890. },
  891. {
  892. value: 'width',
  893. content: '宽',
  894. type: 'float',
  895. keywords: true,
  896. },
  897. {
  898. value: 'height',
  899. content: '高',
  900. type: 'float',
  901. keywords: true,
  902. },
  903. {
  904. value: 'visible',
  905. content: '显示',
  906. type: 'bool',
  907. keywords: true,
  908. },
  909. {
  910. value: 'text',
  911. content: '文字',
  912. // keywords: true,
  913. },
  914. {
  915. value: 'progress',
  916. content: '进度',
  917. type: 'float',
  918. keywords: true,
  919. },
  920. {
  921. value: 'showChild',
  922. content: '状态',
  923. type: 'integer',
  924. keywords: true,
  925. },
  926. {
  927. value: 'rotate',
  928. content: '旋转',
  929. type: 'integer',
  930. keywords: true,
  931. },
  932. ]);
  933. const moreOptions = ref<any>([
  934. {
  935. value: 'view',
  936. content: '查看状态',
  937. },
  938. {
  939. value: 'custom',
  940. content: '自定义状态',
  941. divider: true
  942. },
  943. {
  944. value: 'edit',
  945. content: '编辑',
  946. },
  947. {
  948. value: 'delete',
  949. content: '移除',
  950. },
  951. ]);
  952. const addDataDialog = reactive<any>({
  953. show: false,
  954. data: undefined,
  955. });
  956. const dataBindDialog = reactive<any>({
  957. show: false,
  958. data: undefined,
  959. });
  960. const ojbectDialog = reactive<any>({
  961. show: false,
  962. data: undefined,
  963. });
  964. const dataSetColumns = [
  965. {
  966. colKey: 'row-select',
  967. type: 'single',
  968. width: 50,
  969. },
  970. // {
  971. // colKey: 'device',
  972. // title: '设备',
  973. // ellipsis: { theme: 'light', trigger: 'context-menu' },
  974. // },
  975. {
  976. colKey: 'label',
  977. title: '显示名称',
  978. ellipsis: { theme: 'light', trigger: 'context-menu' },
  979. },
  980. {
  981. colKey: 'id',
  982. title: '变量名',
  983. ellipsis: { theme: 'light', trigger: 'context-menu' },
  984. },
  985. {
  986. colKey: 'type',
  987. title: '类型',
  988. width: 100,
  989. },
  990. {
  991. colKey: 'mock',
  992. title: '值范围',
  993. ellipsis: true,
  994. },
  995. ];
  996. const operatorOptions = ref<any>([
  997. { label: '=', value: '=' },
  998. { label: '!=', value: '!=' },
  999. { label: '>', value: '>' },
  1000. { label: '<', value: '<' },
  1001. { label: '>=', value: '>=' },
  1002. { label: '<=', value: '<=' },
  1003. { label: '包含', value: '[)' },
  1004. { label: '不包含', value: '![)' },
  1005. ]);
  1006. const cProps = [
  1007. {
  1008. value: 'x',
  1009. label: 'X',
  1010. },
  1011. {
  1012. value: 'y',
  1013. label: 'Y',
  1014. },
  1015. {
  1016. value: 'width',
  1017. label: '宽',
  1018. },
  1019. {
  1020. value: 'height',
  1021. label: '高',
  1022. },
  1023. {
  1024. value: 'visible',
  1025. label: '显示',
  1026. },
  1027. {
  1028. value: 'text',
  1029. label: '文字',
  1030. },
  1031. {
  1032. value: 'color',
  1033. label: '颜色',
  1034. },
  1035. {
  1036. value: 'background',
  1037. label: '背景颜色',
  1038. },
  1039. {
  1040. value: 'progress',
  1041. label: '进度',
  1042. },
  1043. {
  1044. value: 'progressColor',
  1045. label: '进度颜色',
  1046. },
  1047. {
  1048. value: 'showChild',
  1049. label: '状态',
  1050. },
  1051. {
  1052. value: 'rotate',
  1053. label: '旋转',
  1054. },
  1055. {
  1056. value: 'disabled',
  1057. label: '禁用',
  1058. },
  1059. {
  1060. value: 'selectedKey',
  1061. label: '单选选中值',
  1062. }
  1063. ];
  1064. const query = reactive<{
  1065. current: number;
  1066. pageSize: number;
  1067. total: number;
  1068. range: any[];
  1069. }>({
  1070. current: 1,
  1071. pageSize: 10,
  1072. total: 0,
  1073. range: [],
  1074. });
  1075. const triggersDialog = reactive<any>({
  1076. show: false,
  1077. data: undefined,
  1078. });
  1079. const penTree: any = ref([]);
  1080. let timer: any;
  1081. onBeforeMount(() => {
  1082. // realTimesOptions - 扩展的动态数据下拉列表
  1083. if (props.pen.realTimesOptions) {
  1084. options.value[options.value.length - 1].divider = true;
  1085. options.value.push(...props.pen.realTimesOptions);
  1086. }
  1087. timer = setInterval($forceUpdate, 1000);
  1088. });
  1089. const addRealTime = (e: any) => {
  1090. if (e.keywords || e.value === 'text') {
  1091. if (!props.pen.realTimes) {
  1092. props.pen.realTimes = [];
  1093. }
  1094. props.pen.realTimes.push({
  1095. label: e.content,
  1096. key: e.value,
  1097. type: e.type,
  1098. keywords: e.keywords,
  1099. });
  1100. return;
  1101. }
  1102. addDataDialog.header = '添加动态数据';
  1103. addDataDialog.data = {
  1104. label: e.content,
  1105. key: e.value,
  1106. type: e.type,
  1107. keywords: e.keywords,
  1108. };
  1109. addDataDialog.data.pen = undefined;
  1110. if (e.keywords) {
  1111. addDataDialog.data.label = '';
  1112. }
  1113. addDataDialog.show = true;
  1114. };
  1115. const onKeyBlur = () => {
  1116. if (addDataDialog.data) {
  1117. let value = getter(props.pen, addDataDialog.data.key);
  1118. if (value) {
  1119. setter(addDataDialog.data, 'value', value);
  1120. } else {
  1121. addDataDialog.data.value = null;
  1122. }
  1123. }
  1124. };
  1125. const onChangeLabel = () => {
  1126. if (!addDataDialog.data.key) {
  1127. addDataDialog.data.key = addDataDialog.data.label;
  1128. }
  1129. };
  1130. const onConfirmData = () => {
  1131. const pen = addDataDialog.data.pen || props.pen;
  1132. if (!pen.realTimes) {
  1133. pen.realTimes = [];
  1134. }
  1135. if (!addDataDialog.data.label || !addDataDialog.data.key) {
  1136. MessagePlugin.error('数据名或属性名不能为空!');
  1137. return;
  1138. }
  1139. delete addDataDialog.data.pen;
  1140. if (addDataDialog.header === '添加动态数据') {
  1141. const found = pen.realTimes.findIndex((item: any) => {
  1142. return item.key === addDataDialog.data.key;
  1143. });
  1144. if (found > -1) {
  1145. MessagePlugin.error('已经存在相同属性数据!');
  1146. return;
  1147. }
  1148. if(pen[addDataDialog.data.key] === undefined && addDataDialog.data.key.indexOf('.') !== -1){
  1149. pen[addDataDialog.data.key] = getter(pen, addDataDialog.data.key);
  1150. }
  1151. pen.realTimes.push(addDataDialog.data);
  1152. }
  1153. addDataDialog.show = false;
  1154. };
  1155. const onMenuMore = (e: any, item: any, i: number) => {
  1156. switch (e.value) {
  1157. case 'edit':
  1158. addDataDialog.header = '编辑动态数据';
  1159. setter(item, 'value', getter(props.pen, item.key));
  1160. addDataDialog.data = item;
  1161. addDataDialog.show = true;
  1162. break;
  1163. case 'delete':
  1164. props.pen.realTimes.splice(i, 1);
  1165. meta2d.initBinds();
  1166. break;
  1167. default:
  1168. break;
  1169. }
  1170. };
  1171. const onBind = (item: any) => {
  1172. dataBindDialog.data = item;
  1173. dataBindDialog.input = '';
  1174. dataBindDialog.selectedIds = [];
  1175. if (item.bind && item.bind.id) {
  1176. dataBindDialog.selectedIds.push(item.bind.id);
  1177. }
  1178. dataBindDialog.show = true;
  1179. getDataset();
  1180. };
  1181. const onSearchDataset = () => {
  1182. debounce(getDataset, 300);
  1183. };
  1184. const getDataset = async () => {
  1185. // @ts-ignore
  1186. const data: Meta2dBackData = meta2d.data();
  1187. if (!data.dataset) {
  1188. return;
  1189. }
  1190. dataBindDialog.dataset = data.dataset.devices;
  1191. dataBindDialog.datasetList = data.dataset.devices;
  1192. if(dataBindDialog.device || dataBindDialog.input){
  1193. dataBindDialog.dataset = dataBindDialog.datasetList.filter(
  1194. (item: any) => {
  1195. if (dataBindDialog.device && item.device !== dataBindDialog.device) {
  1196. return;
  1197. }
  1198. return (
  1199. searchPinyin(item.label, dataBindDialog.input) ||
  1200. item.id.indexOf(dataBindDialog.input) > -1
  1201. );
  1202. }
  1203. );
  1204. }
  1205. query.total = dataBindDialog.dataset.length;
  1206. return;
  1207. dataBindDialog.loading = true;
  1208. if (data.dataset.url) {
  1209. const ret: any = await axios.get(data.dataset.url, {
  1210. params: {
  1211. device: dataBindDialog.device || '',
  1212. q: dataBindDialog.input,
  1213. current: query.current,
  1214. pageSize: query.pageSize,
  1215. },
  1216. });
  1217. dataBindDialog.dataset = ret;
  1218. dataBindDialog.url = true;
  1219. query.total = ret.total;
  1220. console.log( dataBindDialog.dataset,
  1221. query.total);
  1222. } else {
  1223. dataBindDialog.url = false;
  1224. if (!dataBindDialog.datasetList) {
  1225. const ret:any = await axios.post(`/api/data/datasource/get`, {
  1226. id: data.dataset.id,
  1227. });
  1228. if (ret?.data?.devices) {
  1229. data.dataset.data = ret.data.devices;
  1230. dataBindDialog.datasetList = data.dataset.data;
  1231. const set = new Set<string>();
  1232. for (const item of dataBindDialog.datasetList) {
  1233. set.add(item.device);
  1234. }
  1235. dataBindDialog.devices = Array.from(set);
  1236. } else {
  1237. dataBindDialog.dataset = [];
  1238. dataBindDialog.devices = [];
  1239. return;
  1240. }
  1241. }
  1242. if (dataBindDialog.device || dataBindDialog.input) {
  1243. dataBindDialog.dataset = dataBindDialog.datasetList.filter(
  1244. (item: any) => {
  1245. if (dataBindDialog.device && item.device !== dataBindDialog.device) {
  1246. return;
  1247. }
  1248. return (
  1249. searchPinyin(item.label, dataBindDialog.input) ||
  1250. item.id.indexOf(dataBindDialog.input) > -1
  1251. );
  1252. }
  1253. );
  1254. query.total = dataBindDialog.datasetList.length;
  1255. } else {
  1256. dataBindDialog.dataset = [...dataBindDialog.datasetList];
  1257. query.total = dataBindDialog.datasetList.length;
  1258. }
  1259. console.log("dataBindDialog",dataBindDialog,dataBindDialog);
  1260. }
  1261. dataBindDialog.loading = false;
  1262. };
  1263. const onChangePagination = (pageInfo: any) => {
  1264. // router.push({
  1265. // path: route.path,
  1266. // query: { current: pageInfo.current, pageSize: pageInfo.pageSize },
  1267. // });
  1268. query.current = pageInfo.current;
  1269. query.pageSize = pageInfo.pageSize;
  1270. getDataset();
  1271. };
  1272. const onSelectBindsChange = (value: string[], options: any) => {
  1273. if (options.type === 'check') {
  1274. dataBindDialog.selectedIds = value;
  1275. dataBindDialog.data.bind = toRaw(options.selectedRowData[0]);
  1276. if(dataBindDialog.data.bind.id){
  1277. dataBindDialog.data.enableMock = false;
  1278. }
  1279. dataBindDialog.data.mock = dataBindDialog.data.bind.mock;
  1280. dataBindDialog.data.type = dataBindDialog.data.bind.type;
  1281. doBindInit();
  1282. } else if (options.type === 'uncheck') {
  1283. dataBindDialog.selectedIds = [];
  1284. dataBindDialog.data.bind = {};
  1285. }
  1286. };
  1287. const doBindInit = () => {
  1288. let { id } = dataBindDialog.data;
  1289. if (props.pen.name === 'echarts' && id?.includes('echarts.option.series')) {
  1290. const { replaceMode } = props.pen.echarts;
  1291. const { xAxis } = props.pen.echarts.option;
  1292. let beforeV = getter(props.pen, id);
  1293. if (Array.isArray(beforeV) && replaceMode === 0) {
  1294. //追加
  1295. setter(props.pen, id, []);
  1296. let _key = 'echarts.option.xAxis.data';
  1297. if (Array.isArray(xAxis) && xAxis.length) {
  1298. _key = 'echarts.option.xAxis.0.data';
  1299. }
  1300. setter(props.pen, _key, []);
  1301. }
  1302. }
  1303. };
  1304. const dataBindonConfirm = () => {
  1305. dataBindDialog.show = false;
  1306. dataBindDialog.datasetList = undefined;
  1307. meta2d.initBinds();
  1308. };
  1309. const onRemoveBind = () => {
  1310. dataBindDialog.selectedIds = [];
  1311. dataBindDialog.data.bind = undefined;
  1312. };
  1313. const getBindsDesc = (item: any) => {
  1314. if (item.bind?.label) {
  1315. return item.bind.label;
  1316. }
  1317. if (item.enableMock && item.mock) {
  1318. return item.mock;
  1319. }
  1320. return '绑定变量';
  1321. };
  1322. const { selections } = useSelection();
  1323. const changeValue = (prop: string) => {
  1324. updatePen(props.pen, prop);
  1325. selections.pen[prop] = getter(props.pen, prop);
  1326. if (prop === 'iframe') {
  1327. getThumbImg();
  1328. }
  1329. if(prop === 'apiEnable'){
  1330. meta2d.penNetwork(props.pen);
  1331. meta2d.connectNetwork();
  1332. }
  1333. };
  1334. const onTrigger = (item: any) => {
  1335. if (!item.triggers) {
  1336. item.triggers = [];
  1337. }
  1338. triggersDialog.openedCollapses = [0];
  1339. triggersDialog.data = item;
  1340. triggersDialog.show = true;
  1341. penTree.value = getPenTree();
  1342. };
  1343. const onAddTrigger = () => {
  1344. const i = triggersDialog.data.triggers.length;
  1345. triggersDialog.data.triggers.push({
  1346. name: `状态${i + 1}`,
  1347. conditionType: 'and',
  1348. conditions: [],
  1349. actions: [],
  1350. });
  1351. triggersDialog.openedCollapses.push(i);
  1352. };
  1353. const addTriggerCondition = (trigger: any) => {
  1354. trigger.conditions.push({
  1355. type: '',
  1356. operator: '=',
  1357. valueType: '',
  1358. });
  1359. };
  1360. const onChangeTriggerTarget = (c: any) => {
  1361. /*
  1362. c.targetProps = [
  1363. {
  1364. value: 'x',
  1365. label: 'X',
  1366. },
  1367. {
  1368. value: 'y',
  1369. label: 'Y',
  1370. },
  1371. {
  1372. value: 'width',
  1373. label: '宽',
  1374. },
  1375. {
  1376. value: 'height',
  1377. label: '高',
  1378. },
  1379. {
  1380. value: 'visible',
  1381. label: '显示',
  1382. },
  1383. {
  1384. value: 'text',
  1385. label: '文字',
  1386. },
  1387. {
  1388. value: 'progress',
  1389. label: '进度',
  1390. },
  1391. {
  1392. value: 'showChild',
  1393. label: '状态',
  1394. },
  1395. {
  1396. value: 'rotate',
  1397. label: '旋转',
  1398. },
  1399. ];*/
  1400. const target: any = meta2d.findOne(c.target);
  1401. if (target && target.realTimes) {
  1402. for (const item of target.realTimes) {
  1403. const found = cProps.findIndex((elem: any) => elem.value === item.key);
  1404. if (found < 0) {
  1405. cProps.push({
  1406. value: item.key,
  1407. label: item.label,
  1408. });
  1409. }
  1410. }
  1411. }
  1412. };
  1413. const onInput = (item: any) => {
  1414. item.label = item.value;
  1415. };
  1416. const editObject = (item: any) => {
  1417. ojbectDialog.data = props.pen[item.key];
  1418. ojbectDialog.item = item;
  1419. ojbectDialog.pen = undefined;
  1420. ojbectDialog.show = true;
  1421. };
  1422. const onOkEditOjbect = () => {
  1423. if (ojbectDialog.data) {
  1424. if (
  1425. ojbectDialog.item.type === 'array' &&
  1426. !Array.isArray(ojbectDialog.data)
  1427. ) {
  1428. MessagePlugin.error('请输入数组格式数据');
  1429. return;
  1430. }
  1431. const pen = ojbectDialog.pen || props.pen;
  1432. pen[ojbectDialog.item.key] = deepClone(ojbectDialog.data);
  1433. updatePen(
  1434. pen,
  1435. ojbectDialog.item.key
  1436. );
  1437. ojbectDialog.show = false;
  1438. } else {
  1439. MessagePlugin.error('请输入严格的JSON格式数据');
  1440. }
  1441. };
  1442. const propsDialog = reactive<any>({
  1443. show: false,
  1444. });
  1445. // const changeValue = (prop: string) => {
  1446. // updatePen(props.pen, prop);
  1447. // selections.pen[prop] = getter(props.pen, prop);
  1448. // if (prop === 'iframe') {
  1449. // getThumbImg();
  1450. // }
  1451. // };
  1452. const getThumbImg = async () => {
  1453. //改iframe地址后
  1454. let arr = props.pen.iframe.split('?');
  1455. let id = queryURLParams(arr[1]).id;
  1456. if (!id) {
  1457. return;
  1458. }
  1459. // let projection = {
  1460. // image: 1,
  1461. // _id: 1,
  1462. // name: 1,
  1463. // };
  1464. let projection = 'image,id,name';
  1465. let res: any;
  1466. if (arr[0].indexOf('2d.le5le') !== -1||arr[0].indexOf('le5le.com/2d') !== -1) {
  1467. res = await getLe5le2d(id, projection);
  1468. } else if (arr[0].indexOf('v.le5le') !== -1||arr[0].indexOf('le5le.com/v') !== -1) {
  1469. res = await getLe5leV(id, projection);
  1470. } else if (arr[0].indexOf('3d.le5le') !== -1||arr[0].indexOf('le5le.com/3d') !== -1) {
  1471. res = await getLe5le3d(id, projection);
  1472. }
  1473. if (res) {
  1474. props.pen.thumbImg = res.image;
  1475. props.pen.calculative&&(props.pen.calculative.img = null);
  1476. }
  1477. props.pen.onRenderPenRaw?.(props.pen);
  1478. };
  1479. const preShowPropsEdit = (key: string) => {
  1480. showPropsEdit({
  1481. key,
  1482. // item: {
  1483. // key,
  1484. type: 'code',
  1485. label: key,
  1486. placeholder: '支持设置动态参数,例如:{"Authorization": "Bearer ${token}"}',
  1487. // },
  1488. });
  1489. };
  1490. const showPropsEdit = (item: any) => {
  1491. propsDialog.key = item.key;
  1492. propsDialog.header = `${item.label}(${item.key})`;
  1493. propsDialog.value = props.pen[item.key];
  1494. propsDialog.placeholder = item.placeholder;
  1495. propsDialog.show = true;
  1496. };
  1497. const onOkPropsEdit = () => {
  1498. if (!propsDialog.value) {
  1499. MessagePlugin.error('数据不满足json格式');
  1500. return;
  1501. }
  1502. props.pen[propsDialog.key] = propsDialog.value;
  1503. updatePen(props.pen, propsDialog.key);
  1504. propsDialog.show = false;
  1505. };
  1506. const codeChange = (e:any,a:any)=>{
  1507. a.fn = null;
  1508. }
  1509. const valueChange = (e,c:any)=>{
  1510. c.value= changeType(e);
  1511. }
  1512. const drawer = reactive<any>({
  1513. visible: false,
  1514. });
  1515. const showDrawer = (item:any)=>{
  1516. drawer.key = item.key;
  1517. drawer.header = `${item.label}(${item.key})`;
  1518. drawer.value = deepClone(props.pen[item.key]);
  1519. drawer.placeholder = item.placeholder;
  1520. drawer.randomkey = s8();//props.pen.id;
  1521. drawer.visible = true;
  1522. }
  1523. const onConfirmDrawer = () => {
  1524. if (!drawer.value) {
  1525. MessagePlugin.error('数据不满足json格式');
  1526. return;
  1527. }
  1528. props.pen[drawer.key] = drawer.value;
  1529. updatePen(props.pen, drawer.key);
  1530. };
  1531. const childrenPens = ref([]);
  1532. watch(
  1533. () => props.pen.id,
  1534. (newValue) => {
  1535. childrenPens.value = [];
  1536. // childrenKey.value = s8();
  1537. if(props.pen.children?.length){
  1538. childrenPens.value = getAllChildren(meta2d.store.pens[props.pen.id],meta2d.store);
  1539. }
  1540. }
  1541. );
  1542. onMounted(() => {
  1543. childrenPens.value = [];
  1544. if(props.pen.children?.length){
  1545. childrenPens.value = getAllChildren(meta2d.store.pens[props.pen.id],meta2d.store);
  1546. }
  1547. });
  1548. const changeCValue = (prop: string, pen:Pen)=>{
  1549. updatePen(pen, prop);
  1550. selections.pen[prop] = getter(pen, prop);
  1551. if (prop === 'iframe') {
  1552. getThumbImg();
  1553. }
  1554. if(prop === 'apiEnable'){
  1555. meta2d.penNetwork(pen);
  1556. meta2d.connectNetwork();
  1557. }
  1558. }
  1559. const editCObject = (item: any, pen:Pen) => {
  1560. ojbectDialog.data = pen[item.key];
  1561. ojbectDialog.pen = pen;
  1562. ojbectDialog.item = item;
  1563. ojbectDialog.show = true;
  1564. };
  1565. const addCRealTime = (e: any, pen:Pen) => {
  1566. if (e.keywords || e.value === 'text') {
  1567. if (!pen.realTimes) {
  1568. pen.realTimes = [];
  1569. }
  1570. pen.realTimes.push({
  1571. label: e.content,
  1572. key: e.value,
  1573. type: e.type,
  1574. keywords: e.keywords,
  1575. });
  1576. return;
  1577. }
  1578. addDataDialog.header = '添加动态数据';
  1579. addDataDialog.data = {
  1580. label: e.content,
  1581. key: e.value,
  1582. type: e.type,
  1583. keywords: e.keywords,
  1584. };
  1585. addDataDialog.data.pen = pen;
  1586. if (e.keywords) {
  1587. addDataDialog.data.label = '';
  1588. }
  1589. addDataDialog.show = true;
  1590. };
  1591. const onCMenuMore = (e: any, item: any, i: number, pen:any)=>{
  1592. switch (e.value) {
  1593. case 'edit':
  1594. addDataDialog.header = '编辑动态数据';
  1595. setter(item, 'value', getter(pen, item.key));
  1596. addDataDialog.data = item;
  1597. addDataDialog.data.pen = pen;
  1598. addDataDialog.show = true;
  1599. break;
  1600. case 'delete':
  1601. pen.realTimes.splice(i, 1);
  1602. meta2d.initBinds();
  1603. break;
  1604. case 'custom':
  1605. if(!pen.triggers){
  1606. pen.triggers = [];
  1607. }
  1608. pen.triggers.push({
  1609. name: `状态场景${pen.triggers.length + 1}`,
  1610. status:[
  1611. {
  1612. name:'状态1',
  1613. conditionType: 'and',
  1614. conditions: [{
  1615. type:'',
  1616. operator: "=",
  1617. key: item.key,//"text",
  1618. keyLabel: item.label,
  1619. value: undefined
  1620. }],
  1621. actions: [],
  1622. },
  1623. {
  1624. name:'状态2',
  1625. conditionType: 'and',
  1626. conditions: [],
  1627. actions: [],
  1628. }
  1629. ],
  1630. });
  1631. meta2d.active(meta2d.find(pen.id));
  1632. emit('tabchange',pen.triggers.length-1);
  1633. break;
  1634. case 'view':
  1635. meta2d.active(meta2d.find(pen.id));
  1636. emit('tabchange',-1);
  1637. default:
  1638. break;
  1639. }
  1640. }
  1641. const emit = defineEmits(['tabchange']);
  1642. const triggerOptions = computed(() => {
  1643. const options = [
  1644. {
  1645. value: 'custom',
  1646. content: '自定义状态',
  1647. divider: true
  1648. },
  1649. {
  1650. value: 'warning',
  1651. content: '条件告警',
  1652. },
  1653. {
  1654. value: 'warningAnimate',
  1655. content: '条件动画',
  1656. divider: true
  1657. },
  1658. {
  1659. value: 'edit',
  1660. content: '编辑',
  1661. },
  1662. {
  1663. value: 'delete',
  1664. content: '移除',
  1665. },
  1666. ]
  1667. if( props.pen.name === "combine"&& props.pen.showChild !== undefined){
  1668. options.splice(1,0,
  1669. {
  1670. value: 'switch',
  1671. content: '状态切换',
  1672. });
  1673. }
  1674. return options
  1675. });
  1676. const addTrigger = (item:any, e:any, i:any) => {
  1677. if(!['edit', 'delete'].includes(e.value)){
  1678. if(!props.pen.triggers){
  1679. props.pen.triggers = [];
  1680. }
  1681. }
  1682. switch (e.value) {
  1683. case 'edit':
  1684. addDataDialog.header = '编辑动态数据';
  1685. setter(item, 'value', getter(props.pen, item.key));
  1686. addDataDialog.data = item;
  1687. addDataDialog.show = true;
  1688. break;
  1689. case 'delete':
  1690. props.pen.realTimes.splice(i, 1);
  1691. meta2d.initBinds();
  1692. break;
  1693. case 'switch':
  1694. props.pen.triggers.push({
  1695. "name": e.content,
  1696. "status": [
  1697. {
  1698. "name": "满足条件,切换到状态1",
  1699. "conditionType": "and",
  1700. "conditions": [
  1701. {
  1702. "type": "",
  1703. "operator": ">=",
  1704. "key": item.key,
  1705. "keyLabel": item.label,
  1706. "valueType": ""
  1707. }
  1708. ],
  1709. "actions": [
  1710. {
  1711. "action": 1,
  1712. "params": "",
  1713. "value": {
  1714. "showChild": 1
  1715. },
  1716. "targetType": "id"
  1717. }
  1718. ]
  1719. },
  1720. {
  1721. "name": "默认显示状态",
  1722. "conditionType": "and",
  1723. "conditions": [],
  1724. "actions": [
  1725. {
  1726. "action": 1,
  1727. "params": "",
  1728. "value": {
  1729. "showChild": 0
  1730. },
  1731. "targetType": "id"
  1732. }
  1733. ]
  1734. }
  1735. ]
  1736. });
  1737. break;
  1738. case 'warning':
  1739. props.pen.triggers.push({
  1740. "name": e.content,
  1741. "status": [
  1742. {
  1743. "name": "满足条件,触发告警",
  1744. "conditions": [
  1745. {
  1746. "type": "",
  1747. "operator": ">=",
  1748. "valueType": "",
  1749. "key": item.key,
  1750. "keyLabel":item.label,
  1751. "value": undefined
  1752. }
  1753. ],
  1754. "actions": [
  1755. {
  1756. "action": 1,
  1757. "params": "",
  1758. "value": {
  1759. "background": "red",
  1760. },
  1761. "targetType": "id"
  1762. }
  1763. ],
  1764. "conditionType": "and"
  1765. },
  1766. {
  1767. "name": "恢复默认",
  1768. "conditionType": "and",
  1769. "conditions": [],
  1770. "actions": [
  1771. {
  1772. "action": 1,
  1773. "params": "",
  1774. "value": {
  1775. "background": "#0000",
  1776. },
  1777. "targetType": "id"
  1778. }
  1779. ]
  1780. }
  1781. ]
  1782. });
  1783. break;
  1784. case 'warningAnimate':
  1785. props.pen.triggers.push({
  1786. "name": e.content,
  1787. "status": [
  1788. {
  1789. "name": "满足条件,触发动画执行",
  1790. "conditions": [
  1791. {
  1792. "type": "",
  1793. "operator": ">=",
  1794. "valueType": "",
  1795. "key": item.key,
  1796. "keyLabel":item.label,
  1797. "value": undefined
  1798. }
  1799. ],
  1800. "actions": [
  1801. {
  1802. "action": 2,
  1803. "params": "",
  1804. "value": "",
  1805. "targetType": "id",
  1806. }
  1807. ],
  1808. "conditionType": "and"
  1809. },
  1810. {
  1811. "name": "恢复默认状态",
  1812. "conditionType": "and",
  1813. "conditions": [],
  1814. "actions": [
  1815. {
  1816. "action": 4,
  1817. "params": "",
  1818. "value": "",
  1819. "targetType": "id"
  1820. }
  1821. ]
  1822. }
  1823. ]
  1824. });
  1825. break;
  1826. case 'custom':
  1827. props.pen.triggers.push({
  1828. name: `状态场景${props.pen.triggers.length + 1}`,
  1829. status:[
  1830. {
  1831. name:'状态1',
  1832. conditionType: 'and',
  1833. conditions: [{
  1834. type:'',
  1835. operator: "=",
  1836. key: item.key,//"text",
  1837. keyLabel: item.label,
  1838. value: undefined
  1839. }],
  1840. actions: [],
  1841. },
  1842. {
  1843. name:'状态2',
  1844. conditionType: 'and',
  1845. conditions: [],
  1846. actions: [],
  1847. }
  1848. ],
  1849. });
  1850. break;
  1851. }
  1852. if(!['edit', 'delete'].includes(e.value)){
  1853. emit('tabchange',props.pen.triggers.length-1);
  1854. }
  1855. }
  1856. const cell = ref({
  1857. col:undefined,
  1858. row:undefined
  1859. });
  1860. const getPenData = (e)=>{
  1861. if(props.pen.name === 'tablePlus'){
  1862. if(props.pen.calculative.activeRow !== undefined){
  1863. cell.value.row = props.pen.calculative.activeRow;
  1864. cell.value.col = undefined;
  1865. }else if(props.pen.calculative.activeCell){
  1866. cell.value.col = props.pen.calculative.activeCell.col;
  1867. cell.value.row = props.pen.calculative.activeCell.row;
  1868. }else{
  1869. cell.value.col = undefined;
  1870. cell.value.row = undefined;
  1871. }
  1872. }
  1873. }
  1874. const onQuickBind = ()=>{
  1875. if(cell.value.row !== undefined){
  1876. if(!props.pen.realTimes){
  1877. props.pen.realTimes = [];
  1878. }
  1879. if(cell.value.col !== undefined){
  1880. let found = props.pen.realTimes.findIndex((item:any)=>{
  1881. return item.key === `data.${cell.value.row}.${cell.value.col}`;
  1882. });
  1883. if(found === -1){
  1884. props.pen.realTimes.push({
  1885. label: `第${cell.value.row}行,第${cell.value.col}列`,
  1886. key: `data.${cell.value.row}.${cell.value.col}`,
  1887. type: 'float',
  1888. });
  1889. onBind(props.pen.realTimes[props.pen.realTimes.length-1]);
  1890. }else{
  1891. onBind(props.pen.realTimes[found]);
  1892. }
  1893. }else{
  1894. let found = props.pen.realTimes.findIndex((item:any)=>{
  1895. return item.key === `data.${cell.value.row}`;
  1896. });
  1897. if(found === -1){
  1898. props.pen.realTimes.push({
  1899. label: `第${cell.value.row}行`,
  1900. key: `data.${cell.value.row}`,
  1901. type: 'array',
  1902. });
  1903. onBind(props.pen.realTimes[props.pen.realTimes.length-1]);
  1904. }else{
  1905. onBind(props.pen.realTimes[found]);
  1906. }
  1907. }
  1908. }
  1909. }
  1910. const dataSource = ref('');
  1911. const getDataSource = async (e) => {
  1912. dataSource.value = '';
  1913. if (e === 'excel') {
  1914. let data = await importExcel();
  1915. if (Array.isArray(data) && Array.isArray(data[0])) {
  1916. meta2d.setValue({ id: props.pen.id, data: data, styles: [], mergeCells: [], colHeaders: false }, { doEvent: false });
  1917. } else {
  1918. MessagePlugin.warning("数据格式必需是二维数组");
  1919. }
  1920. } else if (e === 'csv') {
  1921. let data = await importCSV();
  1922. if (Array.isArray(data) && Array.isArray(data[0])) {
  1923. meta2d.setValue({ id: props.pen.id, data: data, styles: [], mergeCells: [], colHeaders: false }, { doEvent: false });
  1924. } else {
  1925. MessagePlugin.warning("数据格式必需是二维数组");
  1926. }
  1927. } else if (e === 'api') {
  1928. apiDialog.show = true;
  1929. }
  1930. }
  1931. const apiDialog = reactive<any>({
  1932. show: false,
  1933. });
  1934. const onConfirmAPI = async () => {
  1935. if (!apiDialog.url) {
  1936. MessagePlugin.warning('请输入API地址');
  1937. return;
  1938. }
  1939. const res: Response = await fetch(apiDialog.url, {
  1940. headers: apiDialog.headers,
  1941. method: apiDialog.method || 'GET',
  1942. body: apiDialog.method === 'GET' ? undefined : JSON.stringify(apiDialog.body),
  1943. });
  1944. let data: any = JSON.parse(await res.text());
  1945. if (data.data) {
  1946. data = data.data;
  1947. }
  1948. if (data.list) {
  1949. data = data.list;
  1950. }
  1951. if (Array.isArray(data)) {
  1952. if (Array.isArray(data[0])) {
  1953. } else {
  1954. let _data = [];
  1955. data.forEach((item) => {
  1956. _data.push(Object.values(item));
  1957. })
  1958. data = _data;
  1959. }
  1960. if (Array.isArray(data) && Array.isArray(data[0])) {
  1961. meta2d.setValue({ id: props.pen.id, data: data, styles: [], mergeCells: [], colHeaders: false }, { doEvent: false });
  1962. MessagePlugin.success("导入成功");
  1963. } else {
  1964. MessagePlugin.warning("数据格式必需是二维数组");
  1965. }
  1966. apiDialog.show = false;
  1967. } else {
  1968. MessagePlugin.warning("数据格式必需是数组类型");
  1969. }
  1970. };
  1971. onMounted(() => {
  1972. meta2d.on('click',getPenData);
  1973. getPenData({});
  1974. });
  1975. onUnmounted(() => {
  1976. meta2d.off('click',getPenData);
  1977. clearInterval(timer);
  1978. });
  1979. </script>
  1980. <style lang="postcss" scoped>
  1981. .props {
  1982. height: 100%;
  1983. .grid {
  1984. grid-template-columns: 70px 70px 50px 65px;
  1985. padding: 0 12px;
  1986. &.head {
  1987. background: var(--color-background-input);
  1988. line-height: 36px;
  1989. margin-bottom: 6px;
  1990. .title {
  1991. line-height: 36px;
  1992. }
  1993. }
  1994. }
  1995. .blank {
  1996. height: 70%;
  1997. img {
  1998. padding: 16px;
  1999. opacity: 0.9;
  2000. }
  2001. }
  2002. .c-titile{
  2003. margin-top: 12px;
  2004. color: var(--color-title);
  2005. font-size: 12px;
  2006. font-weight: 700;
  2007. }
  2008. .c-head{
  2009. &::before{
  2010. width: 0%;
  2011. }
  2012. color: var(--color);
  2013. font-weight: 700;
  2014. }
  2015. .real-times{
  2016. .label {
  2017. width: fix-content;
  2018. font-size: 10px;
  2019. line-height: 28px;
  2020. color: var(--color-desc);
  2021. }
  2022. }
  2023. .value {
  2024. padding-right: 8px;
  2025. display: flex;
  2026. align-items: center;
  2027. justify-content: space-between;
  2028. svg {
  2029. flex-shrink: 0;
  2030. margin-right: 4px;
  2031. }
  2032. & > div {
  2033. width: 72px;
  2034. &.t-switch {
  2035. width: fit-content;
  2036. margin-left: 4px;
  2037. }
  2038. }
  2039. :deep(.t-input) {
  2040. padding-left: 4px;
  2041. height: 26px;
  2042. border-color: transparent;
  2043. &:hover {
  2044. border-color: var(--color-primary);
  2045. }
  2046. }
  2047. }
  2048. .actions {
  2049. text-align: right;
  2050. padding-right: 2px;
  2051. }
  2052. .data-list {
  2053. :deep(.t-table__header--fixed:not(.t-table__header--multiple) > tr > th) {
  2054. background: none;
  2055. }
  2056. :deep(.t-table__pagination) {
  2057. padding-bottom: 0;
  2058. }
  2059. }
  2060. }
  2061. .body {
  2062. :deep(.t-collapse.t--border-less) {
  2063. .t-collapse-panel__header {
  2064. border-top: none;
  2065. /* border-bottom: 1px solid var(--td-border-level-1-color); */
  2066. padding: 8px 0;
  2067. .t-input {
  2068. border: none;
  2069. padding-left: 0;
  2070. font-size: 14px;
  2071. }
  2072. }
  2073. .t-collapse-panel__content {
  2074. padding: 8px 0;
  2075. }
  2076. }
  2077. .title {
  2078. position: relative;
  2079. margin: 8px 0;
  2080. :deep(.t-input) {
  2081. border-color: var(--color-background-input);
  2082. border-radius: 0;
  2083. border-left: none;
  2084. border-top: none;
  2085. border-right: none;
  2086. padding-left: 0;
  2087. padding-bottom: 8px;
  2088. font-size: 14px;
  2089. &:hover {
  2090. border-color: var(--color-border-input);
  2091. }
  2092. }
  2093. }
  2094. .head {
  2095. margin-top: 10px;
  2096. }
  2097. .banner {
  2098. background-color: var(--color-background-input);
  2099. padding: 0 12px;
  2100. }
  2101. }
  2102. </style>
  2103. <style lang="postcss">
  2104. .t-drawer__mask{
  2105. /* background-color: #fff0; */
  2106. }
  2107. .t-drawer__body{
  2108. padding:0px;
  2109. }
  2110. </style>