|
@@ -0,0 +1,532 @@
|
|
|
+<script setup lang="ts">
|
|
|
+import { onMounted, ref } from 'vue';
|
|
|
+import { message } from 'ant-design-vue';
|
|
|
+
|
|
|
+import { useRequest } from '@/hooks/request';
|
|
|
+import {
|
|
|
+ deviceGatewayUpdate,
|
|
|
+ gatewayLinkGetList,
|
|
|
+ gatewayLinkProtocolGatewayList,
|
|
|
+ orgGatewaySerialNumber,
|
|
|
+ postProtocolPageList,
|
|
|
+} from '@/api';
|
|
|
+
|
|
|
+import type { DefaultOptionType, SelectValue } from 'ant-design-vue/es/select';
|
|
|
+import type { Key } from 'ant-design-vue/es/table/interface';
|
|
|
+import type {
|
|
|
+ EquipmentInformationForm,
|
|
|
+ EquipmentUpdateForm,
|
|
|
+ InterfaceData,
|
|
|
+ ListEquipmentParametersItem,
|
|
|
+ PostProtocolPageItem,
|
|
|
+ SerialNumberItem,
|
|
|
+ UseGuideStepItemExpose,
|
|
|
+ UseGuideStepItemProps,
|
|
|
+} from '@/types';
|
|
|
+
|
|
|
+const columns = [
|
|
|
+ {
|
|
|
+ title: '关联网关参数',
|
|
|
+ dataIndex: 'index',
|
|
|
+ key: 'index',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '网关序列号',
|
|
|
+ dataIndex: 'snCode',
|
|
|
+ key: 'snCode',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '网关型号',
|
|
|
+ dataIndex: 'modelName',
|
|
|
+ key: 'modelName',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '物理接口',
|
|
|
+ dataIndex: 'linkName',
|
|
|
+ key: 'linkName',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '组号',
|
|
|
+ dataIndex: 'number',
|
|
|
+ key: 'interface',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '参数',
|
|
|
+ key: 'tags',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ key: 'action',
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+const devColumns = [
|
|
|
+ {
|
|
|
+ title: '序列号',
|
|
|
+ dataIndex: 'index',
|
|
|
+ key: 'index',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '设备参数编码',
|
|
|
+ dataIndex: 'deviceNum',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '设备参数名称',
|
|
|
+ dataIndex: 'deviceName',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '网关参数序号',
|
|
|
+ dataIndex: 'name',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '网关参数编码',
|
|
|
+ dataIndex: 'gatewayParamCode',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '单位',
|
|
|
+ dataIndex: 'unit',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '分组名称',
|
|
|
+ dataIndex: 'module',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ key: 'action',
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+const customizationColumns = [
|
|
|
+ {
|
|
|
+ title: '设备参数序号',
|
|
|
+ dataIndex: 'index',
|
|
|
+ key: 'index',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '设备参数编码',
|
|
|
+ dataIndex: 'name1',
|
|
|
+ key: 'name1',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '设备参数名称',
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '自定义公式',
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '保留小数位',
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '分组名称',
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '组别排序',
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '组内排序',
|
|
|
+ dataIndex: 'name',
|
|
|
+ key: 'name',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '是否过程数据',
|
|
|
+ dataIndex: 'switch',
|
|
|
+ key: 'switch',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '操作',
|
|
|
+ dataIndex: 'action',
|
|
|
+ key: 'action',
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+const protocolEquipmentColumns = [
|
|
|
+ {
|
|
|
+ title: '序列号',
|
|
|
+ dataIndex: 'index',
|
|
|
+ key: 'index',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '网关参数编码',
|
|
|
+ dataIndex: 'gatewayParamCode',
|
|
|
+ key: 'gatewayParamCode',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '网关参数名称',
|
|
|
+ dataIndex: 'paramName',
|
|
|
+ key: 'paramName',
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+interface GatewayList {
|
|
|
+ snCode: string;
|
|
|
+ modelName: string;
|
|
|
+ linkName: string;
|
|
|
+ divId: number;
|
|
|
+}
|
|
|
+const props = defineProps<UseGuideStepItemProps<EquipmentInformationForm>>();
|
|
|
+const gatewayList = ref<GatewayList[]>([]);
|
|
|
+const gatewayData = ref<PostProtocolPageItem[]>([]);
|
|
|
+const interfaceData = ref<InterfaceData[]>([]);
|
|
|
+
|
|
|
+const customizationData = ref([
|
|
|
+ {
|
|
|
+ index: 1,
|
|
|
+ switch: true,
|
|
|
+ name1: '123456',
|
|
|
+ },
|
|
|
+ {
|
|
|
+ index: 1,
|
|
|
+ switch: false,
|
|
|
+ name1: '789456',
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
+const { handleRequest } = useRequest();
|
|
|
+
|
|
|
+const listEquipmentParameters = ref<ListEquipmentParametersItem[]>([]);
|
|
|
+const chooselistEquipment = ref<ListEquipmentParametersItem[]>([]);
|
|
|
+const serialNumberItem = ref<SerialNumberItem[]>([]);
|
|
|
+const equipmentLsit = ref<Key[]>([]);
|
|
|
+const open = ref<boolean>(false);
|
|
|
+
|
|
|
+let gatewayId: number;
|
|
|
+const dataList: number[] = [];
|
|
|
+const equipmentList: EquipmentUpdateForm[] = [];
|
|
|
+
|
|
|
+const selectParameters = (value: string) => {
|
|
|
+ if (value) {
|
|
|
+ chooselistEquipment.value = [];
|
|
|
+ equipmentLsit.value = [];
|
|
|
+ handleRequest(async () => {
|
|
|
+ const { records } = await gatewayLinkProtocolGatewayList({
|
|
|
+ pageIndex: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ gatewayId,
|
|
|
+ });
|
|
|
+ listEquipmentParameters.value = records;
|
|
|
+ open.value = true;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ message.warning('请选择物理接口');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+const gatewayDelete = (index: number) => {
|
|
|
+ gatewayList.value.splice(index, 1);
|
|
|
+};
|
|
|
+
|
|
|
+const gatewayDevDelete = (index: number) => {
|
|
|
+ gatewayData.value.splice(index, 1);
|
|
|
+};
|
|
|
+
|
|
|
+const handleOk = () => {
|
|
|
+ handleRequest(async () => {
|
|
|
+ chooselistEquipment.value.forEach((item) => {
|
|
|
+ equipmentList.push({
|
|
|
+ deviceId: props.form.devId,
|
|
|
+ gatewayId,
|
|
|
+ gatewayProtocolId: item.id,
|
|
|
+ });
|
|
|
+ });
|
|
|
+
|
|
|
+ await deviceGatewayUpdate(equipmentList);
|
|
|
+
|
|
|
+ protocolPageData();
|
|
|
+ });
|
|
|
+
|
|
|
+ open.value = false;
|
|
|
+};
|
|
|
+
|
|
|
+const addEquipment = (index: number) => {
|
|
|
+ chooselistEquipment.value.splice(index, 1);
|
|
|
+ equipmentLsit.value.splice(index, 1);
|
|
|
+};
|
|
|
+
|
|
|
+const addGateway = () => {
|
|
|
+ handleRequest(async () => {
|
|
|
+ interfaceData.value = await gatewayLinkGetList(serialNumberItem.value[0].id);
|
|
|
+ gatewayList.value.push({
|
|
|
+ snCode: serialNumberItem.value[0].snCode,
|
|
|
+ modelName: serialNumberItem.value[0].modelName,
|
|
|
+ linkName: interfaceData.value.length ? interfaceData.value[0].linkName : '',
|
|
|
+ divId: serialNumberItem.value[0].id,
|
|
|
+ });
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const serialNumberAdd = (value: SelectValue, option: DefaultOptionType, index: number) => {
|
|
|
+ handleRequest(async () => {
|
|
|
+ gatewayId = option.id;
|
|
|
+ interfaceData.value = await gatewayLinkGetList(option.id);
|
|
|
+ gatewayList.value[index].modelName = option.modelName;
|
|
|
+ gatewayList.value[index].divId = option.id;
|
|
|
+ if (interfaceData.value.length) {
|
|
|
+ gatewayList.value[index].linkName = interfaceData.value.length ? interfaceData.value[0].linkName : '';
|
|
|
+ } else {
|
|
|
+ gatewayList.value[index].linkName = '';
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const rowSelectedChange = (selectedRowKeys: Key[], selectedRows: ListEquipmentParametersItem[]) => {
|
|
|
+ equipmentLsit.value = selectedRowKeys;
|
|
|
+ chooselistEquipment.value = selectedRows;
|
|
|
+};
|
|
|
+
|
|
|
+const protocolPageData = () => {
|
|
|
+ handleRequest(async () => {
|
|
|
+ gatewayList.value.forEach((item) => {
|
|
|
+ dataList.push(item.divId);
|
|
|
+ });
|
|
|
+ const { records } = await postProtocolPageList({
|
|
|
+ pageIndex: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ deviceIds: [props.form.devId],
|
|
|
+ gatewayIds: dataList,
|
|
|
+ });
|
|
|
+ if (records.length) {
|
|
|
+ if (gatewayData.value.length === 0) {
|
|
|
+ gatewayData.value = records;
|
|
|
+ } else {
|
|
|
+ // 数组合并去重
|
|
|
+ gatewayData.value = mergeAndDeduplicate([gatewayData.value, records]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+};
|
|
|
+
|
|
|
+const mergeAndDeduplicate = (arrays: [PostProtocolPageItem[], PostProtocolPageItem[]]) => {
|
|
|
+ return arrays.reduce((acc, curr) => {
|
|
|
+ curr.forEach((item) => {
|
|
|
+ // 使用 find 方法检查累加器数组中是否已存在具有相同 id 的对象
|
|
|
+ const existingItem = acc.find((existing) => existing.id === item.id);
|
|
|
+ // 如果不存在,则将该对象添加到累加器数组中
|
|
|
+ if (!existingItem) {
|
|
|
+ acc.push(item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return acc;
|
|
|
+ }, []);
|
|
|
+};
|
|
|
+
|
|
|
+const finish = () => {
|
|
|
+ protocolPageData();
|
|
|
+};
|
|
|
+
|
|
|
+defineExpose<UseGuideStepItemExpose>({
|
|
|
+ finish,
|
|
|
+});
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ handleRequest(async () => {
|
|
|
+ const { records } = await orgGatewaySerialNumber({
|
|
|
+ pageIndex: 1,
|
|
|
+ pageSize: 10,
|
|
|
+ });
|
|
|
+ serialNumberItem.value = records;
|
|
|
+ });
|
|
|
+});
|
|
|
+</script>
|
|
|
+
|
|
|
+<template>
|
|
|
+ <div style="width: 1092px">
|
|
|
+ <div>
|
|
|
+ <div class="use-guide-title">选择网关参数</div>
|
|
|
+ <div class="use-guide-description" style="margin-bottom: 40px">在设备铭牌上可以找到SN码和设备密码</div>
|
|
|
+ <ADivider />
|
|
|
+ </div>
|
|
|
+ <AFlex justify="space-between" style="margin-bottom: 15px">
|
|
|
+ <span class="header-text">关联网关参数</span>
|
|
|
+ <AButton ghost style="color: #32bac0; border-color: #32bac0" @click="addGateway">新增</AButton>
|
|
|
+ </AFlex>
|
|
|
+
|
|
|
+ <div>
|
|
|
+ <ATable :columns="columns" :data-source="gatewayList" :pagination="false">
|
|
|
+ <template #bodyCell="{ column, record, index }">
|
|
|
+ <template v-if="column.key === 'index'">
|
|
|
+ {{ index + 1 }}
|
|
|
+ </template>
|
|
|
+ <template v-if="column.key === 'snCode'">
|
|
|
+ <ASelect
|
|
|
+ size="large"
|
|
|
+ v-model:value="record.snCode"
|
|
|
+ style="width: 200px"
|
|
|
+ :options="serialNumberItem"
|
|
|
+ :field-names="{ label: 'snCode', value: 'id' }"
|
|
|
+ @change="(value, option) => serialNumberAdd(value, option, index)"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <template v-if="column.key === 'linkName'">
|
|
|
+ <ASelect
|
|
|
+ size="large"
|
|
|
+ v-model:value="record.linkName"
|
|
|
+ style="width: 200px"
|
|
|
+ :options="interfaceData"
|
|
|
+ :field-names="{ label: 'linkName', value: 'id' }"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <template v-if="column.key === 'tags'">
|
|
|
+ <span class="select-parameters" @click="selectParameters(record.linkName)">选择参数</span>
|
|
|
+ </template>
|
|
|
+ <template v-if="column.key === 'action'">
|
|
|
+ <AButton @click="gatewayDelete(index)">删除</AButton>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </ATable>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <AFlex justify="space-between" style="margin-top: 40px; margin-bottom: 15px">
|
|
|
+ <span class="header-text">关联网关参数</span>
|
|
|
+ <AButton ghost style="color: #32bac0; border-color: #32bac0">分组设置</AButton>
|
|
|
+ </AFlex>
|
|
|
+ <ATable :columns="devColumns" :data-source="gatewayData" :pagination="false">
|
|
|
+ <template #bodyCell="{ column, index }">
|
|
|
+ <template v-if="column.key === 'index'">
|
|
|
+ {{ index + 1 }}
|
|
|
+ </template>
|
|
|
+ <template v-else-if="column.key === 'action'">
|
|
|
+ <AButton @click="gatewayDevDelete(index)">删除</AButton>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </ATable>
|
|
|
+
|
|
|
+ <AFlex justify="space-between" style="margin-top: 40px; margin-bottom: 15px">
|
|
|
+ <span class="header-text">自定义监控参数</span>
|
|
|
+ <div>
|
|
|
+ <AButton ghost style="margin-right: 20px; color: #32bac0; border-color: #32bac0">新增</AButton>
|
|
|
+ <AButton ghost style="color: #32bac0; border-color: #32bac0">快速匹配</AButton>
|
|
|
+ </div>
|
|
|
+ </AFlex>
|
|
|
+
|
|
|
+ <ATable :columns="customizationColumns" :data-source="customizationData" :pagination="false">
|
|
|
+ <template #bodyCell="{ column, record, index }">
|
|
|
+ <template v-if="column.key === 'index'">
|
|
|
+ {{ index + 1 }}
|
|
|
+ </template>
|
|
|
+ <template v-else-if="column.key === 'switch'">
|
|
|
+ <ASwitch v-model:checked="record.switch" />
|
|
|
+ </template>
|
|
|
+ <template v-else-if="column.key === 'action'">
|
|
|
+ <AButton>删除</AButton>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </ATable>
|
|
|
+
|
|
|
+ <AModal
|
|
|
+ v-model:open="open"
|
|
|
+ title="选择网关协议参数"
|
|
|
+ @ok="handleOk"
|
|
|
+ width="920px"
|
|
|
+ :mask-closable="false"
|
|
|
+ :keyboard="false"
|
|
|
+ >
|
|
|
+ <div class="gateway-parameters">
|
|
|
+ <AFlex>
|
|
|
+ <div class="gateway-parameters-left">
|
|
|
+ <ATable
|
|
|
+ :row-selection="{
|
|
|
+ type: 'checkbox',
|
|
|
+ selectedRowKeys: equipmentLsit,
|
|
|
+ onChange: rowSelectedChange,
|
|
|
+ }"
|
|
|
+ row-key="id"
|
|
|
+ :columns="protocolEquipmentColumns"
|
|
|
+ :data-source="listEquipmentParameters"
|
|
|
+ :scroll="{ y: 380 }"
|
|
|
+ :pagination="false"
|
|
|
+ >
|
|
|
+ <template #bodyCell="{ column, index }">
|
|
|
+ <template v-if="column.key === 'index'">
|
|
|
+ {{ index + 1 }}
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </ATable>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div class="gateway-parameters-right">
|
|
|
+ <AFlex justify="space-between" style="width: 100%; padding-bottom: 24px">
|
|
|
+ <div>已选 ({{ equipmentLsit.length }}/80)</div>
|
|
|
+ <div style="margin-right: 10px">删除</div>
|
|
|
+ </AFlex>
|
|
|
+
|
|
|
+ <AFlex :vertical="true" class="main-container" style="height: 390px">
|
|
|
+ <AFlex
|
|
|
+ justify="space-between"
|
|
|
+ v-for="(item, index) in chooselistEquipment"
|
|
|
+ :key="item.id"
|
|
|
+ class="gateway-parameters-right-dev"
|
|
|
+ >
|
|
|
+ <span>{{ item.paramName }}</span>
|
|
|
+ <span style="margin-right: 2px; cursor: pointer" @click="addEquipment(index)">删除</span>
|
|
|
+ </AFlex>
|
|
|
+ </AFlex>
|
|
|
+ </div>
|
|
|
+ </AFlex>
|
|
|
+ </div>
|
|
|
+ </AModal>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.header-text {
|
|
|
+ margin-top: 5px;
|
|
|
+ font-size: 16px;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 600;
|
|
|
+ line-height: 24px;
|
|
|
+ color: #333;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+
|
|
|
+.select-parameters {
|
|
|
+ font-size: 14px;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 24px;
|
|
|
+ color: #32bac0;
|
|
|
+ text-align: left;
|
|
|
+ cursor: pointer;
|
|
|
+}
|
|
|
+
|
|
|
+.gateway-parameters {
|
|
|
+ width: 872px;
|
|
|
+ height: 473px;
|
|
|
+ margin-top: 24px;
|
|
|
+ background: #fff;
|
|
|
+ border: 1px solid #e4e7ed;
|
|
|
+ border-radius: 8px;
|
|
|
+}
|
|
|
+
|
|
|
+.gateway-parameters-left {
|
|
|
+ width: 572px;
|
|
|
+ padding: 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.gateway-parameters-right {
|
|
|
+ width: 298px;
|
|
|
+ padding: 24px 20px 24px 24px;
|
|
|
+}
|
|
|
+
|
|
|
+.gateway-parameters-right-dev {
|
|
|
+ width: 100%;
|
|
|
+ height: 24px;
|
|
|
+ margin-bottom: 24px;
|
|
|
+ font-size: 14px;
|
|
|
+ font-style: normal;
|
|
|
+ font-weight: 400;
|
|
|
+ line-height: 24px;
|
|
|
+ color: #666;
|
|
|
+ text-align: left;
|
|
|
+}
|
|
|
+</style>
|