PenDatas.vue 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005
  1. <template>
  2. <div class="props">
  3. <div
  4. class="real-times"
  5. v-if="props.pen.realTimes && props.pen.realTimes.length"
  6. >
  7. <div class="grid head">
  8. <div class="title">数据名</div>
  9. <div class="title">值</div>
  10. <div class="title">触发器</div>
  11. <div class="actions">
  12. <t-icon name="more" />
  13. </div>
  14. </div>
  15. <div class="grid" v-for="(item, i) in props.pen.realTimes">
  16. <t-tooltip :content="item.key" placement="top">
  17. <label class="label">{{ item.label }}</label>
  18. </t-tooltip>
  19. <div class="value">
  20. <t-tooltip :content="getBindsDesc(item)" placement="top">
  21. <t-icon
  22. name="link"
  23. class="hover"
  24. :class="{ primary: item.binds?.id }"
  25. @click="onBind(item)"
  26. />
  27. </t-tooltip>
  28. <t-input
  29. v-if="item.type === 'number'"
  30. v-model="pen[item.key]"
  31. placeholder="数字"
  32. @change="changeValue(item.key)"
  33. />
  34. <t-switch
  35. v-else-if="item.type === 'bool'"
  36. v-model="pen[item.key]"
  37. class="ml-8"
  38. size="small"
  39. @change="changeValue(item.key)"
  40. />
  41. <div
  42. v-else-if="item.type === 'array' || item.type === 'object'"
  43. class="gray ellipsis"
  44. style="height: 30px"
  45. >
  46. {{ JSON.stringify(pen[item.key]) }}
  47. </div>
  48. <t-input
  49. v-else
  50. v-model="pen[item.key]"
  51. placeholder="字符串"
  52. @change="changeValue(item.key)"
  53. />
  54. </div>
  55. <div>
  56. <t-tooltip :content="item.triggers?.length || '触发器'">
  57. <t-badge
  58. :count="item.triggers?.length"
  59. size="small"
  60. dot
  61. :offset="[0, 5]"
  62. >
  63. <t-icon
  64. name="relativity"
  65. class="hover"
  66. @click="onTrigger(item)"
  67. />
  68. </t-badge>
  69. </t-tooltip>
  70. </div>
  71. <div class="actions">
  72. <t-dropdown
  73. :options="moreOptions"
  74. @click="onMenuMore($event, item, i)"
  75. :minColumnWidth="80"
  76. >
  77. <t-icon name="more" class="more hover" />
  78. </t-dropdown>
  79. </div>
  80. </div>
  81. <div class="mt-8 pb-16">
  82. <t-dropdown
  83. :options="options"
  84. @click="addRealTime"
  85. :minColumnWidth="150"
  86. >
  87. <a class="ml-12"> <t-icon name="add-rectangle" /> 添加动态数据 </a>
  88. </t-dropdown>
  89. </div>
  90. </div>
  91. <div class="flex column center blank" v-else>
  92. <img src="/img/blank.png" />
  93. <div class="gray center">还没有动态数据</div>
  94. <div class="mt-8">
  95. <t-dropdown
  96. :options="options"
  97. @click="addRealTime"
  98. :minColumnWidth="150"
  99. >
  100. <t-button style="height: 30px"> 添加动态数据 </t-button>
  101. </t-dropdown>
  102. </div>
  103. </div>
  104. </div>
  105. <t-dialog
  106. v-if="addDataDialog.show"
  107. :visible="true"
  108. class="data-dialog"
  109. :header="addDataDialog.header"
  110. @close="addDataDialog.show = false"
  111. @confirm="onConfirmData"
  112. >
  113. <div class="form-item mt-16">
  114. <label>数据名</label>
  115. <t-input
  116. v-model="addDataDialog.data.label"
  117. placeholder="简短描述"
  118. :disabled="!!addDataDialog.data.keywords"
  119. @blur="onChangeLabel"
  120. />
  121. </div>
  122. <div class="form-item mt-16">
  123. <label>属性名</label>
  124. <t-input
  125. v-model="addDataDialog.data.key"
  126. placeholder="关键字"
  127. :disabled="!!addDataDialog.data.keywords"
  128. />
  129. </div>
  130. <div class="form-item mt-16">
  131. <label>类型</label>
  132. <t-select
  133. class="w-full"
  134. :options="typeOptions"
  135. v-model="addDataDialog.data.type"
  136. placeholder="字符串"
  137. :disabled="!!addDataDialog.data.keywords"
  138. @change="addDataDialog.data.value = null"
  139. />
  140. </div>
  141. <div class="form-item mt-16">
  142. <label>值</label>
  143. <div class="flex-grow" v-if="addDataDialog.data.type === 'number'">
  144. <t-input
  145. class="w-full"
  146. v-model="addDataDialog.data.value"
  147. placeholder="数字"
  148. />
  149. <div class="desc mt-8">
  150. 固定数字:直接输入数字。例如:5<br />
  151. 随机范围数字 :最小值-最大值。例如:0-1 或 0-100
  152. <br />
  153. 随机指定数字 :数字1,数字2,数字3... 。 例如:1,5,10,20<br />
  154. </div>
  155. </div>
  156. <div class="flex-grow" v-else-if="addDataDialog.data.type === 'bool'">
  157. <t-select v-model="addDataDialog.data.value">
  158. <t-option :key="true" :value="true" label="true"></t-option>
  159. <t-option :key="false" :value="false" label="false"></t-option>
  160. <t-option key="随机" label="随机"></t-option>
  161. </t-select>
  162. <div class="desc mt-8">
  163. 固定:指定true或false<br />
  164. 随机:随机生成一个布尔值<br />
  165. </div>
  166. </div>
  167. <div
  168. class="flex-grow"
  169. v-else-if="
  170. addDataDialog.data.type === 'array' ||
  171. addDataDialog.data.type === 'object'
  172. "
  173. >
  174. <CodeEditor v-model="addDataDialog.data.value" :json="true" />
  175. </div>
  176. <div class="flex-grow" v-else>
  177. <t-input
  178. class="w-full"
  179. v-model="addDataDialog.data.value"
  180. placeholder="字符串"
  181. />
  182. <div class="desc mt-8">
  183. 固定文字:直接输入。例如:大屏可视化<br />
  184. 随机文本:[文本长度]。例如:[8] 或 [16]<br />
  185. 随机指定文本:{文本1,文本2,文本3...} 。 例如:{大屏, 可视化}
  186. <br />
  187. </div>
  188. </div>
  189. </div>
  190. </t-dialog>
  191. <t-dialog
  192. v-if="dataBindDialog.show"
  193. :visible="true"
  194. class="data-link-dialog"
  195. header="动态数据绑定"
  196. @close="
  197. // dataBindDialog.data.binds = dataBindDialog.bkBinds;
  198. dataBindDialog.show = false
  199. "
  200. @confirm="dataBindDialog.show = false"
  201. :width="700"
  202. >
  203. <div class="form-item">
  204. <label>当前绑定:</label>
  205. <!-- <div class="label" v-if="dataBindDialog.data.binds?.length">
  206. <t-tooltip
  207. v-for="(tag, index) in dataBindDialog.data.binds"
  208. :key="index"
  209. :content="tag.id"
  210. >
  211. <t-tag class="mr-8 mb-8" closable @close="onRemoveBind(index)">
  212. {{ tag.label }}
  213. </t-tag>
  214. </t-tooltip>
  215. </div> -->
  216. <div class="label" v-if="dataBindDialog.data.binds?.id">
  217. <t-tooltip :content="dataBindDialog.data.binds?.id">
  218. <t-tag class="mr-8 mb-8" closable @close="onRemoveBind()">
  219. {{ dataBindDialog.data.binds?.label }}
  220. </t-tag>
  221. </t-tooltip>
  222. </div>
  223. <div class="label gray" v-else>无</div>
  224. </div>
  225. <div class="form-item mt-8">
  226. <t-input
  227. placeholder="搜索"
  228. v-model="dataBindDialog.input"
  229. @change="onSearchDataset"
  230. @enter="onSearchDataset"
  231. >
  232. <template #suffixIcon>
  233. <t-icon name="search" class="hover" @click="onSearchDataset" />
  234. </template>
  235. </t-input>
  236. </div>
  237. <t-table
  238. class="mt-12 data-list"
  239. row-key="id"
  240. :data="dataBindDialog.dataSet"
  241. :columns="dataSetColumns"
  242. size="small"
  243. bordered
  244. :loading="dataBindDialog.loading"
  245. :pagination="query"
  246. @page-change="onChangePagination"
  247. :selected-row-keys="dataBindDialog.selectedIds"
  248. @select-change="onSelectBindsChange"
  249. >
  250. </t-table>
  251. </t-dialog>
  252. <t-dialog
  253. v-if="triggersDialog.show"
  254. :visible="true"
  255. class="data-events-dialog"
  256. header="数据触发器"
  257. @confirm="triggersDialog.show = false"
  258. @close="triggersDialog.show = false"
  259. :width="700"
  260. >
  261. <div class="body">
  262. <t-collapse
  263. v-model="triggersDialog.openedCollapses"
  264. :borderless="true"
  265. :expand-on-row-click="false"
  266. >
  267. <t-collapse-panel
  268. v-for="(trigger, i) in triggersDialog.data.triggers"
  269. :value="i"
  270. >
  271. <template #header>
  272. <t-input v-model="trigger.name" class="mr-12" />
  273. </template>
  274. <template #headerRightContent>
  275. <t-popconfirm
  276. content="确认删除该触发器吗?"
  277. @confirm="triggersDialog.data.triggers.splice(i, 1)"
  278. >
  279. <t-icon name="delete" class="hover" />
  280. </t-popconfirm>
  281. </template>
  282. <section>
  283. <div class="form-item banner">
  284. <label>触发条件</label>
  285. <div class="w-full flex middle between">
  286. <div></div>
  287. <t-radio-group v-model="trigger.conditionType">
  288. <t-radio value="and"> 满足全部条件 </t-radio>
  289. <t-radio value="or"> 满足任意条件 </t-radio>
  290. </t-radio-group>
  291. </div>
  292. </div>
  293. <div v-for="(c, index) in trigger.conditions" class="mb-12">
  294. <div class="flex middle between head">
  295. <div class="flex middle">
  296. <t-icon name="arrow-right" class="mr-4" />
  297. 条件{{ index + 1 }}
  298. </div>
  299. <t-icon
  300. name="close"
  301. class="hover"
  302. @click="trigger.conditions.splice(index, 1)"
  303. />
  304. </div>
  305. <div class="px-16 py-4">
  306. <div class="form-item mt-4">
  307. <label>条件类型</label>
  308. <t-radio-group v-model="c.type">
  309. <t-radio value=""> 关系条件 </t-radio>
  310. <t-radio value="fn"> 高级条件 </t-radio>
  311. </t-radio-group>
  312. </div>
  313. <template v-if="!c.type">
  314. <div class="form-item mt-8">
  315. <label>比较条件</label>
  316. <div class="flex middle">
  317. <label class="shrink-0 mr-8">数据</label>
  318. <t-select
  319. v-model="c.operator"
  320. placeholder="关系运算"
  321. :options="operatorOptions"
  322. class="shrink-0 mr-8"
  323. style="width: 80px"
  324. />
  325. <t-select
  326. v-model="c.valueType"
  327. class="shrink-0 mr-8"
  328. style="width: 110px"
  329. placeholder="固定值"
  330. >
  331. <t-option key="" value="" label="固定值">
  332. 固定值
  333. </t-option>
  334. <t-option key="prop" value="prop" label="对象属性值">
  335. 对象属性值
  336. </t-option>
  337. </t-select>
  338. <template v-if="!c.valueType">
  339. <t-input
  340. v-model="c.value"
  341. class="shrink-0"
  342. style="width: 320px"
  343. />
  344. </template>
  345. <template v-else>
  346. <t-tree-select
  347. v-model="c.target"
  348. :data="penTree"
  349. filterable
  350. placeholder="对象"
  351. class="shrink-0 mr-8"
  352. style="width: 160px"
  353. @change="onChangeTriggerTarget(c)"
  354. />
  355. <t-select-input
  356. v-model:inputValue="c.value"
  357. :value="c.label"
  358. v-model:popupVisible="c.popupVisible"
  359. allow-input
  360. clearable
  361. @clear="c.label = undefined"
  362. @focus="c.popupVisible = true"
  363. @blur="c.popupVisible = undefined"
  364. @input-change="onInput(c)"
  365. class="shrink-0"
  366. style="width: 152px"
  367. >
  368. <template #panel>
  369. <ul style="padding: 8px 12px">
  370. <li
  371. v-for="item in c.targetProps"
  372. :key="item.value"
  373. @click="
  374. c.value = item.value;
  375. c.label = item.label;
  376. "
  377. >
  378. {{ item.label }}
  379. </li>
  380. </ul>
  381. </template>
  382. </t-select-input>
  383. </template>
  384. </div>
  385. </div>
  386. </template>
  387. <template v-else>
  388. <div>function condition(pen) {</div>
  389. <CodeEditor class="mt-4" v-model="c.fnJs" />
  390. <div class="mt-4">}</div>
  391. </template>
  392. </div>
  393. </div>
  394. <div class="mt-8">
  395. <a @click="addTriggerCondition(trigger)"> + 添加条件 </a>
  396. </div>
  397. <div class="form-item banner mt-16">
  398. <label>执行动作</label>
  399. </div>
  400. <Actions class="mt-8" :data="trigger" />
  401. </section>
  402. </t-collapse-panel>
  403. </t-collapse>
  404. <div class="mt-8">
  405. <a @click="onAddTrigger"> + 添加触发器 </a>
  406. </div>
  407. </div>
  408. </t-dialog>
  409. </template>
  410. <script lang="ts" setup>
  411. import {
  412. getCurrentInstance,
  413. onBeforeMount,
  414. onUnmounted,
  415. reactive,
  416. ref,
  417. toRaw,
  418. } from 'vue';
  419. import { useRoute, useRouter } from 'vue-router';
  420. import { MessagePlugin } from 'tdesign-vue-next';
  421. import axios from 'axios';
  422. import { debounce } from '@/services/debouce';
  423. import { getPenTree, typeOptions } from '@/services/common';
  424. import { updatePen } from './pen';
  425. import CodeEditor from '@/views/components/common/CodeEditor.vue';
  426. import Actions from './Actions.vue';
  427. const route = useRoute();
  428. const router = useRouter();
  429. const {
  430. proxy: { $forceUpdate },
  431. }: any = getCurrentInstance();
  432. const props = defineProps<{
  433. pen: any;
  434. }>();
  435. const options = ref<any>([
  436. {
  437. value: '',
  438. content: '自定义',
  439. divider: true,
  440. },
  441. {
  442. value: 'x',
  443. content: 'X',
  444. type: 'number',
  445. keywords: true,
  446. },
  447. {
  448. value: 'y',
  449. content: 'Y',
  450. type: 'number',
  451. keywords: true,
  452. },
  453. {
  454. value: 'width',
  455. content: '宽',
  456. type: 'number',
  457. keywords: true,
  458. },
  459. {
  460. value: 'height',
  461. content: '高',
  462. type: 'number',
  463. keywords: true,
  464. },
  465. {
  466. value: 'visible',
  467. content: '显示',
  468. type: 'bool',
  469. keywords: true,
  470. },
  471. {
  472. value: 'text',
  473. content: '文字',
  474. keywords: true,
  475. },
  476. {
  477. value: 'progress',
  478. content: '进度',
  479. type: 'number',
  480. keywords: true,
  481. },
  482. {
  483. value: 'showChild',
  484. content: '状态',
  485. type: 'number',
  486. keywords: true,
  487. },
  488. {
  489. value: 'rotate',
  490. content: '旋转',
  491. type: 'number',
  492. keywords: true,
  493. },
  494. ]);
  495. const moreOptions = ref<any>([
  496. {
  497. value: 'edit',
  498. content: '编辑',
  499. },
  500. {
  501. value: 'delete',
  502. content: '移除',
  503. },
  504. ]);
  505. const addDataDialog = reactive<any>({
  506. show: false,
  507. data: undefined,
  508. });
  509. const dataBindDialog = reactive<any>({
  510. show: false,
  511. data: undefined,
  512. });
  513. const dataSetColumns = [
  514. {
  515. colKey: 'row-select',
  516. type: 'single',
  517. width: 50,
  518. },
  519. {
  520. colKey: 'id',
  521. title: '编号',
  522. width: 150,
  523. ellipsis: { theme: 'light', trigger: 'context-menu' },
  524. },
  525. {
  526. colKey: 'label',
  527. title: '动态数据名称',
  528. width: 220,
  529. ellipsis: { theme: 'light', trigger: 'context-menu' },
  530. },
  531. {
  532. colKey: 'case',
  533. title: '场景',
  534. ellipsis: { theme: 'light', trigger: 'context-menu' },
  535. },
  536. ];
  537. const operatorOptions = ref<any>([
  538. { label: '=', value: '=' },
  539. { label: '!=', value: '!=' },
  540. { label: '>', value: '>' },
  541. { label: '<', value: '<' },
  542. { label: '>=', value: '>=' },
  543. { label: '<=', value: '<=' },
  544. { label: '包含', value: '[)' },
  545. { label: '不包含', value: '![)' },
  546. ]);
  547. const query = reactive<{
  548. current: number;
  549. pageSize: number;
  550. total: number;
  551. range: any[];
  552. }>({
  553. current: 1,
  554. pageSize: 10,
  555. total: 0,
  556. range: [],
  557. });
  558. const triggersDialog = reactive<any>({
  559. show: false,
  560. data: undefined,
  561. });
  562. const penTree: any = ref([]);
  563. let timer: any;
  564. onBeforeMount(() => {
  565. // realTimesOptions - 扩展的动态数据下拉列表
  566. if (props.pen.realTimesOptions) {
  567. options.value[options.value.length - 1].divider = true;
  568. options.value.push(...props.pen.realTimesOptions);
  569. }
  570. timer = setInterval($forceUpdate, 1000);
  571. });
  572. const addRealTime = (e: any) => {
  573. if (e.keywords) {
  574. if (!props.pen.realTimes) {
  575. props.pen.realTimes = [];
  576. }
  577. props.pen.realTimes.push({
  578. label: e.content,
  579. key: e.value,
  580. type: e.type,
  581. keywords: e.keywords,
  582. });
  583. return;
  584. }
  585. addDataDialog.header = '添加动态数据';
  586. addDataDialog.data = {
  587. label: e.content,
  588. key: e.value,
  589. type: e.type,
  590. keywords: e.keywords,
  591. };
  592. if (e.keywords) {
  593. addDataDialog.data.label = '';
  594. }
  595. addDataDialog.show = true;
  596. };
  597. const onChangeLabel = () => {
  598. if (!addDataDialog.data.key) {
  599. addDataDialog.data.key = addDataDialog.data.label;
  600. }
  601. };
  602. const onConfirmData = () => {
  603. if (!props.pen.realTimes) {
  604. props.pen.realTimes = [];
  605. }
  606. if (!addDataDialog.data.label || !addDataDialog.data.key) {
  607. MessagePlugin.error('数据名或属性名不能为空!');
  608. return;
  609. }
  610. if (addDataDialog.header === '添加动态数据') {
  611. const found = props.pen.realTimes.findIndex((item: any) => {
  612. return item.key === addDataDialog.data.key;
  613. });
  614. if (found > -1) {
  615. MessagePlugin.error('已经存在相同属性数据!');
  616. return;
  617. }
  618. props.pen.realTimes.push(addDataDialog.data);
  619. }
  620. meta2d.penMock(props.pen);
  621. addDataDialog.show = false;
  622. };
  623. const onMenuMore = (e: any, item: any, i: number) => {
  624. switch (e.value) {
  625. case 'edit':
  626. addDataDialog.header = '编辑动态数据';
  627. addDataDialog.data = item;
  628. addDataDialog.show = true;
  629. break;
  630. case 'delete':
  631. props.pen.realTimes.splice(i, 1);
  632. break;
  633. default:
  634. break;
  635. }
  636. };
  637. const onBind = (item: any) => {
  638. // if (!item.binds) {
  639. // item.binds = [];
  640. // }
  641. // dataBindDialog.data = item;
  642. // dataBindDialog.input = '';
  643. // dataBindDialog.selectedIds = [];
  644. // for (const i of item.binds) {
  645. // dataBindDialog.selectedIds.push(i.id);
  646. // }
  647. // dataBindDialog.bkBinds = [];
  648. // dataBindDialog.bkBinds.push(...item.binds);
  649. // dataBindDialog.show = true;
  650. dataBindDialog.data = item;
  651. dataBindDialog.input = '';
  652. dataBindDialog.selectedIds = [];
  653. if (item.binds && item.binds.id) {
  654. dataBindDialog.selectedIds.push(item.binds.id);
  655. }
  656. dataBindDialog.show = true;
  657. getDataset();
  658. };
  659. const onSearchDataset = () => {
  660. debounce(getDataset, 300);
  661. };
  662. const getDataset = async () => {
  663. // @ts-ignore
  664. const data: Meta2dBackData = meta2d.data();
  665. dataBindDialog.loading = true;
  666. // 应该从data获取url或结果列表
  667. const ret: any = await axios.get(
  668. `/api/device/data/set?mock=1&q=${dataBindDialog.input}&current=${query.current}&pageSize=${query.pageSize}`
  669. );
  670. dataBindDialog.dataSet = ret.list;
  671. query.total = ret.total;
  672. dataBindDialog.loading = false;
  673. };
  674. const onChangePagination = (pageInfo: any) => {
  675. router.push({
  676. path: route.path,
  677. query: { current: pageInfo.current, pageSize: pageInfo.pageSize },
  678. });
  679. query.current = pageInfo.current;
  680. query.pageSize = pageInfo.pageSize;
  681. getDataset();
  682. };
  683. const onSelectBindsChange = (value: string[], options: any) => {
  684. // dataBindDialog.selectedIds = value;
  685. if (options.type === 'check') {
  686. // for (const item of options.selectedRowData) {
  687. // const found = dataBindDialog.data.binds.findIndex((elem: any) => {
  688. // return elem.id === item.id;
  689. // });
  690. // if (found < 0) {
  691. // dataBindDialog.data.binds.push(toRaw(item));
  692. // }
  693. // }
  694. dataBindDialog.selectedIds = value;
  695. dataBindDialog.data.binds = toRaw(options.selectedRowData[0]);
  696. } else if (options.type === 'uncheck') {
  697. // if (options.currentRowKey === 'CHECK_ALL_BOX') {
  698. // for (const data of dataBindDialog.dataSet) {
  699. // const found = dataBindDialog.data.binds.findIndex((elem: any) => {
  700. // return elem.id === data.id;
  701. // });
  702. // if (found > -1) {
  703. // dataBindDialog.data.binds.splice(found, 1);
  704. // }
  705. // }
  706. // } else {
  707. // const found = dataBindDialog.data.binds.findIndex((elem: any) => {
  708. // return elem.id === options.currentRowKey;
  709. // });
  710. // if (found > -1) {
  711. // dataBindDialog.data.binds.splice(found, 1);
  712. // }
  713. dataBindDialog.selectedIds = [];
  714. dataBindDialog.data.binds = {};
  715. // }
  716. }
  717. };
  718. const onRemoveBind = () => {
  719. // dataBindDialog.data.binds.splice(index, 1);
  720. dataBindDialog.selectedIds = [];
  721. // for (const i of dataBindDialog.data.binds) {
  722. // dataBindDialog.selectedIds.push(i.id);
  723. // }
  724. dataBindDialog.data.binds = undefined;
  725. };
  726. const getBindsDesc = (item: any) => {
  727. if (!item.binds || !item.binds.id) {
  728. return '绑定动态数据';
  729. }
  730. // let desc = '';
  731. // for (const i of item.binds) {
  732. // desc += i.label + ',';
  733. // }
  734. // if (desc && desc.length > 1) {
  735. // desc = desc.substring(0, desc.length - 1);
  736. // }
  737. return item.binds.label;
  738. };
  739. const changeValue = (prop: string) => {
  740. updatePen(props.pen, prop);
  741. };
  742. const onTrigger = (item: any) => {
  743. if (!item.triggers) {
  744. item.triggers = [];
  745. }
  746. triggersDialog.openedCollapses = [0];
  747. triggersDialog.data = item;
  748. triggersDialog.show = true;
  749. penTree.value = getPenTree();
  750. };
  751. const onAddTrigger = () => {
  752. const i = triggersDialog.data.triggers.length;
  753. triggersDialog.data.triggers.push({
  754. name: `触发器${i + 1}`,
  755. conditionType: 'and',
  756. conditions: [],
  757. actions: [],
  758. });
  759. triggersDialog.openedCollapses.push(i);
  760. };
  761. const addTriggerCondition = (trigger: any) => {
  762. trigger.conditions.push({
  763. type: '',
  764. operator: '=',
  765. valueType: '',
  766. });
  767. };
  768. const onChangeTriggerTarget = (c: any) => {
  769. c.targetProps = [
  770. {
  771. value: 'x',
  772. label: 'X',
  773. },
  774. {
  775. value: 'y',
  776. label: 'Y',
  777. },
  778. {
  779. value: 'width',
  780. label: '宽',
  781. },
  782. {
  783. value: 'height',
  784. label: '高',
  785. },
  786. {
  787. value: 'visible',
  788. label: '显示',
  789. },
  790. {
  791. value: 'text',
  792. label: '文字',
  793. },
  794. {
  795. value: 'progress',
  796. label: '进度',
  797. },
  798. {
  799. value: 'showChild',
  800. label: '状态',
  801. },
  802. {
  803. value: 'rotate',
  804. label: '旋转',
  805. },
  806. ];
  807. const target: any = meta2d.findOne(c.target);
  808. if (target) {
  809. for (const item of target.realTimes) {
  810. const found = c.targetProps.findIndex(
  811. (elem: any) => elem.value === item.key
  812. );
  813. if (found < 0) {
  814. c.targetProps.push({
  815. value: item.key,
  816. label: item.label,
  817. });
  818. }
  819. }
  820. }
  821. };
  822. const onInput = (item: any) => {
  823. item.label = item.value;
  824. };
  825. onUnmounted(() => {
  826. clearInterval(timer);
  827. });
  828. </script>
  829. <style lang="postcss" scoped>
  830. .props {
  831. height: 100%;
  832. .grid {
  833. grid-template-columns: 60px 140px 54px 30px;
  834. padding: 0 12px;
  835. &.head {
  836. background: var(--color-background-input);
  837. line-height: 36px;
  838. margin-bottom: 6px;
  839. .title {
  840. line-height: 36px;
  841. }
  842. }
  843. }
  844. .blank {
  845. height: 70%;
  846. img {
  847. padding: 16px;
  848. opacity: 0.9;
  849. }
  850. }
  851. .label {
  852. width: fit-content;
  853. font-size: 10px;
  854. line-height: 28px;
  855. color: var(--color-desc);
  856. }
  857. .value {
  858. padding-right: 8px;
  859. display: flex;
  860. align-items: center;
  861. svg {
  862. flex-shrink: 0;
  863. margin-right: 4px;
  864. }
  865. & > div {
  866. width: 110px;
  867. &.t-switch {
  868. width: fit-content;
  869. margin-left: 4px;
  870. }
  871. }
  872. :deep(.t-input) {
  873. padding-left: 4px;
  874. height: 26px;
  875. border-color: transparent;
  876. &:hover {
  877. border-color: var(--color-primary);
  878. }
  879. }
  880. }
  881. .actions {
  882. text-align: right;
  883. padding-right: 2px;
  884. }
  885. .data-list {
  886. height: 300px;
  887. overflow: auto;
  888. }
  889. }
  890. .body {
  891. :deep(.t-collapse.t--border-less) {
  892. .t-collapse-panel__header {
  893. border-top: none;
  894. border-bottom: 1px solid var(--td-border-level-1-color);
  895. padding: 8px 0;
  896. .t-input {
  897. border: none;
  898. padding-left: 0;
  899. font-size: 14px;
  900. }
  901. }
  902. .t-collapse-panel__content {
  903. padding: 8px 0;
  904. }
  905. }
  906. .title {
  907. position: relative;
  908. margin: 8px 0;
  909. :deep(.t-input) {
  910. border-color: var(--color-background-input);
  911. border-radius: 0;
  912. border-left: none;
  913. border-top: none;
  914. border-right: none;
  915. padding-left: 0;
  916. padding-bottom: 8px;
  917. font-size: 14px;
  918. &:hover {
  919. border-color: var(--color-border-input);
  920. }
  921. }
  922. }
  923. .head {
  924. margin-top: 10px;
  925. }
  926. .banner {
  927. background-color: var(--color-background-input);
  928. padding: 0 12px;
  929. }
  930. }
  931. </style>