GlobalStates.vue 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. <template>
  2. <div class="props">
  3. <t-collapse
  4. :borderless="true"
  5. :expand-on-row-click="false"
  6. v-model="openedCollapses"
  7. >
  8. <t-collapse-panel v-for="(trigger, i) in data.triggers" :value="i + 1">
  9. <template #header>
  10. <t-input v-model="trigger.name" class="mr-12" />
  11. </template>
  12. <template #headerRightContent>
  13. <t-popconfirm
  14. content="确认删除该行为吗?"
  15. @confirm="data.triggers.splice(i, 1)"
  16. :popup-props="{ placement: 'left' }"
  17. >
  18. <delete-icon class="hover" />
  19. </t-popconfirm>
  20. </template>
  21. <section>
  22. <div class="form-item banner">
  23. <label>触发条件</label>
  24. <div class="w-full flex middle between">
  25. <div></div>
  26. <t-radio-group v-model="trigger.conditionType">
  27. <t-radio value="and"> 满足全部条件 </t-radio>
  28. <t-radio value="or"> 满足任意条件 </t-radio>
  29. </t-radio-group>
  30. </div>
  31. </div>
  32. <div v-for="(c, index) in trigger.conditions" class="mb-12">
  33. <div class="flex middle between head">
  34. <div class="flex middle">
  35. <arrow-right-icon class="mr-4" />
  36. 条件{{ index + 1 }}
  37. </div>
  38. <close-icon
  39. class="hover"
  40. @click="trigger.conditions.splice(index, 1)"
  41. />
  42. </div>
  43. <div class="py-4">
  44. <div class="form-item mt-8">
  45. <label>对象</label>
  46. <t-tree-select
  47. v-model="c.source"
  48. :data="penTree"
  49. filterable
  50. placeholder="对象"
  51. class="shrink-0"
  52. @change="onChangeTriggerTarget(c)"
  53. />
  54. </div>
  55. <div class="form-item mt-4">
  56. <label>条件类型</label>
  57. <t-radio-group v-model="c.type">
  58. <t-radio value=""> 关系条件 </t-radio>
  59. <t-radio value="fn"> 高级条件 </t-radio>
  60. </t-radio-group>
  61. </div>
  62. <template v-if="!c.type">
  63. <div class="form-item mt-8">
  64. <label>属性名</label>
  65. <t-select-input
  66. v-model:inputValue="c.key"
  67. :value="c.keyLabel"
  68. v-model:popupVisible="c.keyPopupVisible"
  69. allow-input
  70. clearable
  71. @clear="c.keyLabel = undefined"
  72. @focus="c.keyPopupVisible = true"
  73. @blur="c.keyPopupVisible = false"
  74. @input-change="onKeyInput(c)"
  75. class="shrink-0"
  76. style="width: 152px"
  77. >
  78. <template #panel>
  79. <ul style="padding: 8px 12px">
  80. <li
  81. v-for="item in cProps"
  82. :key="item.value"
  83. @click="
  84. c.key = item.value;
  85. c.keyLabel = item.label;
  86. c.keyPopupVisible = false;
  87. "
  88. >
  89. {{ item.label }}
  90. </li>
  91. </ul>
  92. </template>
  93. </t-select-input>
  94. </div>
  95. <div class="form-item mt-8">
  96. <label>关系运算</label>
  97. <t-select
  98. v-model="c.operator"
  99. placeholder="关系运算"
  100. :options="operatorOptions"
  101. clearable
  102. class="shrink-0"
  103. />
  104. </div>
  105. <div class="form-item mt-8">
  106. <label>运算对象</label>
  107. <t-select
  108. v-model="c.valueType"
  109. class="shrink-0"
  110. placeholder="固定值"
  111. >
  112. <t-option key="" value="" label="固定值"> 固定值 </t-option>
  113. <t-option key="prop" value="prop" label="对象属性值">
  114. 对象属性值
  115. </t-option>
  116. </t-select>
  117. </div>
  118. <div
  119. v-if="!c.valueType"
  120. class="form-item mt-8 form-item-valueType"
  121. >
  122. <label>值</label>
  123. <t-input
  124. v-model="c.value"
  125. @change="valueChange($event, c)"
  126. class="shrink-0"
  127. style="width: 320px"
  128. />
  129. </div>
  130. <template v-else>
  131. <div class="form-item mt-8">
  132. <label>对象</label>
  133. <t-tree-select
  134. v-model="c.target"
  135. :data="penTree"
  136. filterable
  137. placeholder="对象"
  138. class="shrink-0"
  139. @change="onChangeTriggerTarget(c)"
  140. />
  141. </div>
  142. <div class="form-item mt-8">
  143. <label>属性</label>
  144. <t-select-input
  145. v-model:inputValue="c.value"
  146. :value="c.label"
  147. v-model:popupVisible="c.popupVisible"
  148. allow-input
  149. clearable
  150. @clear="c.label = undefined"
  151. @focus="c.popupVisible = true"
  152. @blur="c.popupVisible = false"
  153. @input-change="onInput(c)"
  154. class="shrink-0"
  155. >
  156. <template #panel>
  157. <ul style="padding: 8px 12px">
  158. <li
  159. v-for="item in cProps"
  160. :key="item.value"
  161. @click="
  162. c.value = item.value;
  163. c.label = item.label;
  164. c.popupVisible = false;
  165. "
  166. >
  167. {{ item.label }}
  168. </li>
  169. </ul>
  170. </template>
  171. </t-select-input>
  172. </div>
  173. </template>
  174. </template>
  175. <template v-else>
  176. <div>function condition(pen) {</div>
  177. <CodeEditor
  178. class="mt-4"
  179. @change="codeChange($event, c)"
  180. v-model="c.fnJs"
  181. />
  182. <div class="mt-4">}</div>
  183. </template>
  184. </div>
  185. </div>
  186. <div class="mt-8">
  187. <a @click="addTriggerCondition(trigger)"> + 添加条件 </a>
  188. </div>
  189. <div class="form-item banner mt-16">
  190. <label>执行动作</label>
  191. </div>
  192. <Actions class="mt-8" :data="trigger" />
  193. </section>
  194. </t-collapse-panel>
  195. </t-collapse>
  196. <div class="mt-8 ml-16">
  197. <!-- <a @click="onAddTrigger"> + 添加行为 </a> -->
  198. <t-button @click="onAddTrigger" style="width: 90%;" variant="outline">
  199. <template #icon><add-icon /></template>
  200. 添加行为
  201. </t-button>
  202. </div>
  203. </div>
  204. </template>
  205. <script lang="ts" setup>
  206. import {
  207. getCurrentInstance,
  208. onBeforeMount,
  209. onMounted,
  210. onBeforeUnmount,
  211. onUnmounted,
  212. reactive,
  213. ref,
  214. toRaw,
  215. } from 'vue';
  216. import { getPenTree, typeOptions, changeType } from '@/services/common';
  217. import { ArrowRightIcon, CloseIcon, DeleteIcon, AddIcon } from 'tdesign-icons-vue-next';
  218. import CodeEditor from '@/views/components/common/CodeEditor.vue';
  219. import Actions from './Actions.vue';
  220. const openedCollapses = ref([1]);
  221. onBeforeMount(() => {
  222. penTree.value = getPenTree();
  223. });
  224. const data = reactive({
  225. triggers: [],
  226. });
  227. onMounted(() => {
  228. const d = meta2d.store.data as any;
  229. if (!d.triggers) {
  230. d.triggers = [];
  231. }
  232. data.triggers = d.triggers;
  233. meta2d.on('opened', getTriggers);
  234. });
  235. onBeforeUnmount(() => {
  236. meta2d.off('opened', getTriggers);
  237. });
  238. const getTriggers = () => {
  239. const d = meta2d.store.data as any;
  240. if (!d.triggers) {
  241. d.triggers = [];
  242. }
  243. data.triggers = d.triggers;
  244. };
  245. const penTree: any = ref([]);
  246. const operatorOptions = ref<any>([
  247. { label: '=', value: '=' },
  248. { label: '!=', value: '!=' },
  249. { label: '>', value: '>' },
  250. { label: '<', value: '<' },
  251. { label: '>=', value: '>=' },
  252. { label: '<=', value: '<=' },
  253. { label: '包含', value: '[)' },
  254. { label: '不包含', value: '![)' },
  255. ]);
  256. const cProps = [
  257. {
  258. value: 'x',
  259. label: 'X',
  260. },
  261. {
  262. value: 'y',
  263. label: 'Y',
  264. },
  265. {
  266. value: 'width',
  267. label: '宽',
  268. },
  269. {
  270. value: 'height',
  271. label: '高',
  272. },
  273. {
  274. value: 'visible',
  275. label: '显示',
  276. },
  277. {
  278. value: 'text',
  279. label: '文字',
  280. },
  281. {
  282. value: 'color',
  283. label: '颜色',
  284. },
  285. {
  286. value: 'background',
  287. label: '背景颜色',
  288. },
  289. {
  290. value: 'progress',
  291. label: '进度',
  292. },
  293. {
  294. value: 'progressColor',
  295. label: '进度颜色',
  296. },
  297. {
  298. value: 'showChild',
  299. label: '状态',
  300. },
  301. {
  302. value: 'rotate',
  303. label: '旋转',
  304. },
  305. {
  306. value: 'disabled',
  307. label: '禁用',
  308. },
  309. {
  310. value: 'selectedKey',
  311. label: '单选选中值',
  312. }
  313. ];
  314. const valueChange = (e, c: any) => {
  315. c.value = changeType(e);
  316. };
  317. const onChangeTriggerTarget = (c: any) => {
  318. /*
  319. c.targetProps = [
  320. {
  321. value: 'x',
  322. label: 'X',
  323. },
  324. {
  325. value: 'y',
  326. label: 'Y',
  327. },
  328. {
  329. value: 'width',
  330. label: '宽',
  331. },
  332. {
  333. value: 'height',
  334. label: '高',
  335. },
  336. {
  337. value: 'visible',
  338. label: '显示',
  339. },
  340. {
  341. value: 'text',
  342. label: '文字',
  343. },
  344. {
  345. value: 'progress',
  346. label: '进度',
  347. },
  348. {
  349. value: 'showChild',
  350. label: '状态',
  351. },
  352. {
  353. value: 'rotate',
  354. label: '旋转',
  355. },
  356. ];*/
  357. const target: any = meta2d.findOne(c.target);
  358. if (target && target.realTimes) {
  359. for (const item of target.realTimes) {
  360. const found = cProps.findIndex((elem: any) => elem.value === item.key);
  361. if (found < 0) {
  362. cProps.push({
  363. value: item.key,
  364. label: item.label,
  365. });
  366. }
  367. }
  368. }
  369. };
  370. const onInput = (item: any) => {
  371. item.label = item.value;
  372. };
  373. const onKeyInput = (item: any) => {
  374. item.keyLabel = item.key;
  375. };
  376. const addTriggerCondition = (trigger: any) => {
  377. trigger.conditions.push({
  378. type: '',
  379. operator: '=',
  380. valueType: '',
  381. });
  382. };
  383. const codeChange = (e: any, a: any) => {
  384. a.fn = null;
  385. };
  386. const onAddTrigger = () => {
  387. const i = data.triggers.length;
  388. data.triggers.push({
  389. name: `行为${i + 1}`,
  390. conditionType: 'and',
  391. conditions: [],
  392. actions: [],
  393. });
  394. };
  395. </script>
  396. <style lang="postcss" scoped>
  397. .props{
  398. padding-top:12px;
  399. }
  400. :deep(.t-collapse.t--border-less) {
  401. .t-collapse-panel__header {
  402. border: none;
  403. /* border-top: none; */
  404. /* border-bottom: 1px solid var(--td-border-level-1-color); */
  405. padding: 8px 12px;
  406. .t-input {
  407. border: none;
  408. padding-left: 0;
  409. font-size: 14px;
  410. }
  411. }
  412. .t-collapse-panel__content {
  413. padding: 8px 0;
  414. }
  415. }
  416. .title {
  417. position: relative;
  418. margin: 8px 0;
  419. :deep(.t-input) {
  420. border-color: var(--color-background-input);
  421. border-radius: 0;
  422. border-left: none;
  423. border-top: none;
  424. border-right: none;
  425. padding-left: 0;
  426. padding-bottom: 8px;
  427. font-size: 14px;
  428. &:hover {
  429. border-color: var(--color-border-input);
  430. }
  431. }
  432. }
  433. .head {
  434. margin-top: 10px;
  435. }
  436. .banner {
  437. /* background-color: var(--color-background-input);
  438. padding: 0 12px; */
  439. }
  440. </style>