737 lines
24 KiB
Vue
737 lines
24 KiB
Vue
<template>
|
|
<div class="metadata-base">
|
|
<EditTable
|
|
v-if="!heavyLoad"
|
|
ref="tableRef"
|
|
:data-source="dataSource"
|
|
:columns="columns"
|
|
:height="560"
|
|
:disableMenu="!hasOperate('add', type)"
|
|
:openGroup="type === 'properties'"
|
|
:rowSelection="{
|
|
selectedRowKeys: selectedRowKeys
|
|
}"
|
|
@scrollDown="scrollDown"
|
|
@rightMenuClick="rightMenuClick"
|
|
@groupEdit="groupEdit"
|
|
@groupDelete="groupDelete"
|
|
>
|
|
<template #extra="{ isFullscreen, fullScreenToggle }">
|
|
<div class="extra-header">
|
|
<div class="extra-left">
|
|
<a-space>
|
|
<Import
|
|
v-if="type === 'properties'"
|
|
:target="target"
|
|
:metadata="dataSource"
|
|
@ok="importMetadata"
|
|
/>
|
|
<span v-if="searchData.show">
|
|
已查询到
|
|
<span style="color: #ff7875">{{ searchData.len}}</span>
|
|
条相关数据
|
|
</span>
|
|
</a-space>
|
|
</div>
|
|
<div class="extra-center">
|
|
<div v-if="copyDetail.index" class="extra-copy-tip">
|
|
<div class="extra-copy-tip-context">
|
|
<span> 已复制 </span>
|
|
<template v-if="type === 'properties'">
|
|
<Ellipsis style="max-width: 120px">
|
|
{{ copyDetail.groupName }}
|
|
</Ellipsis>
|
|
<span >,</span>
|
|
</template>
|
|
<span>
|
|
第
|
|
{{ copyDetail.index }}
|
|
行
|
|
</span>
|
|
</div>
|
|
<div></div>
|
|
<div class="extra-copy-tip-icon" @click="copyDetail.index = 0">
|
|
<AIcon type="CloseOutlined" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="extra-right">
|
|
<a-button
|
|
@click="() => fullToggle(isFullscreen, fullScreenToggle)"
|
|
>
|
|
<template #icon>
|
|
<AIcon
|
|
:type="isFullscreen ? 'FullscreenExitOutlined' : 'FullscreenOutlined' "
|
|
/>
|
|
</template>
|
|
</a-button>
|
|
|
|
<PermissionButton
|
|
type="primary"
|
|
key="update"
|
|
placement="topRight"
|
|
:hasPermission="`${permission}:update`"
|
|
:loading="loading"
|
|
:disabled="hasOperate('add', type)"
|
|
:tooltip="{
|
|
title: hasOperate('add', type)
|
|
? '当前的存储方式不支持删改、新增'
|
|
: '保存',
|
|
placement: hasOperate('add', type) ? 'topRight' : 'top',
|
|
getPopupContainer: getPopupContainer,
|
|
}"
|
|
@click="handleSaveClick()"
|
|
>
|
|
保存
|
|
</PermissionButton>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template #bodyExtra v-if="hasOperate('add', type)">
|
|
<div class="noEdit-tip">
|
|
<div>
|
|
该设备受所属产品的存储策略影响,无法进行删改、新增操作
|
|
</div>
|
|
<div>
|
|
<a-button type="link" @click="jumpProduct" style="font-size: 20px;">修改存储策略</a-button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<template #id="{ record, index }">
|
|
<EditTableFormItem :name="[index, 'id']" @change="metadataChange">
|
|
<a-input v-model:value="record.id" placeholder="请输入标识" :disabled="record.expands?.isProduct"/>
|
|
</EditTableFormItem>
|
|
</template>
|
|
<template #name="{ record, index }">
|
|
<EditTableFormItem :name="[index, 'name']" @change="metadataChange">
|
|
<a-input v-model:value="record.name" placeholder="请输入名称" :disabled="record.expands?.isProduct"/>
|
|
</EditTableFormItem>
|
|
</template>
|
|
<template #valueType="{ record, index }">
|
|
<EditTableFormItem :name="[index, 'valueType']" @change="metadataChange">
|
|
<div style="display: flex; align-items: center" v-if="['properties', 'tags'].includes(type)">
|
|
<TypeSelect v-model:value="record.valueType.type" style="flex: 1 1 0;min-width: 0" :disabled="record.expands?.isProduct"/>
|
|
<IntegerParams v-if="['int', 'long'].includes(record.valueType.type)" v-model:value="record.valueType.unit" :disabled="record.expands?.isProduct"/>
|
|
<DoubleParams v-else-if="['float', 'double'].includes(record.valueType.type)" v-model:value="record.valueType" :disabled="record.expands?.isProduct"/>
|
|
<StringParams v-else-if="record.valueType.type === 'string'" v-model:value="record.valueType" :disabled="record.expands?.isProduct"/>
|
|
<DateParams v-else-if="record.valueType.type === 'date'" v-model:value="record.valueType.format" :disabled="record.expands?.isProduct"/>
|
|
<FileParams v-else-if="record.valueType.type === 'file'" v-model:value="record.valueType.bodyType" :disabled="record.expands?.isProduct"/>
|
|
<EnumParams v-else-if="record.valueType.type === 'enum'" v-model:value="record.valueType.elements" :disabled="record.expands?.isProduct"/>
|
|
<BooleanParams
|
|
v-else-if="record.valueType.type === 'boolean'"
|
|
v-model:falseText="record.valueType.falseText"
|
|
v-model:falseValue="record.valueType.falseValue"
|
|
v-model:trueText="record.valueType.trueText"
|
|
v-model:trueValue="record.valueType.trueValue"
|
|
:disabled="record.expands?.isProduct"
|
|
/>
|
|
<ObjectParams v-else-if="record.valueType.type === 'object'" v-model:value="record.valueType.properties" :disabled="record.expands?.isProduct"/>
|
|
<ArrayParams v-else-if="record.valueType.type === 'array'" v-model:value="record.valueType.elementType" :disabled="record.expands?.isProduct"/>
|
|
</div>
|
|
<div v-else-if="type === 'events'">
|
|
<ObjectParams v-model:value="record.valueType.properties">
|
|
<a-button type="primary" :disabled="record.expands?.isProduct" :danger="!record.valueType.properties?.length && record.id">
|
|
<template #icon>
|
|
<AIcon type="EditOutlined" :class="{'table-form-required-aicon': !record.valueType.properties?.length}"/>
|
|
</template>
|
|
配置
|
|
</a-button>
|
|
</ObjectParams>
|
|
</div>
|
|
</EditTableFormItem>
|
|
</template>
|
|
<template #expands="{ record, index }">
|
|
<EditTableFormItem :name="[index, 'expands']" @change="metadataChange">
|
|
<Source
|
|
v-if="props.type === 'properties'"
|
|
v-model:value="record.expands"
|
|
:isProduct="record.expands?.isProduct"
|
|
:target="target"
|
|
:record="record"
|
|
:disabled="record.expands?.isProduct"
|
|
/>
|
|
<a-select
|
|
v-else-if="props.type === 'events'"
|
|
v-model:value="record.expands.level"
|
|
style="width: 100%"
|
|
:options="EventLevel"
|
|
:getPopupContainer="(node) => tableRef.tableWrapperRef || node"
|
|
:disabled="record.expands?.isProduct"
|
|
/>
|
|
</EditTableFormItem>
|
|
</template>
|
|
<template #other="{ record }">
|
|
<div>
|
|
<OtherSetting
|
|
v-model:value="record.expands"
|
|
:type="['functions', 'events'].includes(props.type) ? 'object' : record.valueType?.type"
|
|
:id="record.id"
|
|
:name="record.name"
|
|
:metadataType="props.type"
|
|
:isProduct="record.expands?.isProduct"
|
|
:target="props.target"
|
|
:record="record"
|
|
:disabled="record.expands?.isProduct && !['int','long','float','double',].includes(record.valueType?.type)"
|
|
@change="metadataChange"
|
|
/>
|
|
</div>
|
|
</template>
|
|
<template #async="{ record }">
|
|
<BooleanSelect
|
|
v-model:value="record.async"
|
|
style="width: 100%"
|
|
trueLabel="是"
|
|
falseLabel="否"
|
|
:true-value="true"
|
|
:false-value="false"
|
|
:disabled="record.expands?.isProduct"
|
|
@change="metadataChange"
|
|
/>
|
|
</template>
|
|
<template #inputs="{ record, index }">
|
|
<EditTableFormItem :name="[index, 'inputs']" @change="metadataChange">
|
|
<ObjectParams v-model:value="record.inputs" :type="type">
|
|
<a-button type="primary" :disabled="record.expands?.isProduct">
|
|
<template #icon>
|
|
<AIcon type="EditOutlined" :class="{'table-form-required-aicon': !record.inputs.length}"/>
|
|
</template>
|
|
配置
|
|
</a-button>
|
|
</ObjectParams>
|
|
</EditTableFormItem>
|
|
</template>
|
|
<template #output="{ record, index }">
|
|
<EditTableFormItem :name="[index, 'output']" @change="metadataChange">
|
|
<div style="display: flex; align-items: center">
|
|
<TypeSelect v-model:value="record.output.type" style="flex: 1 1 0;min-width: 0" :disabled="record.expands?.isProduct"/>
|
|
<IntegerParams v-if="['int', 'long'].includes(record.output.type)" v-model:value="record.output.unit" :disabled="record.expands?.isProduct"/>
|
|
<DoubleParams v-else-if="['float', 'double'].includes(record.output.type)" v-model:value="record.output" :disabled="record.expands?.isProduct"/>
|
|
<StringParams v-else-if="record.output.type === 'string'" v-model:value="record.output.maxLength" :disabled="record.expands?.isProduct"/>
|
|
<DateParams v-else-if="record.output.type === 'date'" v-model:value="record.output.format" :disabled="record.expands?.isProduct"/>
|
|
<FileParams v-else-if="record.output.type === 'file'" v-model:value="record.output.bodyType" :disabled="record.expands?.isProduct"/>
|
|
<EnumParams v-else-if="record.output.type === 'enum'" v-model:value="record.output.elements" :disabled="record.expands?.isProduct"/>
|
|
<BooleanParams
|
|
v-else-if="record.output.type === 'boolean'"
|
|
v-model:falseText="record.output.falseText"
|
|
v-model:falseValue="record.output.falseValue"
|
|
v-model:trueText="record.output.trueText"
|
|
v-model:trueValue="record.output.trueValue"
|
|
:disabled="record.expands?.isProduct"
|
|
/>
|
|
<ObjectParams
|
|
v-else-if="record.output.type === 'object'"
|
|
v-model:value="record.output.properties"
|
|
:disabled="record.expands?.isProduct"
|
|
/>
|
|
<ArrayParams v-else-if="record.output.type === 'array'" v-model:value="record.output.elementType" :disabled="record.expands?.isProduct"/>
|
|
</div>
|
|
</EditTableFormItem>
|
|
</template>
|
|
<template #description="{ record }">
|
|
<a-input v-model:value="record.description" placeholder="请输入说明" :disabled="record.expands?.isProduct" @change="metadataChange"/>
|
|
</template>
|
|
<template #properties="{ record, index }">
|
|
<EditTableFormItem :name="[index, 'properties']" @change="metadataChange">
|
|
<ObjectParams v-model:value="record.valueType.properties" :disabled="record.expands?.isProduct"/>
|
|
</EditTableFormItem>
|
|
</template>
|
|
<template #group="{ record }">
|
|
<GroupSelect v-model:value="record.expands.group" :disabled="record.expands?.isProduct" @change="metadataChange"/>
|
|
</template>
|
|
</EditTable>
|
|
<div>
|
|
可编辑数据列表共 <span class="metadata-result-total">{{ effectiveDataLength }}</span> 条数据
|
|
</div>
|
|
<PropertiesModal
|
|
v-if="type === 'properties' && detailData.visible"
|
|
:data="detailData.data"
|
|
:type="target"
|
|
:getPopupContainer="getPopupContainer"
|
|
:unitOptions="unitOptions"
|
|
@cancel="cancelDetailModal"
|
|
/>
|
|
<FunctionModal
|
|
v-else-if="type === 'functions' && detailData.visible"
|
|
:data="detailData.data"
|
|
:getPopupContainer="getPopupContainer"
|
|
@cancel="cancelDetailModal"
|
|
/>
|
|
<EventModal
|
|
v-else-if="type === 'events' && detailData.visible"
|
|
:data="detailData.data"
|
|
:getPopupContainer="getPopupContainer"
|
|
@cancel="cancelDetailModal"
|
|
/>
|
|
<TagsModal
|
|
v-else-if="type === 'tags' && detailData.visible"
|
|
:data="detailData.data"
|
|
:getPopupContainer="getPopupContainer"
|
|
:unitOptions="unitOptions"
|
|
@cancel="cancelDetailModal"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts" name="MetadataBase">
|
|
import type {
|
|
MetadataItem,
|
|
MetadataType,
|
|
ProductItem,
|
|
} from '@/views/device/Product/typings';
|
|
import type {PropType} from 'vue';
|
|
import {TOKEN_KEY} from '@/utils/variable'
|
|
import {useRouter, onBeforeRouteUpdate} from 'vue-router'
|
|
import {useMetadata, useOperateLimits, useGroup} from './hooks';
|
|
import {useColumns, useSaveUnit} from './columns';
|
|
import {getMetadataItemByType, limitsMap} from './utils';
|
|
import {Source, OtherSetting} from './components';
|
|
import {saveProductVirtualProperty} from '@/api/device/product';
|
|
import {saveDeviceVirtualProperty} from '@/api/device/instance';
|
|
import {useInstanceStore} from '@/store/instance';
|
|
import {useProductStore} from '@/store/product';
|
|
import {asyncUpdateMetadata, updateMetadata} from '../metadata';
|
|
import {DeviceInstance} from '@/views/device/Instance/typings';
|
|
import {onlyMessage, LocalStore} from '@/utils/comm';
|
|
import {omit} from "lodash-es";
|
|
import {PropertiesModal, FunctionModal, EventModal, TagsModal} from './DetailModal'
|
|
import {Modal} from 'jetlinks-ui-components'
|
|
import {EventEmitter} from "@/utils/utils";
|
|
import {watch} from "vue";
|
|
import {useSystem} from "@/store/system";
|
|
import {useMenuStore} from "@/store/menu";
|
|
import {storeToRefs} from "pinia";
|
|
import {usePermissionStore} from '@/store/permission';
|
|
import {
|
|
EditTable,
|
|
TypeSelect,
|
|
IntegerParams,
|
|
StringParams,
|
|
DateParams,
|
|
FileParams,
|
|
EnumParams,
|
|
BooleanParams,
|
|
ObjectParams,
|
|
ArrayParams,
|
|
DoubleParams,
|
|
GroupSelect,
|
|
EditTableFormItem,
|
|
BooleanSelect
|
|
} from '@/components/Metadata/Table'
|
|
import {EventLevel} from "@/views/device/data";
|
|
import {message } from "ant-design-vue";
|
|
import { Import } from './components/Import'
|
|
|
|
const props = defineProps({
|
|
target: {
|
|
type: String as PropType<'device' | 'product'>,
|
|
default: 'product',
|
|
},
|
|
type: {
|
|
type: String as PropType<MetadataType>,
|
|
default: undefined,
|
|
},
|
|
permission: {
|
|
type: [String, Array] as PropType<string | string[]>,
|
|
default: undefined,
|
|
},
|
|
});
|
|
|
|
const _target = inject<'device' | 'product'>('_metadataType', props.target);
|
|
|
|
const system = useSystem();
|
|
const {basicLayout} = storeToRefs(system);
|
|
const router = useRouter()
|
|
|
|
const { unitOptions } = useSaveUnit()
|
|
|
|
const {data: metadata, noEdit, productNoEdit} = useMetadata(_target, props.type);
|
|
const {data: tagsMetadata} = useMetadata(_target, 'tags')
|
|
const {hasOperate} = useOperateLimits(_target);
|
|
|
|
const permissionStore = usePermissionStore()
|
|
const instanceStore = useInstanceStore()
|
|
const productStore = useProductStore()
|
|
|
|
const dataSource = ref<MetadataItem[]>(JSON.parse(JSON.stringify(metadata.value || '[]')) || []);
|
|
const tableRef = ref();
|
|
const loading = ref(false)
|
|
const editStatus = ref(false) // 编辑表格的编辑状态
|
|
const selectedRowKeys = ref<string[]>([])
|
|
|
|
const _isFullscreen = ref(false)
|
|
|
|
const copyDetail = reactive({
|
|
key: undefined,
|
|
index: 0,
|
|
groupName: undefined
|
|
})
|
|
|
|
const searchData = reactive({
|
|
len: 0,
|
|
show: false
|
|
})
|
|
|
|
const {initOptions} = useGroup()
|
|
|
|
const {columns} = useColumns(dataSource, props.type, _target, noEdit, productNoEdit)
|
|
|
|
const detailData = reactive({
|
|
data: {},
|
|
visible: false
|
|
})
|
|
|
|
const heavyLoad = ref<Boolean>(false)
|
|
|
|
const effectiveDataLength = computed(() => {
|
|
return dataSource.value.filter(item => item.id).length
|
|
})
|
|
|
|
const getPopupContainer = () => {
|
|
if (_isFullscreen.value) {
|
|
return tableRef.value.getTableWrapperRef() || document.body
|
|
}
|
|
return document.body
|
|
}
|
|
|
|
provide('_tagsDataSource', tagsMetadata)
|
|
provide('metadataSource', dataSource)
|
|
|
|
const cancelDetailModal = () => {
|
|
detailData.data = {}
|
|
detailData.visible = false
|
|
}
|
|
|
|
const operateLimits = (action: 'add' | 'updata', types: MetadataType) => {
|
|
return (
|
|
_target === 'device' &&
|
|
(instanceStore.detail.features || []).find((item: {
|
|
id: string;
|
|
name: string
|
|
}) => item.id === limitsMap.get(`${types}-${action}`))
|
|
);
|
|
};
|
|
|
|
// const handleSearch = (searchValue: string) => {
|
|
// const keys: string[] = []
|
|
// if (searchValue) {
|
|
// dataSource.value.forEach(item => {
|
|
// if (item.name && item.name.includes(searchValue)) {
|
|
// keys.push(item.id)
|
|
// }
|
|
// })
|
|
// }
|
|
//
|
|
// if (keys.length) {
|
|
// tableRef.value.scrollToById(keys[0])
|
|
// }
|
|
// selectedRowKeys.value = keys
|
|
//
|
|
// searchData.len = keys.length
|
|
// searchData.show = true
|
|
// };
|
|
|
|
const scrollDown = (len: number = 5) => {
|
|
if (!hasOperate('add', props.type)) {
|
|
dataSource.value.push(...(new Array(len).fill(1).map(() => getMetadataItemByType(props.type!))))
|
|
}
|
|
}
|
|
|
|
const rightMenuClick = (type: string, record: Record<string, any>, copyRecord: Record<string, any>) => {
|
|
const _index = record.__dataIndex
|
|
switch (type) {
|
|
case 'add':
|
|
dataSource.value.splice(_index + 1, 0, getMetadataItemByType(props.type!))
|
|
editStatus.value = true
|
|
nextTick(() => {
|
|
if (copyDetail.key) {
|
|
const copyItem = dataSource.value.find(item => item.__key === copyDetail.key)
|
|
copyDetail.index = copyItem!.__serial
|
|
copyDetail.groupName = copyItem!.expands.groupName
|
|
}
|
|
})
|
|
break;
|
|
case 'paste':
|
|
const cloneRecord = JSON.parse(JSON.stringify(copyRecord))
|
|
cloneRecord.id = `copy_${cloneRecord.id}`
|
|
if (props.type === 'properties') {
|
|
// 获取当前分组id和name
|
|
const expandsItem = dataSource.value[_index + 1].expands
|
|
cloneRecord.expands.groupName = expandsItem.groupName
|
|
cloneRecord.expands.groupId = expandsItem.groupId
|
|
}
|
|
|
|
if (record.id) {
|
|
dataSource.value.splice(_index + 1, 0, cloneRecord)
|
|
// Modal.confirm({
|
|
// title: '当前行存在数据',
|
|
// onOk() {
|
|
// dataSource.value.splice(_index, 1, cloneRecord)
|
|
// },
|
|
// onCancel() {
|
|
// console.log('Cancel');
|
|
// },
|
|
// })
|
|
} else {
|
|
dataSource.value.splice(_index, 1, cloneRecord)
|
|
}
|
|
|
|
editStatus.value = true
|
|
break;
|
|
case 'copy':
|
|
copyDetail.index = record.__serial
|
|
copyDetail.key = record.__key
|
|
copyDetail.groupName = dataSource.value[record.__dataIndex].expands.groupName
|
|
selectedRowKeys.value = [record.id]
|
|
break;
|
|
case 'detail':
|
|
detailData.data = record
|
|
detailData.visible = true
|
|
break;
|
|
case 'delete':
|
|
// Modal.confirm({
|
|
// title: `确认删除【${record.id}】?`,
|
|
// onOk() {
|
|
// dataSource.value.splice(_index, 1)
|
|
// },
|
|
// onCancel() {
|
|
// console.log('Cancel');
|
|
// },
|
|
// })
|
|
if (copyDetail.key === record.__key) {
|
|
copyDetail.key = undefined
|
|
copyDetail.groupName = undefined
|
|
copyDetail.index = 0
|
|
}
|
|
dataSource.value.splice(_index, 1)
|
|
editStatus.value = true
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
const handleSaveClick = async (next?: Function) => {
|
|
let resp = await tableRef.value.validate()
|
|
|
|
if (resp) {
|
|
const virtual: any[] = [];
|
|
const arr = resp.map((item: any) => {
|
|
if (item.expands?.virtualRule) {
|
|
const triggerProperties = item.expands.virtualRule.triggerProperties
|
|
const rule = omit(item.expands.virtualRule, ['triggerProperties'])
|
|
virtual.push({
|
|
triggerProperties,
|
|
rule,
|
|
type: rule.type,
|
|
propertyId: item.id
|
|
})
|
|
}
|
|
return {
|
|
...item,
|
|
expands: {
|
|
...omit(item.expands, ['virtualRule'])
|
|
}
|
|
}
|
|
// return item
|
|
})
|
|
// 保存规则
|
|
if (virtual.length) {
|
|
let res = undefined
|
|
if (_target === 'device') {
|
|
res = await saveDeviceVirtualProperty(instanceStore.current.productId, instanceStore.current.id, virtual)
|
|
} else {
|
|
res = await saveProductVirtualProperty(productStore.current.id, virtual)
|
|
}
|
|
}
|
|
// 保存属性
|
|
const updateStore = (metadata: string) => {
|
|
if (_target === 'device') {
|
|
const detail = instanceStore.current
|
|
detail.metadata = metadata
|
|
instanceStore.setCurrent(detail)
|
|
} else {
|
|
const detail = productStore.current || {} as ProductItem
|
|
detail.metadata = metadata
|
|
productStore.setCurrent(detail)
|
|
}
|
|
}
|
|
|
|
const _detail: ProductItem | DeviceInstance = _target === 'device' ? instanceStore.detail : productStore.current
|
|
let _data = updateMetadata(props.type!, arr, _detail, updateStore)
|
|
loading.value = true
|
|
|
|
const result = await asyncUpdateMetadata(_target, _data).finally(() => {
|
|
loading.value = false
|
|
})
|
|
if (result.success) {
|
|
// dataSource.value = resp
|
|
// tableRef.value.cleanEditStatus()
|
|
editStatus.value = false
|
|
message.config({
|
|
getContainer() {
|
|
return getPopupContainer()
|
|
}
|
|
})
|
|
onlyMessage('操作成功!')
|
|
next?.()
|
|
}
|
|
}
|
|
};
|
|
|
|
const metadataChange = () => {
|
|
editStatus.value = true
|
|
}
|
|
|
|
const jumpProduct = () => {
|
|
useMenuStore().jumpPage(
|
|
'device/Product/Detail', { id: instanceStore.detail.productId, tab: 'Device' }
|
|
)
|
|
}
|
|
|
|
const parentTabsChange = (next?: Function) => {
|
|
if (editStatus.value && permissionStore.hasPermission(`${props.permission}:update`) && LocalStore.get(TOKEN_KEY)) {
|
|
const modal = Modal.confirm({
|
|
content: '页面改动数据未保存',
|
|
okText: '保存',
|
|
cancelText: '不保存',
|
|
zIndex: 1400,
|
|
closable: true,
|
|
onOk: () => {
|
|
handleSaveClick(next as Function)
|
|
},
|
|
onCancel: (e: any) => {
|
|
if (!e.triggerCancel) { // 取消按钮
|
|
modal.destroy();
|
|
(next as Function)?.()
|
|
} else {// 右上角取消按钮
|
|
const paths = router.currentRoute.value.matched
|
|
// basicLayout.value.selectedKeys = paths.map(item => item.path)
|
|
basicLayout.value.openKeys = paths.map(item => item.path)
|
|
}
|
|
}
|
|
})
|
|
} else {
|
|
(next as Function)?.()
|
|
}
|
|
}
|
|
|
|
const fullToggle = (type: boolean, cb: Function) => {
|
|
cb()
|
|
_isFullscreen.value = !type
|
|
}
|
|
|
|
const groupEdit = (record: { value: string, label: string}) => {
|
|
dataSource.value.forEach(item => {
|
|
if (item.expands?.groupId === record.value) {
|
|
item.expands.groupName = record.label
|
|
}
|
|
})
|
|
}
|
|
|
|
const groupDelete = (id: string) => {
|
|
dataSource.value = dataSource.value.filter(item => item.expands?.groupId !== id || item.expands?.isProduct)
|
|
}
|
|
|
|
const importMetadata = (_metadata: any[]) => {
|
|
dataSource.value = _metadata
|
|
}
|
|
|
|
EventEmitter.subscribe(['MetadataTabs'], parentTabsChange)
|
|
|
|
onUnmounted(() => {
|
|
message.config({
|
|
getContainer() {
|
|
return document.body
|
|
},
|
|
})
|
|
EventEmitter.unSubscribe(['MetadataTabs'], parentTabsChange)
|
|
})
|
|
|
|
watch(() => metadata.value, () => {
|
|
dataSource.value = JSON.parse(JSON.stringify(metadata.value || '[]')).map(item => {
|
|
if (!item.expands) {
|
|
item['expands'] = {
|
|
group: undefined
|
|
}
|
|
}
|
|
if(props.type === 'functions' && !item.output){
|
|
item['output'] = {
|
|
|
|
}
|
|
}
|
|
return item
|
|
})
|
|
initOptions(dataSource.value)
|
|
}, {immediate: true})
|
|
|
|
onBeforeRouteUpdate((to, from, next) => { // 设备管理内路由跳转
|
|
parentTabsChange(next as Function)
|
|
})
|
|
|
|
onBeforeRouteLeave((to, from, next) => { // 设备管理外路由跳转
|
|
parentTabsChange(next as Function)
|
|
})
|
|
|
|
</script>
|
|
|
|
<style scoped lang="less">
|
|
.extra-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding-bottom: 16px;
|
|
position: relative;
|
|
}
|
|
|
|
.extra-right {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 12px;
|
|
}
|
|
|
|
.extra-copy-tip {
|
|
position: absolute;
|
|
display: flex;
|
|
align-items: center;
|
|
width: 300px;
|
|
justify-content: space-between;
|
|
padding: 8px 24px;
|
|
background-color: #fff;
|
|
box-shadow: 0px 6px 16px 0px rgba(0, 0, 0, 0.08),0px 3px 6px -4px rgba(0, 0, 0, 0.12),0px 9px 28px 8px rgba(0, 0, 0, 0.05);
|
|
font-size: 14px;
|
|
transform: translateX(-150px);
|
|
|
|
.extra-copy-tip-icon {
|
|
font-size: 12px;
|
|
color: rgba(0, 0, 0, 0.45);
|
|
}
|
|
|
|
.extra-copy-tip-context {
|
|
display: flex;
|
|
gap: 4px;
|
|
}
|
|
}
|
|
|
|
.noEdit-tip {
|
|
position: absolute;
|
|
display: flex;
|
|
flex-direction: column;
|
|
top: 0;
|
|
left: 0;
|
|
right: 0;
|
|
bottom: 0;
|
|
font-size: 22px;
|
|
color: #6f6f6f;
|
|
justify-content: center;
|
|
align-items: center
|
|
}
|
|
|
|
.metadata-base {
|
|
:deep(.ant-message) {
|
|
z-index: 1073;
|
|
}
|
|
}
|
|
|
|
.metadata-result-total {
|
|
color: @primary-color;
|
|
}
|
|
</style>
|