|
@@ -0,0 +1,2477 @@
|
|
|
+<template>
|
|
|
+ <div
|
|
|
+ class="content"
|
|
|
+ style="height: calc(100vh - 82px); overflow-y: auto"
|
|
|
+ v-if="group === '数据'"
|
|
|
+ >
|
|
|
+ <div
|
|
|
+ class="flex mt-16 mb-16"
|
|
|
+ style="justify-content: space-between; padding-right: 8px"
|
|
|
+ >
|
|
|
+ <div style="line-height: 32px">数据列表</div>
|
|
|
+ <t-dropdown :minColumnWidth="168">
|
|
|
+ <div class="icon-box">
|
|
|
+ <AddIcon />
|
|
|
+ </div>
|
|
|
+ <t-dropdown-menu>
|
|
|
+ <t-dropdown-item @click="onShowIot"> 物联网平台 </t-dropdown-item>
|
|
|
+ <t-dropdown-item @click="addSql"> sql数据源 </t-dropdown-item>
|
|
|
+ <t-dropdown-item @click="addNetwork('mqtt')"> MQTT </t-dropdown-item>
|
|
|
+ <t-dropdown-item @click="addNetwork('websocket')"> Websocket </t-dropdown-item>
|
|
|
+ <t-dropdown-item @click="addNetwork('http')"> HTTP </t-dropdown-item>
|
|
|
+ </t-dropdown-menu>
|
|
|
+ </t-dropdown>
|
|
|
+ </div>
|
|
|
+ <div class="flex between mt-8">
|
|
|
+ <t-tooltip content="可批量导入数据图元到画布" placement="top">
|
|
|
+ <t-checkbox v-model="data.checkAll" @change="onCheckAllChange"
|
|
|
+ >批量导入到画布</t-checkbox
|
|
|
+ >
|
|
|
+ </t-tooltip>
|
|
|
+ <!-- <t-tooltip content="开启全局数据模拟" placement="top">
|
|
|
+ <t-checkbox v-model="data.enableMock" @change="onChangeMock"
|
|
|
+ >开启</t-checkbox
|
|
|
+ >
|
|
|
+ </t-tooltip> -->
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div v-if="data.iotTree?.length">
|
|
|
+ <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
|
|
|
+ <div class="flex">
|
|
|
+ <ApplicationIcon class="tree-icon mt-8" />
|
|
|
+ <div class="ml-8">物联网平台</div>
|
|
|
+ </div>
|
|
|
+ <!-- <div>
|
|
|
+ <Edit2Icon class="mr-12 hover" style="width: 14px;height: 14px;" @click="onShowIot" />
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
+ <!-- <div> -->
|
|
|
+ <div
|
|
|
+ :draggable="data.checkAll ? true : false"
|
|
|
+ @dragstart="onAddShape($event, data.iotTree,'iot')"
|
|
|
+ @dragend="onAddShapeEnd"
|
|
|
+ >
|
|
|
+ <t-tree
|
|
|
+ :draggable="false"
|
|
|
+ v-model="allChecked"
|
|
|
+ class="ml-16"
|
|
|
+ style="overflow-y: hidden"
|
|
|
+ activeMultiple
|
|
|
+ :data="data.iotTree"
|
|
|
+ :expand-parent="true"
|
|
|
+ :checkable="data.checkAll"
|
|
|
+ :checkStrictly="false"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <!-- </div> -->
|
|
|
+ <div
|
|
|
+ id="dragElem-iot"
|
|
|
+ style="position: absolute; left: 0; z-index: -999"
|
|
|
+ v-if="data.iotTree.length"
|
|
|
+ >
|
|
|
+ <div v-for="device in data.iotTree">
|
|
|
+ <div
|
|
|
+ class="flex mt-4"
|
|
|
+ v-for="(prop, i) in device.children"
|
|
|
+ v-show="allChecked.includes(prop.value)"
|
|
|
+ >
|
|
|
+ <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
|
|
|
+ <div class="ml-4">{{ prop.mock }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="data.sqls?.length">
|
|
|
+ <div class="flex mt-16" style="height: 32px">
|
|
|
+ <DataIcon class="tree-icon" />
|
|
|
+ <div class="ml-8">SQL数据源</div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ :draggable="data.checkAll ? true : false"
|
|
|
+ @dragstart="onAddShape($event, data.sqls,'sql')"
|
|
|
+ @dragend="onAddShapeEnd"
|
|
|
+ >
|
|
|
+ <t-tree
|
|
|
+ :draggable="false"
|
|
|
+ class="ml-16"
|
|
|
+ :key="sqlTreeKey"
|
|
|
+ hover
|
|
|
+ style="overflow-y: hidden"
|
|
|
+ activeMultiple
|
|
|
+ :data="data.sqls"
|
|
|
+ :expand-parent="true"
|
|
|
+ :checkable="data.checkAll"
|
|
|
+ :checkStrictly="false"
|
|
|
+ >
|
|
|
+ <template #operations="{ node }">
|
|
|
+ <tepmlate v-if="!node.getParent()">
|
|
|
+ <Edit2Icon
|
|
|
+ class="mr-12"
|
|
|
+ @click="editSql(node.data, node.getIndex())"
|
|
|
+ />
|
|
|
+ <DeleteIcon class="mr-8" @click="deleteSql(node.getIndex())" />
|
|
|
+ </tepmlate>
|
|
|
+ </template>
|
|
|
+ </t-tree>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ id="dragElem-sql"
|
|
|
+ style="position: absolute; left: 0; z-index: -999"
|
|
|
+ v-if="data.sqls.length"
|
|
|
+ >
|
|
|
+ <div v-for="item in data.sqls">
|
|
|
+ <div
|
|
|
+ class="flex mt-4"
|
|
|
+ v-for="(prop, i) in item.children"
|
|
|
+ v-show="sqlsCheked.includes(prop.value)"
|
|
|
+ >
|
|
|
+ <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
|
|
|
+ <div class="ml-4">{{ prop.mock }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <!-- <div v-if="data.networks?.length">
|
|
|
+ <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
|
|
|
+ <div class="flex">
|
|
|
+ <ControlPlatformIcon class="tree-icon mt-8" />
|
|
|
+ <div class="ml-8">Mqtt</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ :draggable="data.checkAll ? true : false"
|
|
|
+ @dragstart="onAddShape($event, data.networks,'network')"
|
|
|
+ @dragend="onAddShapeEnd"
|
|
|
+ >
|
|
|
+ <t-tree
|
|
|
+ :draggable="false"
|
|
|
+ class="ml-16"
|
|
|
+ v-model="networksCheked"
|
|
|
+ ref="networkTree"
|
|
|
+ :key="networkTreeKey"
|
|
|
+ style="overflow-y: hidden"
|
|
|
+ activeMultiple
|
|
|
+ :data="data.networks"
|
|
|
+ :expand-parent="true"
|
|
|
+ :checkable="data.checkAll"
|
|
|
+ :checkStrictly="false"
|
|
|
+ >
|
|
|
+ <template #operations="{ node }">
|
|
|
+ <template v-if="node.getParent()">
|
|
|
+ <Edit2Icon
|
|
|
+ class="mr-12"
|
|
|
+ @click="showAddData(node.getParent().data, node)"
|
|
|
+ />
|
|
|
+ <DeleteIcon
|
|
|
+ class="mr-8"
|
|
|
+ @click="
|
|
|
+ deleteData(node.getParent().data, node.getIndex());
|
|
|
+ node.remove();
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <t-dropdown :minColumnWidth="168" :hide-after-item-click="false">
|
|
|
+ <AddIcon class="mr-12" />
|
|
|
+ <t-dropdown-menu>
|
|
|
+ <t-dropdown-item
|
|
|
+ :value="2"
|
|
|
+ :divider="true"
|
|
|
+ @click="showAddData(node.data)"
|
|
|
+ >
|
|
|
+ 新建属性
|
|
|
+ </t-dropdown-item>
|
|
|
+ <t-dropdown-item :value="2" @click="importDataset(node.data)">
|
|
|
+ 从Excel导入
|
|
|
+ </t-dropdown-item>
|
|
|
+ <t-dropdown-item :value="4">
|
|
|
+ <a
|
|
|
+ :href="
|
|
|
+ isDownload
|
|
|
+ ? '/v/data.xlsx'
|
|
|
+ : cdn
|
|
|
+ ? cdn + '/v/data.xlsx?r=' + Math.random()
|
|
|
+ : '/data.xlsx'
|
|
|
+ "
|
|
|
+ style="color: var(--td-text-color-primary)"
|
|
|
+ @click.stop
|
|
|
+ >
|
|
|
+ 下载Excel示例
|
|
|
+ </a>
|
|
|
+ </t-dropdown-item>
|
|
|
+ </t-dropdown-menu>
|
|
|
+ </t-dropdown>
|
|
|
+ <Edit2Icon
|
|
|
+ class="mr-12"
|
|
|
+ @click="editNetwork(node.data, node.getIndex())"
|
|
|
+ />
|
|
|
+ <DeleteIcon
|
|
|
+ class="mr-8"
|
|
|
+ @click="
|
|
|
+ deleteNetwork(node.getIndex());
|
|
|
+ node.remove();
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </t-tree>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ id="dragElem-network"
|
|
|
+ style="position: absolute; left: 0; z-index: -999"
|
|
|
+ v-if="data.networks.length"
|
|
|
+ >
|
|
|
+ <div v-for="item in data.networks">
|
|
|
+ <div
|
|
|
+ class="flex mt-4"
|
|
|
+ v-for="(prop, i) in item.children"
|
|
|
+ v-show="networksCheked.includes(prop.value)"
|
|
|
+ >
|
|
|
+ <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
|
|
|
+ <div class="ml-4">{{ prop.mock }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div> -->
|
|
|
+ <div v-if="data.mqtt_networks?.length">
|
|
|
+ <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
|
|
|
+ <div class="flex">
|
|
|
+ <ControlPlatformIcon class="tree-icon mt-8" />
|
|
|
+ <div class="ml-8">MQTT</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ :draggable="data.checkAll ? true : false"
|
|
|
+ @dragstart="onAddShape($event, data.networks,'network')"
|
|
|
+ @dragend="onAddShapeEnd"
|
|
|
+ >
|
|
|
+ <t-tree
|
|
|
+ :draggable="false"
|
|
|
+ class="ml-16"
|
|
|
+ v-model="networksCheked"
|
|
|
+ ref="mqttTree"
|
|
|
+ :key="mqttTreeKey"
|
|
|
+ style="overflow-y: hidden"
|
|
|
+ activeMultiple
|
|
|
+ :data="data.mqtt_networks"
|
|
|
+ :expand-parent="true"
|
|
|
+ :checkable="data.checkAll"
|
|
|
+ :checkStrictly="false"
|
|
|
+ >
|
|
|
+ <template #operations="{ node }">
|
|
|
+ <template v-if="node.getParent()">
|
|
|
+ <Edit2Icon
|
|
|
+ class="mr-12"
|
|
|
+ @click="showAddData(node.getParent().data, node)"
|
|
|
+ />
|
|
|
+ <DeleteIcon
|
|
|
+ class="mr-8"
|
|
|
+ @click="
|
|
|
+ deleteData(node.getParent().data, node.getIndex());
|
|
|
+ node.remove();
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <t-dropdown :minColumnWidth="168" :hide-after-item-click="false">
|
|
|
+ <AddIcon class="mr-12" />
|
|
|
+ <t-dropdown-menu>
|
|
|
+ <t-dropdown-item
|
|
|
+ :value="2"
|
|
|
+ :divider="true"
|
|
|
+ @click="showAddData(node.data)"
|
|
|
+ >
|
|
|
+ 新建属性
|
|
|
+ </t-dropdown-item>
|
|
|
+ <t-dropdown-item :value="2" @click="importDataset(node.data)">
|
|
|
+ 从Excel导入
|
|
|
+ </t-dropdown-item>
|
|
|
+ <t-dropdown-item :value="4">
|
|
|
+ <a
|
|
|
+ :href="
|
|
|
+ isDownload
|
|
|
+ ? '/v/data.xlsx'
|
|
|
+ : cdn
|
|
|
+ ? cdn + '/v/data.xlsx?r=' + Math.random()
|
|
|
+ : '/data.xlsx'
|
|
|
+ "
|
|
|
+ style="color: var(--td-text-color-primary)"
|
|
|
+ @click.stop
|
|
|
+ >
|
|
|
+ 下载Excel示例
|
|
|
+ </a>
|
|
|
+ </t-dropdown-item>
|
|
|
+ </t-dropdown-menu>
|
|
|
+ </t-dropdown>
|
|
|
+ <Edit2Icon
|
|
|
+ class="mr-12"
|
|
|
+ @click="editNetwork(node.data, node.data.tem_index)"
|
|
|
+ />
|
|
|
+ <DeleteIcon
|
|
|
+ class="mr-8"
|
|
|
+ @click="
|
|
|
+ deleteNetwork(node.data.tem_index);
|
|
|
+ node.remove();
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </t-tree>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ id="dragElem-network"
|
|
|
+ style="position: absolute; left: 0; z-index: -999"
|
|
|
+ v-if="data.networks.length"
|
|
|
+ >
|
|
|
+ <div v-for="item in data.networks">
|
|
|
+ <div
|
|
|
+ class="flex mt-4"
|
|
|
+ v-for="(prop, i) in item.children"
|
|
|
+ v-show="networksCheked.includes(prop.value)"
|
|
|
+ >
|
|
|
+ <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
|
|
|
+ <div class="ml-4">{{ prop.mock }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="data.ws_networks?.length">
|
|
|
+ <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
|
|
|
+ <div class="flex">
|
|
|
+ <ControlPlatformIcon class="tree-icon mt-8" />
|
|
|
+ <div class="ml-8">Websocket</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ :draggable="data.checkAll ? true : false"
|
|
|
+ @dragstart="onAddShape($event, data.networks,'network')"
|
|
|
+ @dragend="onAddShapeEnd"
|
|
|
+ >
|
|
|
+ <t-tree
|
|
|
+ :draggable="false"
|
|
|
+ class="ml-16"
|
|
|
+ v-model="networksCheked"
|
|
|
+ ref="wsTree"
|
|
|
+ :key="wsTreeKey"
|
|
|
+ style="overflow-y: hidden"
|
|
|
+ activeMultiple
|
|
|
+ :data="data.ws_networks"
|
|
|
+ :expand-parent="true"
|
|
|
+ :checkable="data.checkAll"
|
|
|
+ :checkStrictly="false"
|
|
|
+ >
|
|
|
+ <template #operations="{ node }">
|
|
|
+ <template v-if="node.getParent()">
|
|
|
+ <Edit2Icon
|
|
|
+ class="mr-12"
|
|
|
+ @click="showAddData(node.getParent().data, node)"
|
|
|
+ />
|
|
|
+ <DeleteIcon
|
|
|
+ class="mr-8"
|
|
|
+ @click="
|
|
|
+ deleteData(node.getParent().data, node.getIndex());
|
|
|
+ node.remove();
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <t-dropdown :minColumnWidth="168" :hide-after-item-click="false">
|
|
|
+ <AddIcon class="mr-12" />
|
|
|
+ <t-dropdown-menu>
|
|
|
+ <t-dropdown-item
|
|
|
+ :value="2"
|
|
|
+ :divider="true"
|
|
|
+ @click="showAddData(node.data)"
|
|
|
+ >
|
|
|
+ 新建属性
|
|
|
+ </t-dropdown-item>
|
|
|
+ <t-dropdown-item :value="2" @click="importDataset(node.data)">
|
|
|
+ 从Excel导入
|
|
|
+ </t-dropdown-item>
|
|
|
+ <t-dropdown-item :value="4">
|
|
|
+ <a
|
|
|
+ :href="
|
|
|
+ isDownload
|
|
|
+ ? '/v/data.xlsx'
|
|
|
+ : cdn
|
|
|
+ ? cdn + '/v/data.xlsx?r=' + Math.random()
|
|
|
+ : '/data.xlsx'
|
|
|
+ "
|
|
|
+ style="color: var(--td-text-color-primary)"
|
|
|
+ @click.stop
|
|
|
+ >
|
|
|
+ 下载Excel示例
|
|
|
+ </a>
|
|
|
+ </t-dropdown-item>
|
|
|
+ </t-dropdown-menu>
|
|
|
+ </t-dropdown>
|
|
|
+ <Edit2Icon
|
|
|
+ class="mr-12"
|
|
|
+ @click="editNetwork(node.data, node.data.tem_index)"
|
|
|
+ />
|
|
|
+ <DeleteIcon
|
|
|
+ class="mr-8"
|
|
|
+ @click="
|
|
|
+ deleteNetwork(node.data.tem_index);
|
|
|
+ node.remove();
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </t-tree>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ id="dragElem-network"
|
|
|
+ style="position: absolute; left: 0; z-index: -999"
|
|
|
+ v-if="data.networks.length"
|
|
|
+ >
|
|
|
+ <div v-for="item in data.networks">
|
|
|
+ <div
|
|
|
+ class="flex mt-4"
|
|
|
+ v-for="(prop, i) in item.children"
|
|
|
+ v-show="networksCheked.includes(prop.value)"
|
|
|
+ >
|
|
|
+ <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
|
|
|
+ <div class="ml-4">{{ prop.mock }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div v-if="data.http_networks?.length">
|
|
|
+ <div class="flex mt-16 between" style="height: 32px; line-height: 32px">
|
|
|
+ <div class="flex">
|
|
|
+ <ControlPlatformIcon class="tree-icon mt-8" />
|
|
|
+ <div class="ml-8">HTTP</div>
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ :draggable="data.checkAll ? true : false"
|
|
|
+ @dragstart="onAddShape($event, data.networks,'network')"
|
|
|
+ @dragend="onAddShapeEnd"
|
|
|
+ >
|
|
|
+ <t-tree
|
|
|
+ :draggable="false"
|
|
|
+ class="ml-16"
|
|
|
+ v-model="networksCheked"
|
|
|
+ ref="httpTree"
|
|
|
+ :key="httpTreeKey"
|
|
|
+ style="overflow-y: hidden"
|
|
|
+ activeMultiple
|
|
|
+ :data="data.http_networks"
|
|
|
+ :expand-parent="true"
|
|
|
+ :checkable="data.checkAll"
|
|
|
+ :checkStrictly="false"
|
|
|
+ >
|
|
|
+ <template #operations="{ node }">
|
|
|
+ <template v-if="node.getParent()">
|
|
|
+ <Edit2Icon
|
|
|
+ class="mr-12"
|
|
|
+ @click="showAddData(node.getParent().data, node)"
|
|
|
+ />
|
|
|
+ <DeleteIcon
|
|
|
+ class="mr-8"
|
|
|
+ @click="
|
|
|
+ deleteData(node.getParent().data, node.getIndex());
|
|
|
+ node.remove();
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <t-dropdown :minColumnWidth="168" :hide-after-item-click="false">
|
|
|
+ <AddIcon class="mr-12" />
|
|
|
+ <t-dropdown-menu>
|
|
|
+ <t-dropdown-item
|
|
|
+ :value="2"
|
|
|
+ :divider="true"
|
|
|
+ @click="showAddData(node.data)"
|
|
|
+ >
|
|
|
+ 新建属性
|
|
|
+ </t-dropdown-item>
|
|
|
+ <t-dropdown-item :value="2" @click="importDataset(node.data)">
|
|
|
+ 从Excel导入
|
|
|
+ </t-dropdown-item>
|
|
|
+ <t-dropdown-item :value="4">
|
|
|
+ <a
|
|
|
+ :href="
|
|
|
+ isDownload
|
|
|
+ ? '/v/data.xlsx'
|
|
|
+ : cdn
|
|
|
+ ? cdn + '/v/data.xlsx?r=' + Math.random()
|
|
|
+ : '/data.xlsx'
|
|
|
+ "
|
|
|
+ style="color: var(--td-text-color-primary)"
|
|
|
+ @click.stop
|
|
|
+ >
|
|
|
+ 下载Excel示例
|
|
|
+ </a>
|
|
|
+ </t-dropdown-item>
|
|
|
+ </t-dropdown-menu>
|
|
|
+ </t-dropdown>
|
|
|
+ <Edit2Icon
|
|
|
+ class="mr-12"
|
|
|
+ @click="editNetwork(node.data, node.data.tem_index)"
|
|
|
+ />
|
|
|
+ <DeleteIcon
|
|
|
+ class="mr-8"
|
|
|
+ @click="
|
|
|
+ deleteNetwork(node.data.tem_index);
|
|
|
+ node.remove();
|
|
|
+ "
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </t-tree>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ id="dragElem-network"
|
|
|
+ style="position: absolute; left: 0; z-index: -999"
|
|
|
+ v-if="data.networks.length"
|
|
|
+ >
|
|
|
+ <div v-for="item in data.networks">
|
|
|
+ <div
|
|
|
+ class="flex mt-4"
|
|
|
+ v-for="(prop, i) in item.children"
|
|
|
+ v-show="networksCheked.includes(prop.value)"
|
|
|
+ >
|
|
|
+ <div style="width: 100px; text-align: end">{{ prop.label }}:</div>
|
|
|
+ <div class="ml-4">{{ prop.mock }}</div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div
|
|
|
+ class="flex column middle nodata"
|
|
|
+ v-if="!data.iotTree.length && !data.sqls.length && !data.networks.length"
|
|
|
+ >
|
|
|
+ <img src="/img/no-data.png" />
|
|
|
+ <div class="gray center">暂无数据</div>
|
|
|
+ <!-- <div class="mt-20">
|
|
|
+ <t-button theme="primary" @click="addNetwork()">
|
|
|
+ 添加数据源
|
|
|
+ </t-button>
|
|
|
+ </div> -->
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="content" v-if="group === '解析'">
|
|
|
+ <div class="flex between">
|
|
|
+ <div class="title">数据{{ group }}</div>
|
|
|
+ </div>
|
|
|
+ <div class="mt-8">
|
|
|
+ <CodeEditor
|
|
|
+ :key="data.randomkey"
|
|
|
+ v-model="data.socketCbJs"
|
|
|
+ style="min-height: 300px"
|
|
|
+ @change="onSocketCbJsChange"
|
|
|
+ />
|
|
|
+ <div class="data-full-icon hover">
|
|
|
+ <Fullscreen2Icon @click="showDataTransformation" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="mt-16">
|
|
|
+ 参考文档:
|
|
|
+ <a
|
|
|
+ target="_blank"
|
|
|
+ href="https://doc.le5le.com/document/136233394#%E8%A7%A3%E6%9E%90%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F"
|
|
|
+ >
|
|
|
+ 解析自定义格式数据</a
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <t-dialog
|
|
|
+ v-if="addDataDialog.show"
|
|
|
+ :visible="true"
|
|
|
+ class="data-dialog"
|
|
|
+ :header="addDataDialog.header"
|
|
|
+ @close="addDataDialog.show = false"
|
|
|
+ @confirm="onOkAddData"
|
|
|
+ >
|
|
|
+ <!-- <div class="form-item mt-16">
|
|
|
+ <label>设备</label>
|
|
|
+ <t-input v-model="addDataDialog.data.device" placeholder="设备名称" />
|
|
|
+ </div> -->
|
|
|
+ <div class="form-item mt-16">
|
|
|
+ <label>显示名称</label>
|
|
|
+ <t-input
|
|
|
+ @change="changeDataLabel($event)"
|
|
|
+ :value="addDataDialog.data.label"
|
|
|
+ placeholder="属性简短描述"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="form-item mt-16">
|
|
|
+ <label>属性名</label>
|
|
|
+ <t-input
|
|
|
+ @change="changeDataID($event)"
|
|
|
+ :value="addDataDialog.data.id"
|
|
|
+ placeholder="属性名"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <!-- <div class="form-item mt-16">
|
|
|
+ <label>类型</label>
|
|
|
+ <t-select
|
|
|
+ class="w-full"
|
|
|
+ :options="typeOptions"
|
|
|
+ v-model="addDataDialog.data.type"
|
|
|
+ placeholder="字符串"
|
|
|
+ @change="addDataDialog.data.value = null"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="form-item mt-16">
|
|
|
+ <label
|
|
|
+ >值范围
|
|
|
+ <t-tooltip content="可用做数据模拟" placement="top">
|
|
|
+ <HelpCircleIcon style="font-size: 12px" />
|
|
|
+ </t-tooltip>
|
|
|
+ </label>
|
|
|
+ <div class="w-full">
|
|
|
+ <t-input v-model="addDataDialog.data.mock" placeholder="值范围" />
|
|
|
+ <h6 class="desc mt-8" style="font-size: 12px">值范围说明</h6>
|
|
|
+ <ul class="desc ml-16" style="font-size: 12px">
|
|
|
+ <li>
|
|
|
+ <label class="inline" style="width: 80px">固定值:</label>
|
|
|
+ 直接填写,例如:10
|
|
|
+ </li>
|
|
|
+ <li>
|
|
|
+ <label class="inline" style="width: 80px">随机值:</label>
|
|
|
+ 值1,值2,...。例如:1,2,3,4,5
|
|
|
+ </li>
|
|
|
+ <li>
|
|
|
+ <label class="inline" style="width: 80px">范围数字:</label>
|
|
|
+ 最小值-最大值。例如:0-1.0 或 0-100
|
|
|
+ </li>
|
|
|
+ <li>
|
|
|
+ <label class="inline" style="width: 80px">随机字符串:</label>
|
|
|
+ [长度]。例如:[8]
|
|
|
+ </li>
|
|
|
+ </ul>
|
|
|
+ </div>
|
|
|
+ </div> -->
|
|
|
+ </t-dialog>
|
|
|
+ <t-dialog
|
|
|
+ v-if="networkDialog.show"
|
|
|
+ :visible="true"
|
|
|
+ width="800px"
|
|
|
+ class="data-dialog"
|
|
|
+ :header="networkDialog.header"
|
|
|
+ @close="networkDialog.show = false"
|
|
|
+ @confirm="onOkNetwork"
|
|
|
+ >
|
|
|
+ <template #footer>
|
|
|
+ <div class="flex mr-8" style="justify-content: end">
|
|
|
+ <!-- <t-checkbox v-model="networkDialog.save" class="mr-12">
|
|
|
+ 同时保存到我的数据源
|
|
|
+ </t-checkbox> -->
|
|
|
+ <t-button @click="onOkNetwork">确定</t-button>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <div style="max-height: 450px; padding: 8px; overflow-y: auto">
|
|
|
+ <Net v-model="networkDialog.network" />
|
|
|
+ </div>
|
|
|
+ </t-dialog>
|
|
|
+ <t-dialog
|
|
|
+ v-if="dataTransformationDialog.show"
|
|
|
+ :visible="true"
|
|
|
+ header="数据监听"
|
|
|
+ @confirm="onOkDataTransformation"
|
|
|
+ @close="dataTransformationDialog.show = false"
|
|
|
+ :width="800"
|
|
|
+ >
|
|
|
+ <CodeEditor v-model="dataTransformationDialog.data" style="height: 300px" />
|
|
|
+ <div class="mt-8">
|
|
|
+ 参考文档:
|
|
|
+ <a
|
|
|
+ target="_blank"
|
|
|
+ href="https://doc.le5le.com/document/136233394#%E8%A7%A3%E6%9E%90%E8%87%AA%E5%AE%9A%E4%B9%89%E6%95%B0%E6%8D%AE%E6%A0%BC%E5%BC%8F"
|
|
|
+ >
|
|
|
+ 解析自定义格式数据</a
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </t-dialog>
|
|
|
+ <t-dialog
|
|
|
+ v-if="sqlDialog.show"
|
|
|
+ :visible="true"
|
|
|
+ width="800px"
|
|
|
+ class="data-dialog"
|
|
|
+ :header="sqlDialog.header"
|
|
|
+ @close="sqlDialog.show = false"
|
|
|
+ @confirm="onOkSql"
|
|
|
+ >
|
|
|
+ <div style="max-height: 450px; padding: 8px">
|
|
|
+ <div class="form-item mt-8">
|
|
|
+ <label>sql数据源</label>
|
|
|
+ <t-select v-model="sqlDialog.sql.dbid" placeholder="请选择数据源">
|
|
|
+ <t-option
|
|
|
+ v-for="sql in sqlList"
|
|
|
+ @click="sqlChange(sql)"
|
|
|
+ :key="sql.id"
|
|
|
+ :value="sql.id"
|
|
|
+ :label="sql.name + '(' + sql.dbType + ')'"
|
|
|
+ />
|
|
|
+ </t-select>
|
|
|
+ </div>
|
|
|
+ <div class="form-item mt-8">
|
|
|
+ <label>sql轮询间隔</label>
|
|
|
+ <t-input-number
|
|
|
+ theme="column"
|
|
|
+ v-model="sqlDialog.sql.interval"
|
|
|
+ placeholder="不填,仅初始执行一次"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="form-item mt-8">
|
|
|
+ <label>查询方式</label>
|
|
|
+ <t-select v-model="sqlDialog.sql.method">
|
|
|
+ <t-option key="get" value="get" label="单条" />
|
|
|
+ <t-option key="list" value="list" label="列表" />
|
|
|
+ </t-select>
|
|
|
+ </div>
|
|
|
+ <div class="form-item mt-8">
|
|
|
+ <label>sql语句</label>
|
|
|
+ <CodeEditor
|
|
|
+ :json="false"
|
|
|
+ :language="'sql'"
|
|
|
+ v-model="sqlDialog.sql.sql"
|
|
|
+ class="mt-4"
|
|
|
+ style="height: 100px"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div v-if="sqlDialog.sql.method === 'list'" class="form-item mt-8">
|
|
|
+ <label>第几页</label>
|
|
|
+ <t-input-number
|
|
|
+ v-model="sqlDialog.sql.current"
|
|
|
+ theme="normal"
|
|
|
+ :min="1"
|
|
|
+ placeholder="默认1"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div v-if="sqlDialog.sql.method === 'list'" class="form-item mt-8">
|
|
|
+ <label>每页数量</label>
|
|
|
+ <t-input-number
|
|
|
+ v-model="sqlDialog.sql.pageSize"
|
|
|
+ theme="normal"
|
|
|
+ placeholder="默认20"
|
|
|
+ :min="1"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="form-item mt-8">
|
|
|
+ <label>关联属性名</label>
|
|
|
+ <t-input v-model="sqlDialog.sql.bindId" placeholder="关联属性名" />
|
|
|
+ </div>
|
|
|
+ <div class="flex mt-8">
|
|
|
+ <!-- <label> -->
|
|
|
+ <t-button style="width: 75px" @click="sqlTest">连接测试</t-button>
|
|
|
+ <!-- </label> -->
|
|
|
+ <p class="ml-8" style="width: 700px">{{ sqlDialog.result }}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </t-dialog>
|
|
|
+ <t-dialog
|
|
|
+ v-if="iotDialog.show"
|
|
|
+ :visible="true"
|
|
|
+ width="472px"
|
|
|
+ class="data-dialog"
|
|
|
+ :header="iotDialog.header"
|
|
|
+ @close="iotDialog.show = false"
|
|
|
+ @confirm="onOkIot"
|
|
|
+ >
|
|
|
+ <!-- <t-input
|
|
|
+ v-model="iotSearch"
|
|
|
+ @change="onSearchIot"
|
|
|
+ @enter="onSearchIot"
|
|
|
+ placeholder="设备属性搜索"
|
|
|
+ /> -->
|
|
|
+ <div class="input-search" style="padding: 0px 4px">
|
|
|
+ <div class="btn" style="left: 14px">
|
|
|
+ <img src="/img/icon_search_gray.svg" />
|
|
|
+ </div>
|
|
|
+ <t-input
|
|
|
+ style="height: 32px"
|
|
|
+ v-model="iotSearch"
|
|
|
+ @change="onSearchIot"
|
|
|
+ @enter="onSearchIot"
|
|
|
+ placeholder="搜索设备属性"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div style="height: 320px; margin-top: 8px; overflow-y: scroll">
|
|
|
+ <t-tree
|
|
|
+ style="overflow-y: hidden"
|
|
|
+ activeMultiple
|
|
|
+ v-model="checkedIots"
|
|
|
+ :data="iots"
|
|
|
+ :expand-parent="true"
|
|
|
+ :checkable="true"
|
|
|
+ :checkStrictly="false"
|
|
|
+ allow-fold-node-on-filter
|
|
|
+ :filter="iotFilter"
|
|
|
+ :scroll="{
|
|
|
+ // rowHeight: 34,
|
|
|
+ bufferSize: 10,
|
|
|
+ threshold: 10,
|
|
|
+ type: 'virtual',
|
|
|
+ }"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </t-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { reactive, defineComponent, ref, onMounted, toRaw, watch } from 'vue';
|
|
|
+import {
|
|
|
+ FileImportIcon,
|
|
|
+ FileExportIcon,
|
|
|
+ DeleteIcon,
|
|
|
+ AddIcon,
|
|
|
+ AddCircleIcon,
|
|
|
+ MinusCircleIcon,
|
|
|
+ Edit2Icon,
|
|
|
+ FileExcelIcon,
|
|
|
+ CloudDownloadIcon,
|
|
|
+ SearchIcon,
|
|
|
+ Fullscreen2Icon,
|
|
|
+ FullscreenExit1Icon,
|
|
|
+ HelpCircleIcon,
|
|
|
+ CaretDownSmallIcon,
|
|
|
+ CaretRightSmallIcon,
|
|
|
+ RouterWaveIcon,
|
|
|
+ ArrowUpDown3Icon,
|
|
|
+ Download1Icon,
|
|
|
+ ApplicationIcon,
|
|
|
+ DataIcon,
|
|
|
+ ControlPlatformIcon,
|
|
|
+} from 'tdesign-icons-vue-next';
|
|
|
+import { typeOptions } from '@/services/common';
|
|
|
+import { MessagePlugin } from 'tdesign-vue-next';
|
|
|
+import { Pen, deepClone } from '@meta2d/core';
|
|
|
+import { useDot } from '@/services/common';
|
|
|
+import { isDownload } from '@/services/defaults';
|
|
|
+import { cdn } from '@/services/api';
|
|
|
+import { importExcel, saveAsExcel } from '@/services/excel';
|
|
|
+import axios from 'axios';
|
|
|
+import { transformData } from '@/services/utils';
|
|
|
+import { debounce } from '@/services/debouce';
|
|
|
+import Net from '@/views/components/Net.vue';
|
|
|
+import CodeEditor from '@/views/components/common/CodeEditor.vue';
|
|
|
+import { s8 } from '@/services/random';
|
|
|
+import { useUser } from '@/services/user';
|
|
|
+import {
|
|
|
+ getSqlSourceList,
|
|
|
+ getDevices,
|
|
|
+ getDeviceProperties,
|
|
|
+ getMqttUrl,
|
|
|
+ doSqlCode,
|
|
|
+} from '@/services/iot';
|
|
|
+import { tree } from '@2d-components/domForm';
|
|
|
+
|
|
|
+const props = defineProps<{
|
|
|
+ group: string;
|
|
|
+}>();
|
|
|
+
|
|
|
+const { user } = useUser();
|
|
|
+
|
|
|
+const { dot, setDot } = useDot();
|
|
|
+
|
|
|
+const data = reactive({
|
|
|
+ //列表
|
|
|
+ datesetBak: {},
|
|
|
+ datasetId: '',
|
|
|
+ networks: [],
|
|
|
+ http_networks:[],
|
|
|
+ ws_networks:[],
|
|
|
+ mqtt_networks:[],
|
|
|
+ datasetList: [],
|
|
|
+ dataset: {
|
|
|
+ name: '',
|
|
|
+ id: '',
|
|
|
+ url: '',
|
|
|
+ devices: [],
|
|
|
+ } as any,
|
|
|
+ checkAll: false,
|
|
|
+ //获取
|
|
|
+ networkList: [],
|
|
|
+ input: '',
|
|
|
+ popupVisible: false,
|
|
|
+ networkId: '',
|
|
|
+
|
|
|
+ //监听
|
|
|
+ socketCbJs: '',
|
|
|
+ full: false,
|
|
|
+
|
|
|
+ dataMocks: [
|
|
|
+ // {
|
|
|
+ // name: '',
|
|
|
+ // id: '',
|
|
|
+ // enableMock: true,
|
|
|
+ // mock: 'aaa',
|
|
|
+ // type: 'string',
|
|
|
+ // expend: true,
|
|
|
+ // show: false,
|
|
|
+ // },
|
|
|
+ ],
|
|
|
+ enableMock: false,
|
|
|
+ randomkey: s8(),
|
|
|
+ sqls: [],
|
|
|
+ iotList: [],
|
|
|
+ iotTree: [],
|
|
|
+});
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ meta2d.store.data.networks?.forEach((network:any)=>
|
|
|
+ {
|
|
|
+ if(!network.label){
|
|
|
+ network.label = network.name;
|
|
|
+ }
|
|
|
+ if(!network.value){
|
|
|
+ network.value = s8();
|
|
|
+ }
|
|
|
+ network.checkable = false
|
|
|
+ });
|
|
|
+ data.networks = meta2d.store.data.networks || [];
|
|
|
+ data.dataset = (meta2d.store.data as any).dataset || {};
|
|
|
+ if( data.networks?.length&&data.dataset?.devices){
|
|
|
+ data.networks[0].children = deepClone(data.dataset.devices);
|
|
|
+ }
|
|
|
+ data.socketCbJs = meta2d.store.data.socketCbJs || '';
|
|
|
+ // data.dataMocks = meta2d.store.data.dataMocks || [];
|
|
|
+ data.enableMock = meta2d.store.data.enableMock || false;
|
|
|
+ // getNetworks();
|
|
|
+ // getDatasets();
|
|
|
+ // getIot();
|
|
|
+ data.sqls = meta2d.store.data.sqls || [];
|
|
|
+ data.iotList = meta2d.store.data.iot?.list || [];
|
|
|
+
|
|
|
+ data.iotTree = meta2d.store.data.iot?.tree || [];
|
|
|
+ getThirdNetwork();
|
|
|
+});
|
|
|
+
|
|
|
+const getThirdNetwork = (key?:string)=>{
|
|
|
+ if(!meta2d.store.data.networks?.length){
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ meta2d.store.data.networks.forEach((item:any,index)=>{
|
|
|
+ item.tem_index = index;
|
|
|
+ });
|
|
|
+ if(!key||key==='http'){
|
|
|
+ data.http_networks = meta2d.store.data.networks.filter((item)=>item.protocol==='http') || [];
|
|
|
+ }
|
|
|
+ if(!key||key==='websocket'){
|
|
|
+ data.ws_networks = meta2d.store.data.networks.filter((item)=>item.protocol==='websocket') || [];
|
|
|
+ }
|
|
|
+ if(!key||key==='mqtt'){
|
|
|
+ data.mqtt_networks = meta2d.store.data.networks.filter((item)=>item.protocol==='mqtt') || [];
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+const iotDialog = ref({
|
|
|
+ show: false,
|
|
|
+ header: '添加物联网平台',
|
|
|
+});
|
|
|
+
|
|
|
+const onOkIot = () => {
|
|
|
+ let _iots = [];
|
|
|
+ iots.value.forEach((item) => {
|
|
|
+ if (checkedIots.value.includes(item.value)) {
|
|
|
+ _iots.push(deepClone(item));
|
|
|
+ } else {
|
|
|
+ if (item.children?.length) {
|
|
|
+ const child = item.children.filter((child) =>
|
|
|
+ checkedIots.value.includes(child.value)
|
|
|
+ );
|
|
|
+ if (child.length) {
|
|
|
+ _iots.push({
|
|
|
+ label: item.label,
|
|
|
+ value: item.value,
|
|
|
+ deviceId: item.deviceId, //item.id
|
|
|
+ token: item.token,
|
|
|
+ children: deepClone(child),
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ data.iotTree = _iots;
|
|
|
+ if (!meta2d.store.data.iot) {
|
|
|
+ meta2d.store.data.iot = {};
|
|
|
+ }
|
|
|
+ meta2d.store.data.iot.tree = _iots;
|
|
|
+ iotDialog.value.show = false;
|
|
|
+};
|
|
|
+
|
|
|
+const onShowIot = async () => {
|
|
|
+ await getIotTree();
|
|
|
+ iotDialog.value.show = true;
|
|
|
+};
|
|
|
+
|
|
|
+const iots = ref([]);
|
|
|
+
|
|
|
+const getIotTree = async () => {
|
|
|
+ if (iots.value.length) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let ret = await getDevices();
|
|
|
+ const type = ret.type;
|
|
|
+ const list = ret.list;
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
+ const item = list[i];
|
|
|
+ item.label = item.name;
|
|
|
+ item.value = item.id;
|
|
|
+
|
|
|
+ item.deviceId = item.id; //item.id
|
|
|
+ item.token = item.token;
|
|
|
+ // item.children = true;
|
|
|
+ // item.checkable = false;
|
|
|
+ let properties = await getDeviceProperties(item.id);
|
|
|
+ item.children = properties.map((prop: any) => {
|
|
|
+ return {
|
|
|
+ label: prop.name,
|
|
|
+ value: type?prop.key:item.deviceId + '#' + prop.key,
|
|
|
+ _label: item.name + '#' + prop.name,
|
|
|
+ token: item.token,
|
|
|
+ class: 'iot',
|
|
|
+ };
|
|
|
+ });
|
|
|
+ if (!item.children.length) {
|
|
|
+ item.checkable = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // setTimeout(()=>{
|
|
|
+ iots.value = deepClone(list);
|
|
|
+ // },3000);
|
|
|
+};
|
|
|
+
|
|
|
+const iotSearch = ref('');
|
|
|
+const iotFilter = ref(null);
|
|
|
+const onSearchIot = () => {
|
|
|
+ iotFilter.value = iotSearch.value
|
|
|
+ ? (node) =>
|
|
|
+ node.data.label.indexOf(iotSearch.value) >= 0 ||
|
|
|
+ node.data.value.indexOf(iotSearch.value) >= 0
|
|
|
+ : null;
|
|
|
+};
|
|
|
+
|
|
|
+const checkedIots = ref([]);
|
|
|
+
|
|
|
+const onShowSql = async () => {
|
|
|
+ addSql();
|
|
|
+};
|
|
|
+const iotLoad = async (node) => {
|
|
|
+ let properties = await getDeviceProperties(node.value);
|
|
|
+ return properties.map((item: any) => {
|
|
|
+ item.label = item.name;
|
|
|
+ item.value = node.data.deviceId + '#' + item.key;
|
|
|
+ item._label = node.data.name + '#' + item.name;
|
|
|
+ // item.sn = item.sn;
|
|
|
+ item.token = node.data.token;
|
|
|
+ return item;
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const doBind = (node) => {
|
|
|
+};
|
|
|
+
|
|
|
+const iotMqtt = ref({});
|
|
|
+const iotProtocol = ref('');
|
|
|
+const getIot = async () => {
|
|
|
+ let canmqtt: any = await getMqttUrl();
|
|
|
+ if (canmqtt && canmqtt.host) {
|
|
|
+ iotMqtt.value = canmqtt;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (meta2d.store.data.iot) {
|
|
|
+ iotProtocol.value = meta2d.store.data.iot.protocol;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const selectIot = (protocol: any) => {
|
|
|
+ if (iotProtocol.value === protocol) {
|
|
|
+ meta2d.store.data.iot = {};
|
|
|
+ iotProtocol.value = '';
|
|
|
+ } else {
|
|
|
+ if (protocol === 'mqtt') {
|
|
|
+ meta2d.store.data.iot = {
|
|
|
+ protocol: protocol,
|
|
|
+ ...iotMqtt.value,
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ meta2d.store.data.iot = {
|
|
|
+ protocol: protocol,
|
|
|
+ // host: iotMqtt.value.host
|
|
|
+ };
|
|
|
+ }
|
|
|
+ iotProtocol.value = protocol;
|
|
|
+ }
|
|
|
+ meta2d.connectNetwork();
|
|
|
+};
|
|
|
+
|
|
|
+const addSql = async () => {
|
|
|
+ sqlList.value = await getSqlSourceList();
|
|
|
+ sqlDialog.header = '添加sql数据源';
|
|
|
+ sqlDialog.show = true;
|
|
|
+ sqlDialog.edit = false;
|
|
|
+ sqlDialog.sql = {
|
|
|
+ interval: undefined,
|
|
|
+ sql: '-- eg:SELECT * FROM "directory"',
|
|
|
+ };
|
|
|
+ sqlDialog.result = '';
|
|
|
+};
|
|
|
+
|
|
|
+const editSql = (sql: any, index: number) => {
|
|
|
+ sqlDialog.header = '编辑sql数据源';
|
|
|
+ sqlDialog.show = true;
|
|
|
+ sqlDialog.edit = true;
|
|
|
+ sqlDialog.index = index;
|
|
|
+ sqlDialog.sql = deepClone(sql);
|
|
|
+};
|
|
|
+
|
|
|
+const deleteSql = (index: number) => {
|
|
|
+ data.sqls.splice(index, 1);
|
|
|
+ (meta2d.store.data as any).sqls = data.sqls;
|
|
|
+ sqlTreeKey.value = s8();
|
|
|
+ setDot(true);
|
|
|
+};
|
|
|
+const sqlTreeKey = ref(s8());
|
|
|
+const onOkSql = async () => {
|
|
|
+ if (!sqlDialog.sql.dbid) {
|
|
|
+ MessagePlugin.error('请选择数据源');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!sqlDialog.sql.sql) {
|
|
|
+ MessagePlugin.error('请填写sql语句');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!sqlDialog.sql.interval) {
|
|
|
+ sqlDialog.sql.interval = undefined;
|
|
|
+ }
|
|
|
+ if (!sqlDialog.sql.bindId) {
|
|
|
+ MessagePlugin.error('关联属性名必填');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ sqlDialog.sql.label = sqlDialog.sql.bindId;
|
|
|
+ sqlDialog.sql.value = sqlDialog.sql.bindId;
|
|
|
+ // let sql = sqlDialog.value.sql+' LIMIT '+(sqlDialog.value.pageSize||20)+(sqlDialog.value.current>1?(' OFFSET '+(sqlDialog.value.current-1)*sqlDialog.value.pageSize):'');
|
|
|
+
|
|
|
+ if (!sqlDialog.sql.children) {
|
|
|
+ await sqlTest();
|
|
|
+ sqlTreeKey.value = s8();
|
|
|
+ }
|
|
|
+ if (!sqlDialog.edit) {
|
|
|
+ data.sqls.push(sqlDialog.sql);
|
|
|
+ // meta2d.store.data.sqls = data.sqls;
|
|
|
+ } else {
|
|
|
+ data.sqls[sqlDialog.index] = sqlDialog.sql;
|
|
|
+ }
|
|
|
+ meta2d.store.data.sqls = toRaw(data.sqls);
|
|
|
+ sqlTreeKey.value = s8();
|
|
|
+ // data.sqls = deepClone(data.sqls);
|
|
|
+ meta2d.connectNetwork();
|
|
|
+ sqlDialog.show = false;
|
|
|
+};
|
|
|
+
|
|
|
+const sqlDialog = reactive<any>({
|
|
|
+ show: false,
|
|
|
+ edit: false,
|
|
|
+ index: -1,
|
|
|
+ header: '添加sql数据源',
|
|
|
+ sql: {
|
|
|
+ interval: undefined,
|
|
|
+ sql: '',
|
|
|
+ },
|
|
|
+});
|
|
|
+const sqlList = ref([]);
|
|
|
+
|
|
|
+const sqlChange = (sql: any) => {
|
|
|
+ sqlDialog.sql.dbid = sql.id;
|
|
|
+ sqlDialog.sql.dbType = sql.dbType;
|
|
|
+ sqlDialog.sql.name = sql.name;
|
|
|
+};
|
|
|
+
|
|
|
+const sqlTest = async () => {
|
|
|
+ let ret: any = await doSqlCode(sqlDialog.sql);
|
|
|
+ if (ret.error) {
|
|
|
+ MessagePlugin.error('连接错误:' + ret.error);
|
|
|
+ sqlDialog.result = '连接错误:' + ret.error;
|
|
|
+ } else {
|
|
|
+ if (sqlDialog.sql.method === 'list') {
|
|
|
+ sqlDialog.result = '连接成功:[' + JSON.stringify(ret[0]) + ',...]';
|
|
|
+ // sqlDialog.sql.columns = ret[0];
|
|
|
+ const columnsKeys = Object.keys(ret[0]);
|
|
|
+ const children = new Array(ret.length).fill(0).map((item, index) => {
|
|
|
+ return {
|
|
|
+ label: index + 1 + '',
|
|
|
+ value: sqlDialog.sql.bindId + '#' + index,
|
|
|
+ _label: sqlDialog.sql.bindId + '#' + index + 1,
|
|
|
+ class: 'sql',
|
|
|
+ children: columnsKeys.map((key) => {
|
|
|
+ return {
|
|
|
+ label: key,
|
|
|
+ value: sqlDialog.sql.bindId + '#' + index + '#' + key,
|
|
|
+ _label: sqlDialog.sql.bindId + '#' + (index + 1) + '#' + key,
|
|
|
+ class: 'sql',
|
|
|
+ };
|
|
|
+ }),
|
|
|
+ };
|
|
|
+ });
|
|
|
+ sqlDialog.sql.class = 'sql';
|
|
|
+ sqlDialog.sql.children = children;
|
|
|
+ } else {
|
|
|
+ sqlDialog.result = '连接成功:' + JSON.stringify(ret);
|
|
|
+ // sqlDialog.sql.columns = ret;
|
|
|
+ const children = [];
|
|
|
+ for (let key in ret) {
|
|
|
+ children.push({
|
|
|
+ label: key,
|
|
|
+ value: sqlDialog.sql.bindId + '#' + key,
|
|
|
+ _label: sqlDialog.sql.bindId + '#' + key,
|
|
|
+ class: 'sql',
|
|
|
+ });
|
|
|
+ }
|
|
|
+ sqlDialog.sql.class = 'sql';
|
|
|
+ sqlDialog.sql.children = children;
|
|
|
+ }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const addDataDialog = reactive<any>({});
|
|
|
+
|
|
|
+const showAddData = (network: any, node?: any) => {
|
|
|
+ addDataDialog.network = network;
|
|
|
+ const row = node?.data;
|
|
|
+ const index = node?.getIndex();
|
|
|
+ addDataDialog.node = node;
|
|
|
+ if (row) {
|
|
|
+ addDataDialog.header = '编辑数据';
|
|
|
+ addDataDialog.data = JSON.parse(JSON.stringify(row));
|
|
|
+ addDataDialog.index = index;
|
|
|
+ } else {
|
|
|
+ addDataDialog.header = '添加数据';
|
|
|
+ addDataDialog.data = { type: 'string', expend: true };
|
|
|
+ }
|
|
|
+
|
|
|
+ addDataDialog.show = true;
|
|
|
+};
|
|
|
+
|
|
|
+const deleteData = (network: any, index: number) => {
|
|
|
+ network.children.splice(index, 1);
|
|
|
+ meta2d.store.data.networks = toRaw(data.networks);
|
|
|
+ // data.dataset.devices.splice(row, 1);
|
|
|
+ // (meta2d.store.data as any).dataset = data.dataset;
|
|
|
+ setDot(true);
|
|
|
+};
|
|
|
+
|
|
|
+const clearData = () => {
|
|
|
+ data.datasetId = undefined;
|
|
|
+ data.dataset.id = undefined;
|
|
|
+ data.dataset.name = undefined;
|
|
|
+ data.dataset.url = undefined;
|
|
|
+ data.dataset.devices = [];
|
|
|
+ setDot(true);
|
|
|
+};
|
|
|
+
|
|
|
+const changeDataLabel = (value) => {
|
|
|
+ if (!value) {
|
|
|
+ MessagePlugin.error('显示名称不能为空!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let item = data.dataset.devices?.filter((item) => item.label === value);
|
|
|
+ if (item && item.length) {
|
|
|
+ MessagePlugin.error('显示名称重复!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ addDataDialog.data.label = value;
|
|
|
+};
|
|
|
+
|
|
|
+const changeDataID = (value) => {
|
|
|
+ if (!value) {
|
|
|
+ MessagePlugin.error('属性名不能为空!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ let item = data.dataset.devices?.filter((item) => item.id === value);
|
|
|
+ if (item && item.length) {
|
|
|
+ MessagePlugin.error('属性名重复!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ addDataDialog.data.id = value;
|
|
|
+};
|
|
|
+
|
|
|
+const onOkAddData = () => {
|
|
|
+ if (!addDataDialog.data.label) {
|
|
|
+ MessagePlugin.error('请填写名称');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!addDataDialog.data.id) {
|
|
|
+ MessagePlugin.error('请填写数据ID');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!addDataDialog.network.children) {
|
|
|
+ addDataDialog.network.children = [];
|
|
|
+ }
|
|
|
+ addDataDialog.data.value = addDataDialog.data.id;
|
|
|
+ if (addDataDialog.header === '添加数据') {
|
|
|
+ addDataDialog.network.children.push(addDataDialog.data);
|
|
|
+ if(addDataDialog.network.protocol === 'http'){
|
|
|
+ httpTree.value.appendTo(addDataDialog.network.value, addDataDialog.data);
|
|
|
+ }else if(addDataDialog.network.protocol === 'websocket'){
|
|
|
+ wsTree.value.appendTo(addDataDialog.network.value, addDataDialog.data);
|
|
|
+ }else if(addDataDialog.network.protocol === 'mqtt'){
|
|
|
+ mqttTree.value.appendTo(addDataDialog.network.value, addDataDialog.data);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ // addDataDialog.network.children[addDataDialog.index] = addDataDialog.data;
|
|
|
+ addDataDialog.network.children.splice(
|
|
|
+ addDataDialog.index,
|
|
|
+ 1,
|
|
|
+ addDataDialog.data
|
|
|
+ );
|
|
|
+ addDataDialog.node?.insertAfter(deepClone(addDataDialog.data));
|
|
|
+ addDataDialog.node?.remove();
|
|
|
+ // mqttTreeKey.value = s8();
|
|
|
+ // wsTreeKey.value = s8();
|
|
|
+ // httpTreeKey.value = s8();
|
|
|
+ // networkTree.value.setItem(addDataDialog.network.value, {children:deepClone(addDataDialog.network.children)});
|
|
|
+ // addDataDialog.node?.setData(deepClone(addDataDialog.data));
|
|
|
+ //更新所有绑定该id的pen label
|
|
|
+ // let binds = meta2d.store.bind[addDataDialog.data.id];
|
|
|
+ // if (binds) {
|
|
|
+ // binds.forEach((item) => {
|
|
|
+ // const pen: Pen = meta2d.findOne(item.id);
|
|
|
+ // pen.realTimes &&
|
|
|
+ // pen.realTimes.forEach((_realTime) => {
|
|
|
+ // if (_realTime.key === item.key) {
|
|
|
+ // _realTime.bind.label = addDataDialog.data.label;
|
|
|
+ // }
|
|
|
+ // });
|
|
|
+ // });
|
|
|
+ // }
|
|
|
+ }
|
|
|
+ // (meta2d.store.data as any).dataset = data.dataset;
|
|
|
+ meta2d.store.data.networks = toRaw(data.networks);
|
|
|
+ addDataDialog.show = false;
|
|
|
+};
|
|
|
+
|
|
|
+const importDataset = async (network) => {
|
|
|
+ let columns: any = [
|
|
|
+ {
|
|
|
+ header: '设备',
|
|
|
+ key: 'device',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ header: '显示名称',
|
|
|
+ key: 'label',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ header: '属性名',
|
|
|
+ key: 'id',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ header: '类型',
|
|
|
+ key: 'type',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ header: '值范围',
|
|
|
+ key: 'mock',
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ const _data: any = await importExcel(columns);
|
|
|
+ _data.forEach((item) => {
|
|
|
+ if (item.device) {
|
|
|
+ item.label = item.device + '-' + item.label;
|
|
|
+ delete item.device;
|
|
|
+ }
|
|
|
+ item.value = item.id;
|
|
|
+ });
|
|
|
+ if (!network.children) {
|
|
|
+ network.children = [];
|
|
|
+ }
|
|
|
+ mergeDataset(network.children, _data);
|
|
|
+ if(network.protocol === 'http'){
|
|
|
+ httpTree.value.appendTo(network.value, network.children);
|
|
|
+ }else if(network.protocol === 'websocket'){
|
|
|
+ wsTree.value.appendTo(network.value, network.children);
|
|
|
+ }else if(network.protocol === 'mqtt'){
|
|
|
+ mqttTree.value.appendTo(network.value, network.children);
|
|
|
+ }
|
|
|
+ // networkTree.value.appendTo(network.value, network.children);
|
|
|
+ // (meta2d.store.data as any).dataset = data.dataset;
|
|
|
+};
|
|
|
+
|
|
|
+const downloadAsExcel = () => {
|
|
|
+ if (!(data.dataset.devices && data.dataset.devices.length)) {
|
|
|
+ MessagePlugin.error('属性列表不能为空!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const name = meta2d.store.data.name;
|
|
|
+ const columns: any[] = [
|
|
|
+ {
|
|
|
+ key: 'label',
|
|
|
+ header: '显示名称',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'id',
|
|
|
+ header: '属性名',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'type',
|
|
|
+ header: '类型',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: 'mock',
|
|
|
+ header: '值范围',
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ saveAsExcel(name, columns, data.dataset.devices);
|
|
|
+};
|
|
|
+
|
|
|
+const downloadAsJson = () => {
|
|
|
+ if (!(data.dataset.devices && data.dataset.devices.length)) {
|
|
|
+ MessagePlugin.error('属性列表不能为空!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ import('file-saver').then(({ saveAs }) => {
|
|
|
+ saveAs(
|
|
|
+ new Blob([JSON.stringify(data.dataset)], {
|
|
|
+ type: 'text/plain;charset=utf-8',
|
|
|
+ }),
|
|
|
+ `${data.dataset.name || '未命名'}.json`
|
|
|
+ );
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const onOkDataset = async (saveas = false) => {
|
|
|
+ // if (!dataDialog.dataset.name) {
|
|
|
+ // MessagePlugin.error('名称不能为空');
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+ if (!(data.dataset.devices && data.dataset.devices.length)) {
|
|
|
+ MessagePlugin.error('属性列表不能为空');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const dataset = JSON.parse(JSON.stringify(data.dataset));
|
|
|
+ let _data = dataset;
|
|
|
+ _data.type = 'dataset';
|
|
|
+ if (!_data.name) {
|
|
|
+ _data.name = meta2d.store.data.name;
|
|
|
+ }
|
|
|
+ _data = transformData(dataset, 'toNetwork');
|
|
|
+ // 保存到我的数据源
|
|
|
+ if (saveas || !dataset.id) {
|
|
|
+ delete dataset.id;
|
|
|
+ delete dataset._id;
|
|
|
+ dataset.type = 'dataset';
|
|
|
+ const ret: any = await axios.post(`/api/data/datasource/add`, _data);
|
|
|
+ if (!ret) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ ret.id = ret.id || ret._id;
|
|
|
+ data.datasetId = ret.id;
|
|
|
+ dataset.id = ret.id;
|
|
|
+ data.dataset.id = ret.id;
|
|
|
+ data.datasetList.push(dataset);
|
|
|
+ } else {
|
|
|
+ const ret: any = await axios.post(`/api/data/datasource/update`, _data);
|
|
|
+ if (!ret) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ data.datasetList.forEach((item: any, index: number) => {
|
|
|
+ if (
|
|
|
+ item.id === dataset.id ||
|
|
|
+ (item._id === dataset._id && dataset._id != undefined)
|
|
|
+ ) {
|
|
|
+ data.datasetList.splice(index, 1, dataset);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ delete dataset.devices;
|
|
|
+ // @ts-ignore
|
|
|
+ // meta2d.store.data.dataset = dataset;
|
|
|
+
|
|
|
+ // setDot(true);
|
|
|
+
|
|
|
+ data.editDataset = false;
|
|
|
+ delete data.datesetBak;
|
|
|
+};
|
|
|
+
|
|
|
+const mergeDataset = (arr1: any, arr2: any[]) => {
|
|
|
+ if (!(arr2 && arr2.length)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!arr1) {
|
|
|
+ arr1 = [];
|
|
|
+ }
|
|
|
+ arr2.forEach((item) => {
|
|
|
+ let index = arr1.findIndex((elem) => elem.id === item.id);
|
|
|
+ if (index >= 0) {
|
|
|
+ Object.assign(arr1[index], item);
|
|
|
+ } else {
|
|
|
+ arr1.push(item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const getDatas = async () => {
|
|
|
+ if (!data.dataset.url) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const ret = await axios.get(data.dataset.url);
|
|
|
+ let flattenRet = flattenTree(ret);
|
|
|
+ if (flattenRet) {
|
|
|
+ mergeDataset(data.dataset, flattenRet);
|
|
|
+ (meta2d.store.data as any).dataset = data.dataset;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+//展开树
|
|
|
+const flattenTree = (root) => {
|
|
|
+ if (!root) return []; // 空树返回空数组
|
|
|
+
|
|
|
+ const result = []; // 存储展开后的数组
|
|
|
+
|
|
|
+ // 递归遍历树
|
|
|
+ function dfs(node) {
|
|
|
+ result.push({
|
|
|
+ id: node.id,
|
|
|
+ label: node.label || node.name,
|
|
|
+ device: node.device || node.id,
|
|
|
+ type: node.type,
|
|
|
+ mock: node.mock,
|
|
|
+ // children: node.children,
|
|
|
+ }); // 将当前节点值添加到结果数组
|
|
|
+ // 遍历当前节点的子节点
|
|
|
+ if (node.children) {
|
|
|
+ for (let child of node.children) {
|
|
|
+ dfs(child); // 递归调用DFS
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ root.forEach((item) => {
|
|
|
+ dfs(item);
|
|
|
+ });
|
|
|
+ // dfs(root); // 从根节点开始遍历
|
|
|
+
|
|
|
+ return result;
|
|
|
+};
|
|
|
+
|
|
|
+const onSelDataset = async (datasetId = false) => {
|
|
|
+ if (datasetId) {
|
|
|
+ const dataset = data.datasetList.find((item: any) => {
|
|
|
+ return item.id === datasetId;
|
|
|
+ });
|
|
|
+
|
|
|
+ if (!dataset) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dataset.url) {
|
|
|
+ const ret = await axios.get(dataset.url);
|
|
|
+ if (ret) {
|
|
|
+ dataset.devices = ret;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ const ret = await axios.post(`/api/data/datasource/get`, {
|
|
|
+ id: dataset.id,
|
|
|
+ });
|
|
|
+ if (ret?.data) {
|
|
|
+ Object.assign(dataset, { ...ret.data });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ mergeDataset(data.dataset, dataset.devices);
|
|
|
+
|
|
|
+ (meta2d.store.data as any).dataset = data.dataset;
|
|
|
+ // dataDialog.dataset = dataset;
|
|
|
+
|
|
|
+ // if (!init) {
|
|
|
+ // const d = JSON.parse(JSON.stringify(dataset));
|
|
|
+ // delete d.devices;
|
|
|
+ // // @ts-ignore
|
|
|
+ // meta2d.store.data.dataset = d;
|
|
|
+
|
|
|
+ // setDot(true);
|
|
|
+ // }
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 请求我的数据模型
|
|
|
+const getDatasets = async (name?: string) => {
|
|
|
+ if (!user.id) {
|
|
|
+ MessagePlugin.error('请先登录');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const body: any = {
|
|
|
+ type: 'dataset',
|
|
|
+ projection: 'id,data,name,type',
|
|
|
+ };
|
|
|
+ if (name) {
|
|
|
+ body.name = name;
|
|
|
+ }
|
|
|
+ const ret: any = await axios.post(`/api/data/datasource/list`, body, {
|
|
|
+ params: {
|
|
|
+ current: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ },
|
|
|
+ });
|
|
|
+ if (ret?.list) {
|
|
|
+ const list = [];
|
|
|
+ let found = false;
|
|
|
+ for (const item of ret.list) {
|
|
|
+ item.id = item.id || item._id;
|
|
|
+ list.push(transformData(item, 'toMetaNetwork'));
|
|
|
+ if (data.dataset?.id === item.id) {
|
|
|
+ found = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (data.dataset?.id && !found) {
|
|
|
+ list.push(data.dataset);
|
|
|
+ }
|
|
|
+
|
|
|
+ data.datasetList = list;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const onDelDataset = async (item: any, i: number) => {
|
|
|
+ const ret: any = await axios.post(`/api/data/datasource/delete`, {
|
|
|
+ id: item.id,
|
|
|
+ });
|
|
|
+ if (
|
|
|
+ (meta2d.store.data as any).dataset &&
|
|
|
+ (meta2d.store.data as any).dataset.id === item.id
|
|
|
+ ) {
|
|
|
+ //@ts-ignore
|
|
|
+ meta2d.store.data.dataset = {};
|
|
|
+ data.dataset = {};
|
|
|
+ data.datasetId = undefined;
|
|
|
+ }
|
|
|
+ if (ret) {
|
|
|
+ data.datasetList.splice(i, 1);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const search = ref('');
|
|
|
+const onSearch = () => {
|
|
|
+ // if (!search.value) {
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+ data.dataset.devices.forEach((item) => {
|
|
|
+ if (
|
|
|
+ item.label.indexOf(search.value) !== -1 ||
|
|
|
+ item.id.indexOf(search.value) !== -1
|
|
|
+ ) {
|
|
|
+ item.show = true;
|
|
|
+ } else {
|
|
|
+ item.show = false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const onInputNetwork = (e) => {
|
|
|
+ debounce(getNetworks, 300, e);
|
|
|
+};
|
|
|
+
|
|
|
+const onSelectNetWork = (value) => {
|
|
|
+ if (!value) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const network: any = data.networks.find((elem: any) => value === elem.id);
|
|
|
+ if (!network) {
|
|
|
+ const item = data.networkList.find((elem: any) => value === elem.id);
|
|
|
+ data.networks.push(item);
|
|
|
+ meta2d.store.data.networks = toRaw(data.networks);
|
|
|
+ meta2d.connectNetwork();
|
|
|
+ setDot(true);
|
|
|
+ }
|
|
|
+ // data.input = null;
|
|
|
+ data.popupVisible = false;
|
|
|
+};
|
|
|
+
|
|
|
+// 请求我的实时数据
|
|
|
+const getNetworks = async (e?) => {
|
|
|
+ const ret: any = await axios.post(
|
|
|
+ `/api/data/datasource/list`,
|
|
|
+ {
|
|
|
+ // q: {
|
|
|
+ name: e,
|
|
|
+ // },
|
|
|
+ type: 'subscribe',
|
|
|
+ projection: 'id,data,name,type',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ params: {
|
|
|
+ current: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ },
|
|
|
+ }
|
|
|
+ );
|
|
|
+ if (ret?.list) {
|
|
|
+ const list = [];
|
|
|
+ for (const item of ret.list) {
|
|
|
+ item.id = item.id || item._id;
|
|
|
+ list.push(transformData(item, 'toMetaNetwork'));
|
|
|
+ }
|
|
|
+ data.networkList = list;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const onDelNetWork = async (item: any, i: number) => {
|
|
|
+ const ret: any = await axios.post(`/api/data/datasource/delete`, {
|
|
|
+ id: item.id || item._id,
|
|
|
+ });
|
|
|
+ if (ret) {
|
|
|
+ data.networkList.splice(i, 1);
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const networkTree = ref();
|
|
|
+const networkTreeKey = ref(s8());
|
|
|
+const mqttTree = ref();
|
|
|
+const mqttTreeKey = ref(s8());
|
|
|
+const wsTree = ref();
|
|
|
+const wsTreeKey = ref(s8());
|
|
|
+const httpTree = ref();
|
|
|
+const httpTreeKey = ref(s8());
|
|
|
+
|
|
|
+const deleteNetwork = (index: number) => {
|
|
|
+ data.networks.splice(index, 1);
|
|
|
+ meta2d.store.data.networks = toRaw(data.networks);
|
|
|
+ getThirdNetwork('xxx');
|
|
|
+ meta2d.connectNetwork();
|
|
|
+ setDot(true);
|
|
|
+};
|
|
|
+
|
|
|
+const networkDialog = reactive<any>({
|
|
|
+ save: true,
|
|
|
+});
|
|
|
+const editNetwork = (network: any, index: number) => {
|
|
|
+ networkDialog.network = JSON.parse(JSON.stringify(data.networks[index]));
|
|
|
+ networkDialog.editNetwork = 2;
|
|
|
+ networkDialog.editNetworkIndex = index;
|
|
|
+ networkDialog.header = `编辑${networkDialog.network.protocol}数据源`;
|
|
|
+ networkDialog.show = true;
|
|
|
+};
|
|
|
+
|
|
|
+const addNetwork = (protocol:string) => {
|
|
|
+ networkDialog.network = {
|
|
|
+ name: '',
|
|
|
+ type: 'subscribe',
|
|
|
+ protocol,
|
|
|
+ url: '',
|
|
|
+ options: {
|
|
|
+ clientId: '',
|
|
|
+ username: '',
|
|
|
+ password: '',
|
|
|
+ customClientId: false,
|
|
|
+ },
|
|
|
+ };
|
|
|
+ networkDialog.editNetwork = 1;
|
|
|
+ networkDialog.header = `添加${protocol}数据源`;
|
|
|
+ networkDialog.show = true;
|
|
|
+};
|
|
|
+
|
|
|
+const onOkNetwork = async () => {
|
|
|
+ const _data = transformData(networkDialog.network, 'toNetwork');
|
|
|
+ networkDialog.network.label = networkDialog.network.name;
|
|
|
+ // networkDialog.network.value = networkDialog.network.url;
|
|
|
+ networkDialog.network.value = s8();
|
|
|
+ networkDialog.network.checkable = false;
|
|
|
+ if (networkDialog.editNetwork === 1) {
|
|
|
+ if (
|
|
|
+ ['mqtt', 'websocket', 'http'].includes(networkDialog.network.protocol) &&
|
|
|
+ !networkDialog.network.url
|
|
|
+ ) {
|
|
|
+ MessagePlugin.error('URL地址不能为空!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!networkDialog.network.name) {
|
|
|
+ MessagePlugin.error('名称不能为空!');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // if (networkDialog.save) {
|
|
|
+ // const ret: any = await axios.post(`/api/data/datasource/add`, _data);
|
|
|
+ // if (!ret) {
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+ // ret.id = ret.id || ret._id;
|
|
|
+ // networkDialog.network.id = ret.id;
|
|
|
+ // }
|
|
|
+ data.networks.push(networkDialog.network);
|
|
|
+ // getThirdNetwork(networkDialog.network.protocol);
|
|
|
+ // data.networkList.push(networkDialog.network);
|
|
|
+ // networkTree.value?.appendTo('', networkDialog.network);
|
|
|
+ } else if (networkDialog.editNetwork === 2) {
|
|
|
+ // if (networkDialog.save) {
|
|
|
+ // const ret: any = await axios.post(`/api/data/datasource/update`, _data);
|
|
|
+ // if (!ret) {
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+ //替换
|
|
|
+ let index = networkDialog.editNetworkIndex;
|
|
|
+ if (index !== undefined) {
|
|
|
+ data.networks.splice(index, 1, networkDialog.network);
|
|
|
+ // getThirdNetwork(networkDialog.network.protocol);
|
|
|
+ // networkTreeKey.value = s8();
|
|
|
+ if(networkDialog.network.protocol==='http'){
|
|
|
+ httpTreeKey.value = s8();
|
|
|
+ }else if(networkDialog.network.protocol==='websocket'){
|
|
|
+ wsTreeKey.value = s8();
|
|
|
+ }else if(networkDialog.network.protocol==='mqtt'){
|
|
|
+ mqttTreeKey.value = s8();
|
|
|
+ }
|
|
|
+ // networkTree.value.setItem(networkDialog.network.value,networkDialog.network);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ networkDialog.show = false;
|
|
|
+ networkDialog.editNetwork = 0;
|
|
|
+ meta2d.store.data.networks = toRaw(data.networks);
|
|
|
+ getThirdNetwork(networkDialog.network.protocol);
|
|
|
+ meta2d.connectNetwork();
|
|
|
+ setDot(true);
|
|
|
+};
|
|
|
+
|
|
|
+const dataTransformationDialog = reactive<any>({
|
|
|
+ show: false,
|
|
|
+ data: '',
|
|
|
+});
|
|
|
+
|
|
|
+const showDataTransformation = () => {
|
|
|
+ dataTransformationDialog.data = meta2d.store.data.socketCbJs;
|
|
|
+ dataTransformationDialog.show = true;
|
|
|
+};
|
|
|
+
|
|
|
+const onOkDataTransformation = () => {
|
|
|
+ meta2d.store.data.socketCbJs = dataTransformationDialog.data;
|
|
|
+ data.randomkey = s8();
|
|
|
+ data.socketCbJs = dataTransformationDialog.data;
|
|
|
+ meta2d.listenSocket();
|
|
|
+ dataTransformationDialog.show = false;
|
|
|
+};
|
|
|
+
|
|
|
+let timer: any = 0;
|
|
|
+
|
|
|
+const onSocketCbJsChange = (e) => {
|
|
|
+ clearTimeout(timer);
|
|
|
+ timer = setTimeout(() => {
|
|
|
+ meta2d.store.data.socketCbJs = data.socketCbJs;
|
|
|
+ meta2d.listenSocket();
|
|
|
+ }, 3000);
|
|
|
+};
|
|
|
+
|
|
|
+const onChangeMock = () => {
|
|
|
+ // @ts-ignore
|
|
|
+ data.enableMock = !data.enableMock;
|
|
|
+ meta2d.store.data.enableMock = data.enableMock;
|
|
|
+ if (data.enableMock) {
|
|
|
+ meta2d.startDataMock();
|
|
|
+ } else {
|
|
|
+ meta2d.stopDataMock();
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const onCheckAllChange = (e) => {
|
|
|
+ if (!e) {
|
|
|
+ data.dataset?.devices?.forEach((item) => {
|
|
|
+ item.checked = false;
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const allChecked = ref([]);
|
|
|
+const networksCheked = ref([]);
|
|
|
+const sqlsCheked = ref([]);
|
|
|
+const onAddShape = (e, _data,type) => {
|
|
|
+ e.stopPropagation();
|
|
|
+ let data: any;
|
|
|
+ if (Array.isArray(_data)) {
|
|
|
+ const dragElem = document.getElementById(`dragElem-${type}`);
|
|
|
+ let width = dragElem.offsetWidth;
|
|
|
+ e.dataTransfer.setDragImage(dragElem, width / 2, 10);
|
|
|
+ const checked = [];
|
|
|
+ if(type === 'iot'){
|
|
|
+ _data.forEach((item) => {
|
|
|
+ item.children.forEach((_item) => {
|
|
|
+ if (allChecked.value.includes(_item.value)) {
|
|
|
+ checked.push(_item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }else if(type === 'network'){
|
|
|
+ _data.forEach((item) => {
|
|
|
+ item.children.forEach((_item) => {
|
|
|
+ if (networksCheked.value.includes(_item.value)) {
|
|
|
+ checked.push(_item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }else if(type === 'sql'){
|
|
|
+ _data.forEach((item) => {
|
|
|
+ item.children.forEach((_item) => {
|
|
|
+ if (sqlsCheked.value.includes(_item.value)) {
|
|
|
+ checked.push(_item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ });
|
|
|
+ }
|
|
|
+ // const checked = _data.filter((item) => item.checked);
|
|
|
+ if (!checked.length) {
|
|
|
+ MessagePlugin.error('请先选择数据');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ data = [];
|
|
|
+ checked.forEach((item) => {
|
|
|
+ let bind:any = {
|
|
|
+ class: 'iot',
|
|
|
+ id: item.value,
|
|
|
+ label: item._label,
|
|
|
+ token: item.token,
|
|
|
+ };
|
|
|
+ if(type === 'network'){
|
|
|
+ bind = {
|
|
|
+ id: item.id||item.value,
|
|
|
+ label: item.label,
|
|
|
+ }
|
|
|
+ }else if(type === 'sql'){
|
|
|
+ //TODO
|
|
|
+ bind = {
|
|
|
+ id: item.id||item.value,
|
|
|
+ label: item.label,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (globalThis.style1) {
|
|
|
+ data.push(
|
|
|
+ ...[
|
|
|
+ {
|
|
|
+ text: item.label,
|
|
|
+ width: 150,
|
|
|
+ height: 20,
|
|
|
+ name: 'text',
|
|
|
+ dataset: true,
|
|
|
+ textAlign: 'right',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: item.mock || 0,
|
|
|
+ width: 58,
|
|
|
+ height: 28,
|
|
|
+ name: 'rectangle',
|
|
|
+ dataset: true,
|
|
|
+ // textAlign: 'left',
|
|
|
+ color: '#478BFFFF',
|
|
|
+ textColor: '#A9C9FFFF',
|
|
|
+ background: '#478BFF1F',
|
|
|
+ fontWeight: 'bold',
|
|
|
+ borderRadius: 0.1,
|
|
|
+ lineWidth: 1,
|
|
|
+ realTimes: [
|
|
|
+ {
|
|
|
+ label: '文字',
|
|
|
+ key: 'text',
|
|
|
+ type: 'string',
|
|
|
+ bind: deepClone(item),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ data.push(
|
|
|
+ ...[
|
|
|
+ {
|
|
|
+ text: item.label + ':',
|
|
|
+ width: 150,
|
|
|
+ height: 28,
|
|
|
+ name: 'text',
|
|
|
+ dataset: true,
|
|
|
+ textAlign: 'right',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: item.mock,
|
|
|
+ width: 58,
|
|
|
+ height: 20,
|
|
|
+ name: 'text',
|
|
|
+ dataset: true,
|
|
|
+ textAlign: 'left',
|
|
|
+ realTimes: [
|
|
|
+ {
|
|
|
+ label: '文字',
|
|
|
+ key: 'text',
|
|
|
+ type: 'string',
|
|
|
+ bind: bind,
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ]
|
|
|
+ );
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ if (globalThis.style1) {
|
|
|
+ data = [
|
|
|
+ {
|
|
|
+ text: _data.label,
|
|
|
+ width: 150,
|
|
|
+ height: 28,
|
|
|
+ name: 'text',
|
|
|
+ dataset: true,
|
|
|
+ textAlign: 'right',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: _data.mock || 0,
|
|
|
+ width: 58,
|
|
|
+ height: 28,
|
|
|
+ name: 'rectangle',
|
|
|
+ dataset: true,
|
|
|
+ // textAlign: 'left',
|
|
|
+ color: '#478BFFFF',
|
|
|
+ textColor: '#A9C9FFFF',
|
|
|
+ background: '#478BFF1F',
|
|
|
+ fontWeight: 'bold',
|
|
|
+ borderRadius: 0.1,
|
|
|
+ lineWidth: 1,
|
|
|
+ realTimes: [
|
|
|
+ {
|
|
|
+ label: '文字',
|
|
|
+ key: 'text',
|
|
|
+ type: 'string',
|
|
|
+ bind: deepClone(_data),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ } else {
|
|
|
+ data = [
|
|
|
+ {
|
|
|
+ text: _data.label + ':',
|
|
|
+ width: 150,
|
|
|
+ height: 20,
|
|
|
+ name: 'text',
|
|
|
+ dataset: true,
|
|
|
+ textAlign: 'right',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ text: _data.mock,
|
|
|
+ width: 58,
|
|
|
+ height: 20,
|
|
|
+ name: 'text',
|
|
|
+ dataset: true,
|
|
|
+ textAlign: 'left',
|
|
|
+ realTimes: [
|
|
|
+ {
|
|
|
+ label: '文字',
|
|
|
+ key: 'text',
|
|
|
+ type: 'string',
|
|
|
+ bind: deepClone(_data),
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ },
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ meta2d.canvas.addCaches = deepClone(data);
|
|
|
+};
|
|
|
+
|
|
|
+const onAddShapeEnd = () => {
|
|
|
+ setTimeout(() => {
|
|
|
+ meta2d.initBinds();
|
|
|
+ }, 1000);
|
|
|
+};
|
|
|
+
|
|
|
+let lastIndex = -1;
|
|
|
+
|
|
|
+const onCheckChange = (e, i) => {
|
|
|
+ if (lastIndex > -1) {
|
|
|
+ if (e.shiftKey) {
|
|
|
+ let start = Math.min(i, lastIndex);
|
|
|
+ let end = Math.max(i, lastIndex);
|
|
|
+ data.dataset?.devices?.forEach((item, index) => {
|
|
|
+ if (index >= start && index <= end) {
|
|
|
+ item.checked = true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ e.stopPropagation();
|
|
|
+ e.preventDefault();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ lastIndex = i;
|
|
|
+};
|
|
|
+
|
|
|
+const checkChange = (e, device, i) => {
|
|
|
+ data.checkAll && (device.checked = !device.checked);
|
|
|
+ if (lastIndex > -1) {
|
|
|
+ if (e.shiftKey) {
|
|
|
+ let start = Math.min(i, lastIndex);
|
|
|
+ let end = Math.max(i, lastIndex);
|
|
|
+ data.dataset?.devices?.forEach((item, index) => {
|
|
|
+ if (index >= start && index <= end) {
|
|
|
+ item.checked = true;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+ lastIndex = i;
|
|
|
+};
|
|
|
+
|
|
|
+const onAddmock = (item: any) => {
|
|
|
+ if (data.dataMocks.find((elem) => elem.id === item.id)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ item.name = item.label;
|
|
|
+ data.dataMocks.push(deepClone(item));
|
|
|
+ (meta2d.store.data as any).dataMocks = data.dataMocks;
|
|
|
+ meta2d.startDataMock();
|
|
|
+};
|
|
|
+
|
|
|
+const onAddAllMock = () => {
|
|
|
+ if (!data.dataset.devices) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ data.dataset.devices.forEach((item) => {
|
|
|
+ if (data.dataMocks.find((elem) => elem.id === item.id)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ item.name = item.label;
|
|
|
+ data.dataMocks.push(deepClone(item));
|
|
|
+ });
|
|
|
+ (meta2d.store.data as any).dataMocks = data.dataMocks;
|
|
|
+ meta2d.startDataMock();
|
|
|
+};
|
|
|
+
|
|
|
+const deleteMock = (index: number) => {
|
|
|
+ data.dataMocks.splice(index, 1);
|
|
|
+ (meta2d.store.data as any).dataMocks = data.dataMocks;
|
|
|
+ setDot(true);
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="postcss" scoped>
|
|
|
+/* :deep(.data-input-box){
|
|
|
+ position: absolute;
|
|
|
+ left: 193px;
|
|
|
+ width: 501px;
|
|
|
+ top: 80px;
|
|
|
+} */
|
|
|
+.content {
|
|
|
+ background: var(--color-background-active);
|
|
|
+ padding: 16px;
|
|
|
+
|
|
|
+ .tree-icon {
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .prop-title {
|
|
|
+ white-space: nowrap;
|
|
|
+ overflow: hidden;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.t-collapse) {
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.t-collapse-panel__header) {
|
|
|
+ border: none;
|
|
|
+ font-size: 12px;
|
|
|
+ font-weight: 400;
|
|
|
+ padding: 8px 0px;
|
|
|
+ background: var(--color-background-active);
|
|
|
+ }
|
|
|
+ :deep(.t-collapse-panel__body) {
|
|
|
+ border: none;
|
|
|
+ }
|
|
|
+ :deep(.t-collapse-panel__content) {
|
|
|
+ background-color: var(--color-background-active);
|
|
|
+ color: var(--color);
|
|
|
+ padding: 8px 0px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-select {
|
|
|
+ height: 32px;
|
|
|
+ line-height: 32px;
|
|
|
+ color: #fff;
|
|
|
+ border: 1px solid var(--color-border);
|
|
|
+ border-radius: 4px;
|
|
|
+ padding: 0px 8px;
|
|
|
+ background-color: var(--color-background-input);
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ .btn-select-active {
|
|
|
+ background-color: var(--color-primary);
|
|
|
+ }
|
|
|
+
|
|
|
+ .input-search {
|
|
|
+ flex-shrink: 0;
|
|
|
+ color: #878f9c;
|
|
|
+ padding: 0px;
|
|
|
+ margin-top: 10px;
|
|
|
+
|
|
|
+ .btn {
|
|
|
+ background: #fff0;
|
|
|
+ left: 12px;
|
|
|
+
|
|
|
+ img {
|
|
|
+ background-color: #fff0;
|
|
|
+ margin-top: 9px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ :deep(.t-select) {
|
|
|
+ .t-input {
|
|
|
+ padding-left: 8px !important;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .select-search {
|
|
|
+ .t-input {
|
|
|
+ padding-left: 8px !important;
|
|
|
+
|
|
|
+ .t-icon {
|
|
|
+ font-size: 12px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .title {
|
|
|
+ height: 32px;
|
|
|
+ line-height: 32px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .title-span {
|
|
|
+ display: inline-block;
|
|
|
+ margin-left: 4px;
|
|
|
+ max-width: 108px;
|
|
|
+ overflow: hidden;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
+
|
|
|
+ .data-list {
|
|
|
+ /* padding: 12px 6px; */
|
|
|
+ /* background: var(--color-background-active); */
|
|
|
+ max-height: calc(100vh - 200px);
|
|
|
+ margin-bottom: 24px;
|
|
|
+ overflow-y: auto;
|
|
|
+
|
|
|
+ .data-title {
|
|
|
+ /* padding: 4px; */
|
|
|
+ }
|
|
|
+
|
|
|
+ .data-body {
|
|
|
+ margin-bottom: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .data-title-hover {
|
|
|
+ &:hover {
|
|
|
+ background: var(--color-background-input);
|
|
|
+ border-radius: 4px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ width: 234px;
|
|
|
+
|
|
|
+ & > div {
|
|
|
+ width: 218px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .data-mock-list {
|
|
|
+ height: auto;
|
|
|
+ max-height: calc(100vh - 220px);
|
|
|
+ }
|
|
|
+
|
|
|
+ .icon-box {
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ margin: 4px;
|
|
|
+ text-align: center;
|
|
|
+ line-height: 24px;
|
|
|
+ border-radius: 4px;
|
|
|
+
|
|
|
+ &:hover {
|
|
|
+ background: var(--td-brand-color-light);
|
|
|
+ }
|
|
|
+
|
|
|
+ .t-icon {
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .icon-item-box {
|
|
|
+ height: 30px;
|
|
|
+ line-height: 30px;
|
|
|
+ margin: 1px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .nodata {
|
|
|
+ padding-top: 50px;
|
|
|
+
|
|
|
+ img {
|
|
|
+ width: 80px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .gray {
|
|
|
+ margin-top: 8px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .t-button {
|
|
|
+ height: 24px;
|
|
|
+ padding-left: 8px;
|
|
|
+ padding-right: 8px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-line {
|
|
|
+ margin-left: 12px;
|
|
|
+ width: 11px;
|
|
|
+ /* height: 120px; */
|
|
|
+ /* border-bottom: 1px solid var(--color-background-input); */
|
|
|
+ /* border-left: 1px solid var(--color-background-input); */
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-data-item {
|
|
|
+ margin-left: 4px;
|
|
|
+ margin-top: 4px;
|
|
|
+
|
|
|
+ /* margin-right: 12px; */
|
|
|
+ label {
|
|
|
+ /* color: #ffffff80; */
|
|
|
+ height: 24px;
|
|
|
+ line-height: 24px;
|
|
|
+ width: 60px;
|
|
|
+ }
|
|
|
+
|
|
|
+ & > div {
|
|
|
+ width: 118px;
|
|
|
+ height: 24px;
|
|
|
+ line-height: 24px;
|
|
|
+ /* background: var(--color-background-input); */
|
|
|
+ border-radius: 4px;
|
|
|
+ /* color: #e3e8f459; */
|
|
|
+ padding-left: 8px;
|
|
|
+ padding-right: 8px;
|
|
|
+ overflow: hidden;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-mock-item {
|
|
|
+ & > div {
|
|
|
+ padding: 0px;
|
|
|
+
|
|
|
+ :deep(.t-input) {
|
|
|
+ height: 24px !important;
|
|
|
+ border: 0px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .form-swicth-item {
|
|
|
+ margin-left: 4px;
|
|
|
+
|
|
|
+ label {
|
|
|
+ /* color: #ffffff80; */
|
|
|
+ height: 24px;
|
|
|
+ width: 56px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .data-code {
|
|
|
+ width: 218px;
|
|
|
+
|
|
|
+ .code-editor {
|
|
|
+ height: 126px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .data-code-full {
|
|
|
+ position: absolute;
|
|
|
+ /* right: calc(50% - 250px); */
|
|
|
+ width: 100%;
|
|
|
+ height: 100vh;
|
|
|
+ background: var(--td-mask-active);
|
|
|
+ right: 0px;
|
|
|
+ top: 0px;
|
|
|
+
|
|
|
+ .code-editor {
|
|
|
+ width: 800px;
|
|
|
+ margin: 0 auto;
|
|
|
+ height: 80%;
|
|
|
+ margin-top: 16vh;
|
|
|
+ }
|
|
|
+
|
|
|
+ .data-full-icon {
|
|
|
+ .t-icon {
|
|
|
+ margin-right: calc(50% - 384px);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .data-full-icon {
|
|
|
+ margin-top: -20px;
|
|
|
+ /* z-index: 10000; */
|
|
|
+ position: relative;
|
|
|
+ display: flex;
|
|
|
+ justify-content: flex-end;
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ .t-icon {
|
|
|
+ margin-right: 16px;
|
|
|
+ cursor: pointer;
|
|
|
+ height: 16px;
|
|
|
+ width: 16px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ ul {
|
|
|
+ list-style-type: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+:deep(.t-tree) {
|
|
|
+ .t-tree__label {
|
|
|
+ font-size: 12px;
|
|
|
+ color: #bdc7db;
|
|
|
+ }
|
|
|
+ .t-tree__item[data-level='1'] {
|
|
|
+ padding: 0 0 0 16px;
|
|
|
+ .t-checkbox__label {
|
|
|
+ max-width: 50px;
|
|
|
+ overflow: hidden;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .t-tree__item[data-level='2'] {
|
|
|
+ padding: 0 0 0 16px;
|
|
|
+ .t-checkbox__label {
|
|
|
+ max-width: 50px;
|
|
|
+ overflow: hidden;
|
|
|
+ white-space: nowrap;
|
|
|
+ text-overflow: ellipsis;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .t-tree__item .t-icon {
|
|
|
+ color: #bdc7db;
|
|
|
+ }
|
|
|
+ .t-tree__label.t-is-checked {
|
|
|
+ background: none;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|
|
|
+<style lang="postcss">
|
|
|
+.menu-item-a {
|
|
|
+ &:hover {
|
|
|
+ color: var(--td-brand-color);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.network-option {
|
|
|
+ height: 100%;
|
|
|
+ padding: 0px;
|
|
|
+}
|
|
|
+</style>
|