197 lines
5.4 KiB
Vue
197 lines
5.4 KiB
Vue
<template>
|
||
<j-drawer :mask-closable="false" title="查看物模型" width="700" v-model:visible="_visible" destroy-on-close @close="close">
|
||
<template #extra>
|
||
<j-space>
|
||
<j-button type="primary" @click="handleExport">
|
||
导出
|
||
</j-button>
|
||
</j-space>
|
||
</template>
|
||
<j-spin :spinning="loading">
|
||
<div class="cat-content">
|
||
<p class="cat-tip">
|
||
物模型是对设备在云端的功能描述,包括设备的属性、服务和事件。物联网平台通过定义一种物的描述语言来描述物模型,称之为
|
||
TSL(即 Thing Specification Language),采用 JSON 格式,您可以根据 TSL
|
||
组装上报设备的数据。您可以导出完整物模型,用于云端应用开发。
|
||
</p>
|
||
</div>
|
||
<j-tabs @change="handleConvertMetadata" destroy-inactive-tab-pane>
|
||
<j-tab-pane v-for="item in codecs" :key="item.id" :tab="item.name">
|
||
<div class="cat-panel">
|
||
<JMonacoEditor v-model="monacoValue" lang="javascript" style="height: 100%" theme="vs"></JMonacoEditor>
|
||
</div>
|
||
</j-tab-pane>
|
||
</j-tabs>
|
||
</j-spin>
|
||
</j-drawer>
|
||
</template>
|
||
<script setup lang="ts" name="Cat">
|
||
import { downloadObject } from '@/utils/utils'
|
||
import { useInstanceStore } from '@/store/instance';
|
||
import { useProductStore } from '@/store/product';
|
||
import type { Key } from 'ant-design-vue/es/_util/type';
|
||
import { convertMetadata, getCodecs, detail as productDetail } from '@/api/device/product';
|
||
import { detail } from '@/api/device/instance'
|
||
import { onlyMessage } from '@/utils/comm';
|
||
import {cloneDeep} from "lodash";
|
||
import {omit} from "lodash-es";
|
||
|
||
interface Props {
|
||
visible: boolean;
|
||
type: 'product' | 'device';
|
||
}
|
||
interface Emits {
|
||
(e: 'update:visible', data: boolean): void;
|
||
}
|
||
const props = defineProps<Props>()
|
||
const emits = defineEmits<Emits>()
|
||
const route = useRoute()
|
||
const loading = ref(false)
|
||
|
||
const _visible = computed({
|
||
get: () => {
|
||
return props.visible;
|
||
},
|
||
set: (val: any) => {
|
||
emits('update:visible', val);
|
||
},
|
||
})
|
||
|
||
const close = () => {
|
||
emits('update:visible', false);
|
||
}
|
||
|
||
const instanceStore = useInstanceStore()
|
||
const productStore = useProductStore()
|
||
const metadata = computed(() => {
|
||
const metadataMap = {
|
||
product: productStore.current?.metadata as string,
|
||
device: instanceStore.current?.metadata as string,
|
||
};
|
||
return metadataMap[props.type];
|
||
})
|
||
// const metadata = metadataMap[props.type];
|
||
const value = ref(metadata.value)
|
||
const monacoValue = ref()
|
||
|
||
const handleExport = async () => {
|
||
try {
|
||
downloadObject(
|
||
JSON.parse(monacoValue.value),
|
||
`${props.type === 'device'
|
||
? instanceStore.current?.name
|
||
: productStore.current?.name
|
||
}-物模型`,
|
||
'YYYY/MM/DD',
|
||
);
|
||
} catch (e) {
|
||
onlyMessage('请先配置物模型', 'error');
|
||
}
|
||
}
|
||
|
||
const handleConvertMetadata = (key: Key) => {
|
||
if (key === 'alink') {
|
||
value.value = '';
|
||
monacoValue.value = '';
|
||
if (metadata) {
|
||
convertMetadata('to', 'alink', JSON.parse(metadata.value)).then(res => {
|
||
if (res.status === 200) {
|
||
value.value = JSON.stringify(res.result)
|
||
monacoValue.value = JSON.stringify(res.result)
|
||
}
|
||
});
|
||
}
|
||
} else {
|
||
value.value = metadata.value;
|
||
hideVirtualRule(metadata.value)
|
||
}
|
||
};
|
||
|
||
const codecs = ref<{ id: string; name: string }[]>()
|
||
|
||
const routeChange = async (id: string) => {
|
||
const res = await getCodecs()
|
||
if (res.status === 200) {
|
||
codecs.value = [{ id: 'jetlinks', name: '标准物模型' }].concat(res.result)
|
||
}
|
||
if (props.type === 'device' && id) {
|
||
detail(id as string).then((resp) => {
|
||
if (resp.status === 200) {
|
||
instanceStore.setCurrent(resp.result);
|
||
const _metadata = resp.result?.metadata;
|
||
value.value = _metadata;
|
||
hideVirtualRule(_metadata)
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|
||
// watch(
|
||
// () => route.params.id,
|
||
// (id) => routeChange(id as string),
|
||
// { immediate: true }
|
||
// )
|
||
|
||
const hideVirtualRule = (metadata: string) => {
|
||
const _metadata = JSON.parse(metadata || '{}')
|
||
if (_metadata.properties) {
|
||
_metadata.properties = _metadata.properties.map((item: any) => {
|
||
if (item.expands.virtualRule) {
|
||
item.expands = cloneDeep(omit(item.expands, ['virtualRule']))
|
||
}
|
||
return item
|
||
})
|
||
}
|
||
monacoValue.value = JSON.stringify(_metadata)
|
||
}
|
||
|
||
onMounted(() => {
|
||
routeChange(route.params.id as string)
|
||
})
|
||
|
||
watch(
|
||
() => [props.visible, props.type],
|
||
() => {
|
||
if (props.visible) {
|
||
loading.value = true
|
||
const { id } = route.params
|
||
if (props.type === 'device') {
|
||
detail(id as string).then((resp) => {
|
||
loading.value = false
|
||
instanceStore.setCurrent(resp.result)
|
||
value.value = resp.result.metadata
|
||
hideVirtualRule(resp.result.metadata)
|
||
});
|
||
} else {
|
||
productDetail(id as string).then((resp) => {
|
||
loading.value = false
|
||
productStore.setCurrent(resp.result)
|
||
value.value = resp.result.metadata
|
||
hideVirtualRule(resp.result.metadata)
|
||
});
|
||
}
|
||
}
|
||
},
|
||
{ immediate: true }
|
||
)
|
||
|
||
watch(() => metadata.value, () => {
|
||
hideVirtualRule(metadata.value)
|
||
}, { immediate: true})
|
||
</script>
|
||
<style scoped lang="less">
|
||
.cat-content {
|
||
background: #F6F6F6;
|
||
|
||
.cat-tip {
|
||
padding: 10px;
|
||
color: rgba(0, 0, 0, 0.55);
|
||
}
|
||
}
|
||
|
||
.cat-panel {
|
||
border: 1px solid #eeeeee;
|
||
height: 670px;
|
||
width: 650px;
|
||
}
|
||
</style> |