|
@@ -1,13 +1,12 @@
|
|
|
<template>
|
|
|
<div class="props">
|
|
|
- <div class="px-16 py-16" v-if="pen.realTimes && pen.realTimes.length">
|
|
|
- <div class="grid" style="line-height: 30px">
|
|
|
+ <div class="real-times" v-if="pen.realTimes && pen.realTimes.length">
|
|
|
+ <div class="grid head">
|
|
|
<div class="title">数据名</div>
|
|
|
- <div class="title ml-8">值</div>
|
|
|
- <div>
|
|
|
- <div style="text-align: right; padding-right: 2px">
|
|
|
- <t-icon name="more" />
|
|
|
- </div>
|
|
|
+ <div class="title">值</div>
|
|
|
+ <div class="title">触发器</div>
|
|
|
+ <div class="actions">
|
|
|
+ <t-icon name="more" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="grid" v-for="(item, i) in pen.realTimes">
|
|
@@ -15,12 +14,51 @@
|
|
|
<label class="label">{{ item.label }}</label>
|
|
|
</t-tooltip>
|
|
|
<div class="value">
|
|
|
- <t-input v-model="item.value" />
|
|
|
+ <t-tooltip :content="getBindsDesc(item)" placement="top">
|
|
|
+ <t-icon
|
|
|
+ name="link"
|
|
|
+ class="hover"
|
|
|
+ :class="{ primary: item.binds?.length }"
|
|
|
+ @click="onBind(item)"
|
|
|
+ />
|
|
|
+ </t-tooltip>
|
|
|
+ <t-input
|
|
|
+ v-if="item.type === 'number'"
|
|
|
+ v-model="pen[item.key]"
|
|
|
+ placeholder="数字"
|
|
|
+ @change="changeValue(item.key)"
|
|
|
+ />
|
|
|
+ <t-switch
|
|
|
+ v-else-if="item.type === 'bool'"
|
|
|
+ v-model="pen[item.key]"
|
|
|
+ class="ml-8"
|
|
|
+ size="small"
|
|
|
+ @change="changeValue(item.key)"
|
|
|
+ />
|
|
|
+ <t-input
|
|
|
+ v-else
|
|
|
+ v-model="pen[item.key]"
|
|
|
+ placeholder="字符串"
|
|
|
+ @change="changeValue(item.key)"
|
|
|
+ />
|
|
|
</div>
|
|
|
- <div class="actions">
|
|
|
- <t-tooltip content="变量绑定" placement="top">
|
|
|
- <t-icon name="link" class="hover" @click="onBind(item)" />
|
|
|
+ <div>
|
|
|
+ <t-tooltip :content="item.triggers?.length || '触发器'">
|
|
|
+ <t-badge
|
|
|
+ :count="item.triggers?.length"
|
|
|
+ size="small"
|
|
|
+ dot
|
|
|
+ :offset="[0, 5]"
|
|
|
+ >
|
|
|
+ <t-icon
|
|
|
+ name="relativity"
|
|
|
+ class="hover"
|
|
|
+ @click="onTrigger(item)"
|
|
|
+ />
|
|
|
+ </t-badge>
|
|
|
</t-tooltip>
|
|
|
+ </div>
|
|
|
+ <div class="actions">
|
|
|
<t-dropdown
|
|
|
:options="moreOptions"
|
|
|
@click="onMenuMore($event, item, i)"
|
|
@@ -36,7 +74,7 @@
|
|
|
@click="addRealTime"
|
|
|
:minColumnWidth="150"
|
|
|
>
|
|
|
- <a> <t-icon name="add-rectangle" /> 添加动态数据 </a>
|
|
|
+ <a class="ml-12"> <t-icon name="add-rectangle" /> 添加动态数据 </a>
|
|
|
</t-dropdown>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -133,7 +171,7 @@
|
|
|
v-if="dataBindDialog.show"
|
|
|
:visible="true"
|
|
|
class="data-link-dialog"
|
|
|
- header="变量绑定"
|
|
|
+ header="动态数据绑定"
|
|
|
@cancel="
|
|
|
dataBindDialog.data.binds = dataBindDialog.bkBinds;
|
|
|
dataBindDialog.show = false;
|
|
@@ -148,7 +186,6 @@
|
|
|
v-for="(tag, index) in dataBindDialog.data.binds"
|
|
|
:key="index"
|
|
|
:content="tag.id"
|
|
|
- trigger="click"
|
|
|
>
|
|
|
<t-tag class="mr-8 mb-8" closable @close="onRemoveBind(index)">
|
|
|
{{ tag.label }}
|
|
@@ -184,18 +221,62 @@
|
|
|
>
|
|
|
</t-table>
|
|
|
</t-dialog>
|
|
|
+
|
|
|
+ <t-dialog
|
|
|
+ v-if="triggersDialog.show"
|
|
|
+ :visible="true"
|
|
|
+ class="data-events-dialog"
|
|
|
+ header="数据触发器"
|
|
|
+ @cancel="triggersDialog.show = false"
|
|
|
+ @confirm="triggersDialog.show = false"
|
|
|
+ :width="700"
|
|
|
+ >
|
|
|
+ <div class="body">
|
|
|
+ <div class="mb-12" v-for="(trigger, i) in triggersDialog.data.triggers">
|
|
|
+ <div class="flex middle between">
|
|
|
+ <div class="title">触发器{{ i + 1 }}</div>
|
|
|
+
|
|
|
+ <t-popconfirm
|
|
|
+ content="确认删除该触发器吗?"
|
|
|
+ @confirm="triggersDialog.data.triggers.splice(i, 1)"
|
|
|
+ >
|
|
|
+ <t-icon name="close" class="hover" />
|
|
|
+ </t-popconfirm>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <a @click="triggersDialog.data.triggers.push({})">
|
|
|
+ <t-icon name="add" />
|
|
|
+ 添加触发器
|
|
|
+ </a>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </t-dialog>
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
-import { onBeforeMount, reactive, ref, toRaw } from 'vue';
|
|
|
+import {
|
|
|
+ getCurrentInstance,
|
|
|
+ onBeforeMount,
|
|
|
+ onUnmounted,
|
|
|
+ reactive,
|
|
|
+ ref,
|
|
|
+ toRaw,
|
|
|
+} from 'vue';
|
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
|
import { MessagePlugin } from 'tdesign-vue-next';
|
|
|
import axios from 'axios';
|
|
|
import { debounce } from '@/services/debouce';
|
|
|
|
|
|
+import { updatePen } from './pen.ts';
|
|
|
+
|
|
|
const route = useRoute();
|
|
|
const router = useRouter();
|
|
|
|
|
|
+const {
|
|
|
+ proxy: { $forceUpdate },
|
|
|
+}: any = getCurrentInstance();
|
|
|
+
|
|
|
const { pen } = defineProps<{
|
|
|
pen: any;
|
|
|
}>();
|
|
@@ -308,7 +389,7 @@ const dataSetColumns = [
|
|
|
},
|
|
|
{
|
|
|
colKey: 'label',
|
|
|
- title: '变量名称',
|
|
|
+ title: '动态数据名称',
|
|
|
width: 220,
|
|
|
ellipsis: { theme: 'light', trigger: 'context-menu' },
|
|
|
},
|
|
@@ -331,11 +412,21 @@ const query = reactive<{
|
|
|
range: [],
|
|
|
});
|
|
|
|
|
|
+const triggersDialog = reactive<any>({
|
|
|
+ show: false,
|
|
|
+ data: undefined,
|
|
|
+});
|
|
|
+
|
|
|
+let timer: any;
|
|
|
+
|
|
|
onBeforeMount(() => {
|
|
|
+ // realTimesOptions - 扩展的动态数据下拉列表
|
|
|
if (pen.realTimesOptions) {
|
|
|
options.value[options.value.length - 1].divider = true;
|
|
|
options.value.push(...pen.realTimesOptions);
|
|
|
}
|
|
|
+
|
|
|
+ timer = setInterval($forceUpdate, 1000);
|
|
|
});
|
|
|
|
|
|
const addRealTime = (e: any) => {
|
|
@@ -499,13 +590,50 @@ const onRemoveBind = (index: number) => {
|
|
|
dataBindDialog.selectedIds.push(i.id);
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+const getBindsDesc = (item: any) => {
|
|
|
+ if (!item.binds || !item.binds.length) {
|
|
|
+ return '绑定动态数据';
|
|
|
+ }
|
|
|
+ let desc = '';
|
|
|
+ for (const i of item.binds) {
|
|
|
+ desc += i.label + ',';
|
|
|
+ }
|
|
|
+ if (desc && desc.length > 1) {
|
|
|
+ desc = desc.substring(0, desc.length - 1);
|
|
|
+ }
|
|
|
+ return desc;
|
|
|
+};
|
|
|
+
|
|
|
+const changeValue = (prop: string) => {
|
|
|
+ updatePen(pen, prop);
|
|
|
+};
|
|
|
+
|
|
|
+const onTrigger = (item: any) => {
|
|
|
+ if (!item.triggers) {
|
|
|
+ item.triggers = [];
|
|
|
+ }
|
|
|
+ triggersDialog.data = item;
|
|
|
+ triggersDialog.show = true;
|
|
|
+};
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ clearInterval(timer);
|
|
|
+});
|
|
|
</script>
|
|
|
<style lang="postcss" scoped>
|
|
|
.props {
|
|
|
height: 100%;
|
|
|
|
|
|
.grid {
|
|
|
- grid-template-columns: 80px 154px 40px;
|
|
|
+ grid-template-columns: 60px 140px 54px 30px;
|
|
|
+ padding: 0 12px;
|
|
|
+
|
|
|
+ &.head {
|
|
|
+ background: var(--color-background-input);
|
|
|
+ line-height: 36px;
|
|
|
+ margin-bottom: 6px;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
.blank {
|
|
@@ -525,8 +653,20 @@ const onRemoveBind = (index: number) => {
|
|
|
|
|
|
.value {
|
|
|
padding-right: 8px;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+
|
|
|
+ svg {
|
|
|
+ flex-shrink: 0;
|
|
|
+ margin-right: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ div {
|
|
|
+ width: 110px;
|
|
|
+ }
|
|
|
|
|
|
:deep(.t-input) {
|
|
|
+ padding-left: 4px;
|
|
|
height: 26px;
|
|
|
border-color: transparent;
|
|
|
&:hover {
|
|
@@ -536,9 +676,8 @@ const onRemoveBind = (index: number) => {
|
|
|
}
|
|
|
|
|
|
.actions {
|
|
|
- svg {
|
|
|
- margin-left: 6px;
|
|
|
- }
|
|
|
+ text-align: right;
|
|
|
+ padding-right: 2px;
|
|
|
}
|
|
|
|
|
|
.data-list {
|