PenDatas.vue 25 KB

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