Pārlūkot izejas kodu

feat:新增全局行为+触发改状态

ananzhusen 1 gadu atpakaļ
vecāks
revīzija
12b85f77d5

+ 20 - 0
src/services/common.ts

@@ -902,6 +902,26 @@ export const getPenTree = () => {
   return tree.list;
 };
 
+const iframeTree = reactive({
+  list: [],
+  patch: true,
+});
+
+export const getIframeTree = () => {
+  iframeTree.patch = false;
+  const list = [];
+  for (const item of meta2d.store.data.pens) {
+    if (item.name !== 'iframe') {
+      continue;
+    }
+    const elem = calcElem(item);
+    elem && list.push(elem);
+  }
+  iframeTree.list = list.reverse();
+
+  return iframeTree.list;
+};
+
 export const getPenAnimations = (idOrTag?: string) => {
   const animations = [];
   let pens: any[] = meta2d.store.active || [];

+ 10 - 2
src/views/components/Actions.vue

@@ -355,7 +355,13 @@
         <template v-else-if="a.action == 16">
           <div class="form-item mt-8">
             <label>场景对象</label>
-            <t-input v-model="a.params" placeholder="画笔id/tag" />
+            <!-- <t-input v-model="a.params" placeholder="画笔id/tag" /> -->
+            <t-tree-select
+              v-model="a.params"
+              :data="iframeTree"
+              filterable
+              placeholder="必填"
+            />
           </div>
           <div class="form-item mt-8">
             <label>消息名</label>
@@ -382,7 +388,7 @@ import { onBeforeMount, ref } from 'vue';
 import CodeEditor from '@/views/components/common/CodeEditor.vue';
 import Network from './Network.vue';
 import { CloseIcon,AddCircleIcon,DeleteIcon,CheckIcon} from 'tdesign-icons-vue-next';
-import { getPenAnimations, getPenTree ,changeType} from '@/services/common';
+import { getPenAnimations, getPenTree ,changeType, getIframeTree} from '@/services/common';
 
 const { data } = defineProps<{
   data: any;
@@ -458,6 +464,7 @@ const actionOptions = [
 const penTree: any = ref([]);
 const groups: any = ref([]);
 const animations: any = ref([]);
+const iframeTree:any = ref([]);
 
 onBeforeMount(() => {
   if (!data.actions) {
@@ -465,6 +472,7 @@ onBeforeMount(() => {
   }
 
   penTree.value = getPenTree();
+  iframeTree.value = getIframeTree();
   groups.value = [];
   const d = meta2d.store.data as any;
   if (d.groups) {

+ 4 - 0
src/views/components/FileProps.vue

@@ -282,6 +282,9 @@
           </t-collapse>
         </t-space>
       </t-tab-panel>
+      <t-tab-panel :value="3" label="行为">
+        <GlobalStates />
+      </t-tab-panel>
       <t-tab-panel :value="2" label="结构">
         <ElementTree />
       </t-tab-panel>
@@ -327,6 +330,7 @@ import { useEnterprise } from '@/services/enterprise';
 import { MoreIcon, CloseIcon, EllipsisIcon} from 'tdesign-icons-vue-next';
 import { useMeta2dData,useExtendData } from '@/services/common';
 import { lineCross,clearLineCross,handleLineCross } from '@meta2d/utils';
+import GlobalStates from './GlobalStates.vue';
 
 const { getEnterprise } = useEnterprise();
 const { meta2dData, setMeta2dData } = useMeta2dData();

+ 436 - 0
src/views/components/GlobalStates.vue

@@ -0,0 +1,436 @@
+<template>
+  <div class="props">
+    <t-collapse
+      :borderless="true"
+      :expand-on-row-click="false"
+      v-model="openedCollapses"
+    >
+      <t-collapse-panel v-for="(trigger, i) in data.triggers" :value="i + 1">
+        <template #header>
+          <t-input v-model="trigger.name" class="mr-12" />
+        </template>
+        <template #headerRightContent>
+          <t-popconfirm
+            content="确认删除该行为吗?"
+            @confirm="data.triggers.splice(i, 1)"
+          >
+            <delete-icon class="hover" />
+          </t-popconfirm>
+        </template>
+        <section>
+          <div class="form-item">
+            <label>触发条件</label>
+            <div class="w-full flex middle between">
+              <div></div>
+              <t-radio-group v-model="trigger.conditionType">
+                <t-radio value="and"> 满足全部条件 </t-radio>
+                <t-radio value="or"> 满足任意条件 </t-radio>
+              </t-radio-group>
+            </div>
+          </div>
+          <div v-for="(c, index) in trigger.conditions" class="mb-12">
+            <div class="flex middle between head">
+              <div class="flex middle">
+                <arrow-right-icon class="mr-4" />
+                条件{{ index + 1 }}
+              </div>
+              <close-icon
+                class="hover"
+                @click="trigger.conditions.splice(index, 1)"
+              />
+            </div>
+            <div class="py-4">
+              <div class="form-item mt-8">
+                <label>对象</label>
+                <t-tree-select
+                  v-model="c.source"
+                  :data="penTree"
+                  filterable
+                  placeholder="对象"
+                  class="shrink-0"
+                  @change="onChangeTriggerTarget(c)"
+                />
+              </div>
+              <div class="form-item mt-4">
+                <label>条件类型</label>
+                <t-radio-group v-model="c.type">
+                  <t-radio value=""> 关系条件 </t-radio>
+                  <t-radio value="fn"> 高级条件 </t-radio>
+                </t-radio-group>
+              </div>
+              <template v-if="!c.type">
+                <div class="form-item mt-8">
+                  <label>属性名</label>
+                  <t-select-input
+                    v-model:inputValue="c.key"
+                    :value="c.keyLabel"
+                    v-model:popupVisible="c.keyPopupVisible"
+                    allow-input
+                    clearable
+                    @clear="c.keyLabel = undefined"
+                    @focus="c.keyPopupVisible = true"
+                    @blur="c.keyPopupVisible = false"
+                    @input-change="onKeyInput(c)"
+                    class="shrink-0"
+                    style="width: 152px"
+                  >
+                    <template #panel>
+                      <ul style="padding: 8px 12px">
+                        <li
+                          v-for="item in cProps"
+                          :key="item.value"
+                          @click="
+                            c.key = item.value;
+                            c.keyLabel = item.label;
+                            c.keyPopupVisible = false;
+                          "
+                        >
+                          {{ item.label }}
+                        </li>
+                      </ul>
+                    </template>
+                  </t-select-input>
+                </div>
+                <div class="form-item mt-8">
+                  <label>关系运算</label>
+                  <t-select
+                    v-model="c.operator"
+                    placeholder="关系运算"
+                    :options="operatorOptions"
+                    clearable
+                    class="shrink-0"
+                  />
+                </div>
+                <div class="form-item mt-8">
+                  <label>运算对象</label>
+                  <t-select
+                    v-model="c.valueType"
+                    class="shrink-0"
+                    placeholder="固定值"
+                  >
+                    <t-option key="" value="" label="固定值"> 固定值 </t-option>
+                    <t-option key="prop" value="prop" label="对象属性值">
+                      对象属性值
+                    </t-option>
+                  </t-select>
+                </div>
+                <div
+                  v-if="!c.valueType"
+                  class="form-item mt-8 form-item-valueType"
+                >
+                  <label>值</label>
+                  <t-input
+                    v-model="c.value"
+                    @change="valueChange($event, c)"
+                    class="shrink-0"
+                    style="width: 320px"
+                  />
+                </div>
+                <template v-else>
+                  <div class="form-item mt-8">
+                    <label>对象</label>
+                    <t-tree-select
+                      v-model="c.target"
+                      :data="penTree"
+                      filterable
+                      placeholder="对象"
+                      class="shrink-0"
+                      @change="onChangeTriggerTarget(c)"
+                    />
+                  </div>
+                  <div class="form-item mt-8">
+                    <label>属性</label>
+                    <t-select-input
+                      v-model:inputValue="c.value"
+                      :value="c.label"
+                      v-model:popupVisible="c.popupVisible"
+                      allow-input
+                      clearable
+                      @clear="c.label = undefined"
+                      @focus="c.popupVisible = true"
+                      @blur="c.popupVisible = false"
+                      @input-change="onInput(c)"
+                      class="shrink-0"
+                    >
+                      <template #panel>
+                        <ul style="padding: 8px 12px">
+                          <li
+                            v-for="item in cProps"
+                            :key="item.value"
+                            @click="
+                              c.value = item.value;
+                              c.label = item.label;
+                              c.popupVisible = false;
+                            "
+                          >
+                            {{ item.label }}
+                          </li>
+                        </ul>
+                      </template>
+                    </t-select-input>
+                  </div>
+                </template>
+              </template>
+              <template v-else>
+                <div>function condition(pen) {</div>
+                <CodeEditor
+                  class="mt-4"
+                  @change="codeChange($event, c)"
+                  v-model="c.fnJs"
+                />
+                <div class="mt-4">}</div>
+              </template>
+            </div>
+          </div>
+          <div class="mt-8">
+            <a @click="addTriggerCondition(trigger)"> + 添加条件 </a>
+          </div>
+
+          <div class="form-item banner mt-16">
+            <label>执行动作</label>
+          </div>
+          <Actions class="mt-8" :data="trigger" />
+        </section>
+      </t-collapse-panel>
+    </t-collapse>
+
+    <div class="mt-8 ml-16">
+      <a @click="onAddTrigger"> + 添加行为 </a>
+    </div>
+  </div>
+</template>
+
+<script lang="ts" setup>
+import {
+  getCurrentInstance,
+  onBeforeMount,
+  onMounted,
+  onBeforeUnmount,
+  onUnmounted,
+  reactive,
+  ref,
+  toRaw,
+} from 'vue';
+import { getPenTree, typeOptions, changeType } from '@/services/common';
+import { ArrowRightIcon, CloseIcon, DeleteIcon } from 'tdesign-icons-vue-next';
+import CodeEditor from '@/views/components/common/CodeEditor.vue';
+import Actions from './Actions.vue';
+
+const openedCollapses = ref([1]);
+onBeforeMount(() => {
+  penTree.value = getPenTree();
+});
+const data = reactive({
+  triggers: [],
+});
+
+onMounted(() => {
+  const d = meta2d.store.data as any;
+  if (!d.triggers) {
+    d.triggers = [];
+  }
+  data.triggers = d.triggers;
+  meta2d.on('opened', getTriggers);
+});
+
+onBeforeUnmount(() => {
+  meta2d.off('opened', getTriggers);
+});
+
+const getTriggers = () => {
+  const d = meta2d.store.data as any;
+  if (!d.triggers) {
+    d.triggers = [];
+  }
+  data.triggers = d.triggers;
+};
+const penTree: any = ref([]);
+
+const operatorOptions = ref<any>([
+  { label: '=', value: '=' },
+  { label: '!=', value: '!=' },
+  { label: '>', value: '>' },
+  { label: '<', value: '<' },
+  { label: '>=', value: '>=' },
+  { label: '<=', value: '<=' },
+  { label: '包含', value: '[)' },
+  { label: '不包含', value: '![)' },
+]);
+
+const cProps = [
+  {
+    value: 'x',
+    label: 'X',
+  },
+  {
+    value: 'y',
+    label: 'Y',
+  },
+  {
+    value: 'width',
+    label: '宽',
+  },
+  {
+    value: 'height',
+    label: '高',
+  },
+  {
+    value: 'visible',
+    label: '显示',
+  },
+  {
+    value: 'text',
+    label: '文字',
+  },
+  {
+    value: 'progress',
+    label: '进度',
+  },
+  {
+    value: 'showChild',
+    label: '状态',
+  },
+  {
+    value: 'rotate',
+    label: '旋转',
+  },
+];
+
+const valueChange = (e, c: any) => {
+  c.value = changeType(e);
+};
+
+const onChangeTriggerTarget = (c: any) => {
+  /*
+  c.targetProps = [
+    {
+      value: 'x',
+      label: 'X',
+    },
+    {
+      value: 'y',
+      label: 'Y',
+    },
+    {
+      value: 'width',
+      label: '宽',
+    },
+    {
+      value: 'height',
+      label: '高',
+    },
+    {
+      value: 'visible',
+      label: '显示',
+    },
+    {
+      value: 'text',
+      label: '文字',
+    },
+    {
+      value: 'progress',
+      label: '进度',
+    },
+    {
+      value: 'showChild',
+      label: '状态',
+    },
+    {
+      value: 'rotate',
+      label: '旋转',
+    },
+  ];*/
+
+  const target: any = meta2d.findOne(c.target);
+  if (target && target.realTimes) {
+    for (const item of target.realTimes) {
+      const found = cProps.findIndex((elem: any) => elem.value === item.key);
+      if (found < 0) {
+        cProps.push({
+          value: item.key,
+          label: item.label,
+        });
+      }
+    }
+  }
+};
+
+const onInput = (item: any) => {
+  item.label = item.value;
+};
+
+const onKeyInput = (item: any) => {
+  item.keyLabel = item.key;
+};
+
+const addTriggerCondition = (trigger: any) => {
+  trigger.conditions.push({
+    type: '',
+    operator: '=',
+    valueType: '',
+  });
+};
+
+const codeChange = (e: any, a: any) => {
+  a.fn = null;
+};
+
+const onAddTrigger = () => {
+  const i = data.triggers.length;
+  data.triggers.push({
+    name: `行为${i + 1}`,
+    conditionType: 'and',
+    conditions: [],
+    actions: [],
+  });
+};
+</script>
+<style lang="postcss" scoped>
+:deep(.t-collapse.t--border-less) {
+  .t-collapse-panel__header {
+    border: none;
+    /* border-top: none; */
+    /* border-bottom: 1px solid var(--td-border-level-1-color); */
+    padding: 8px 12px;
+
+    .t-input {
+      border: none;
+      padding-left: 0;
+      font-size: 14px;
+    }
+  }
+
+  .t-collapse-panel__content {
+    padding: 8px 0;
+  }
+}
+
+.title {
+  position: relative;
+  margin: 8px 0;
+
+  :deep(.t-input) {
+    border-color: var(--color-background-input);
+    border-radius: 0;
+    border-left: none;
+    border-top: none;
+    border-right: none;
+    padding-left: 0;
+    padding-bottom: 8px;
+    font-size: 14px;
+
+    &:hover {
+      border-color: var(--color-border-input);
+    }
+  }
+}
+
+.head {
+  margin-top: 10px;
+}
+
+.banner {
+  /* background-color: var(--color-background-input); */
+  padding: 0 12px;
+}
+</style>

+ 13 - 12
src/views/components/PenDatas.vue

@@ -158,7 +158,7 @@
           <div class="grid head">
             <div class="title">数据名</div>
             <div class="title">值</div>
-            <div class="title">触发器</div>
+            <div class="title">状态</div>
             <div class="actions">
               <more-icon />
               <!-- <t-icon name="more" /> -->
@@ -218,7 +218,7 @@
               </t-tooltip>
             </div>
             <div>
-              <t-tooltip :content="item.triggers?.length || '触发器'">
+              <t-tooltip :content="item.triggers?.length || '状态'">
                 <t-badge
                   :count="item.triggers?.length"
                   size="small"
@@ -369,7 +369,7 @@
           <div class="label gray" v-else>无</div>
         </div>
         <div class="form-item flex middle mt-8">
-          <t-input
+          <!-- <t-input
             v-if="dataBindDialog.url"
             v-model="dataBindDialog.device"
             placeholder="设备"
@@ -390,9 +390,10 @@
               :value="item"
               :label="item"
             />
-          </t-select>
+          </t-select> -->
 
           <t-input
+            style="width:250px;"
             placeholder="搜索"
             v-model="dataBindDialog.input"
             @change="onSearchDataset"
@@ -475,7 +476,7 @@
     v-if="triggersDialog.show"
     :visible="true"
     class="data-events-dialog"
-    header="数据触发器"
+    header="数据状态"
     @confirm="triggersDialog.show = false"
     @close="triggersDialog.show = false"
     :width="700"
@@ -495,7 +496,7 @@
           </template>
           <template #headerRightContent>
             <t-popconfirm
-              content="确认删除该触发器吗?"
+              content="确认删除该状态吗?"
               @confirm="triggersDialog.data.triggers.splice(i, 1)"
             >
               <delete-icon class="hover"/>
@@ -504,12 +505,12 @@
           </template>
           <section>
             <div class="form-item banner">
-              <label>触发条件</label>
+              <label>满足条件</label>
               <div class="w-full flex middle between">
                 <div></div>
                 <t-radio-group v-model="trigger.conditionType">
-                  <t-radio value="and"> 满足全部条件 </t-radio>
-                  <t-radio value="or"> 满足任意条件 </t-radio>
+                  <t-radio value="and"> 所有 </t-radio>
+                  <t-radio value="or"> 任意 </t-radio>
                 </t-radio-group>
               </div>
             </div>
@@ -632,7 +633,7 @@
       </t-collapse>
 
       <div class="mt-8">
-        <a @click="onAddTrigger"> + 添加触发器 </a>
+        <a @click="onAddTrigger"> + 添加状态 </a>
       </div>
     </div>
   </t-dialog>
@@ -1164,7 +1165,7 @@ const getBindsDesc = (item: any) => {
     return item.mock;
   }
 
-  return '动态数据';
+  return '绑定变量';
 };
 const { selections } = useSelection();
 
@@ -1194,7 +1195,7 @@ const onTrigger = (item: any) => {
 const onAddTrigger = () => {
   const i = triggersDialog.data.triggers.length;
   triggersDialog.data.triggers.push({
-    name: `触发器${i + 1}`,
+    name: `状态${i + 1}`,
     conditionType: 'and',
     conditions: [],
     actions: [],