fix: 物模型属性开发
This commit is contained in:
parent
11e9d6faf9
commit
0b090cf818
|
@ -166,3 +166,13 @@ export const saveDevice = (data:any) => server.post('/device-product',data)
|
||||||
* 更新选择设备(设备接入)
|
* 更新选择设备(设备接入)
|
||||||
*/
|
*/
|
||||||
export const updateDevice = (data:any) => server.patch('/device-product',data)
|
export const updateDevice = (data:any) => server.patch('/device-product',data)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取操作符
|
||||||
|
*/
|
||||||
|
export const getOperator = () => server.get<OperatorItem>('/property-calculate-rule/description')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取聚合函数列表
|
||||||
|
*/
|
||||||
|
export const getStreamingAggType = () => server.get<Record<string, string>[]>('/dictionary/streaming-agg-type/items')
|
|
@ -3,6 +3,7 @@
|
||||||
<div class="advance-box">
|
<div class="advance-box">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<Editor
|
<Editor
|
||||||
|
ref="editor"
|
||||||
mode="advance"
|
mode="advance"
|
||||||
key="advance"
|
key="advance"
|
||||||
v-model:value="_value"
|
v-model:value="_value"
|
||||||
|
@ -16,7 +17,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<Operator :id="id" />
|
<Operator :id="id" @add-operator-value="addOperatorValue"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a-modal>
|
</a-modal>
|
||||||
|
@ -44,10 +45,15 @@ const handleCancel = () => {
|
||||||
emit('change', 'simple')
|
emit('change', 'simple')
|
||||||
}
|
}
|
||||||
const handleOk = () => {
|
const handleOk = () => {
|
||||||
|
console.log(_value.value)
|
||||||
emit('update:value', _value.value)
|
emit('update:value', _value.value)
|
||||||
emit('change', 'simple')
|
emit('change', 'simple')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const editor = ref()
|
||||||
|
const addOperatorValue = (val: string) => {
|
||||||
|
editor.value.addOperatorValue(val)
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="top">
|
<div class="top">
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<span v-for="item in symbolList.filter((t: SymbolType, i: number) => i <= 3)" :key="item.key"
|
<span v-for="item in symbolList.filter((t: SymbolType, i: number) => i <= 3)" :key="item.key"
|
||||||
@click="handleInsertCode(item.value)">
|
@click="addOperatorValue(item.value)">
|
||||||
{{ item.value }}
|
{{ item.value }}
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<template #overlay>
|
<template #overlay>
|
||||||
<a-menu>
|
<a-menu>
|
||||||
<a-menu-item v-for="item in symbolList.filter((t: SymbolType, i: number) => i > 6)" :key="item.key"
|
<a-menu-item v-for="item in symbolList.filter((t: SymbolType, i: number) => i > 6)" :key="item.key"
|
||||||
@click="handleInsertCode(item.value)">
|
@click="addOperatorValue(item.value)">
|
||||||
{{ item.value }}
|
{{ item.value }}
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
|
@ -149,7 +149,7 @@ onMounted(() => {
|
||||||
}, 100);
|
}, 100);
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleInsertCode = (val: string) => {
|
const addOperatorValue = (val: string) => {
|
||||||
editor.value?.insert(val)
|
editor.value?.insert(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,6 +159,10 @@ const fullscreenClick = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
addOperatorValue
|
||||||
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.editor-box {
|
.editor-box {
|
||||||
|
|
|
@ -1,51 +1,64 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="operator-box">
|
<div class="operator-box">
|
||||||
<a-input-search @search="search" allow-clear placeholder="搜索关键字" />
|
<a-input-search @search="search" allow-clear placeholder="搜索关键字" />
|
||||||
<a-tree class="tree" @select="selectTree" :field-names="{ title: 'name', key: 'id', }" auto-expand-parent
|
<div class="tree">
|
||||||
:tree-data="data">
|
<a-tree @select="selectTree" :field-names="{ title: 'name', key: 'id', }" auto-expand-parent
|
||||||
<template #title="node">
|
:tree-data="data">
|
||||||
<div class="node">
|
<template #title="node">
|
||||||
<div>{{ node.name }}</div>
|
<div class="node">
|
||||||
<div :class="node.children?.length > 0 ? 'parent' : 'add'">
|
<div>{{ node.name }}</div>
|
||||||
<a-popover v-if="node.type === 'property'" placement="right" title="请选择使用值" @visibleChange="setVisible">
|
<div :class="node.children?.length > 0 ? 'parent' : 'add'">
|
||||||
<template #content>
|
<a-popover v-if="node.type === 'property'" placement="right" title="请选择使用值">
|
||||||
<a-space direction="vertical">
|
<template #content>
|
||||||
<a-tooltip placement="right" title="实时值为空时获取上一有效值补齐,实时值不为空则使用实时值">
|
<a-space direction="vertical">
|
||||||
<a-button type="text" @click="recentClick(node)">
|
<a-tooltip placement="right" title="实时值为空时获取上一有效值补齐,实时值不为空则使用实时值">
|
||||||
$recent实时值
|
<a-button type="text" @click="recentClick(node)">
|
||||||
</a-button>
|
$recent实时值
|
||||||
</a-tooltip>
|
</a-button>
|
||||||
<a-tooltip placement="right" title="实时值的上一有效值">
|
</a-tooltip>
|
||||||
<a-button @click="lastClick(node)" type="text">
|
<a-tooltip placement="right" title="实时值的上一有效值">
|
||||||
上一值
|
<a-button @click="lastClick(node)" type="text">
|
||||||
</a-button>
|
上一值
|
||||||
</a-tooltip>
|
</a-button>
|
||||||
</a-space>
|
</a-tooltip>
|
||||||
</template>
|
</a-space>
|
||||||
<a @click="setVisible(true)">添加</a>
|
</template>
|
||||||
</a-popover>
|
<a>添加</a>
|
||||||
|
</a-popover>
|
||||||
|
|
||||||
<a v-else @click="addClick(node)">
|
<a v-else @click="addClick(node)">
|
||||||
添加
|
添加
|
||||||
</a>
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</template>
|
||||||
</template>
|
</a-tree>
|
||||||
</a-tree>
|
</div>
|
||||||
<div class="explain">
|
<div class="explain">
|
||||||
<ReactMarkdown>{{ item?.description || '' }}</ReactMarkdown>
|
<Markdown :source="item?.description || ''"></Markdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts" name="Operator">
|
<script setup lang="ts" name="Operator">
|
||||||
|
import { useProductStore } from '@/store/product';
|
||||||
import type { OperatorItem } from './typings';
|
import type { OperatorItem } from './typings';
|
||||||
import { treeFilter } from '@/utils/tree'
|
import { treeFilter } from '@/utils/tree'
|
||||||
import { Store } from 'jetlinks-store';
|
import { PropertyMetadata } from '@/views/device/Product/typings';
|
||||||
|
import { getOperator } from '@/api/device/product'
|
||||||
|
import Markdown from 'vue3-markdown-it'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
id: String
|
||||||
|
})
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'addOperatorValue', data: string): void;
|
||||||
|
}
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
const item = ref<Partial<OperatorItem>>()
|
const item = ref<Partial<OperatorItem>>()
|
||||||
const data = ref<OperatorItem[]>([])
|
const data = ref<OperatorItem[]>([])
|
||||||
const dataRef = ref<OperatorItem[]>([])
|
const dataRef = ref<OperatorItem[]>([])
|
||||||
const visible = ref(false)
|
|
||||||
|
|
||||||
const search = (value: string) => {
|
const search = (value: string) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -60,22 +73,52 @@ const selectTree = (k: any, info: any) => {
|
||||||
item.value = info.node as unknown as OperatorItem;
|
item.value = info.node as unknown as OperatorItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
const setVisible = (_visible: boolean) => {
|
|
||||||
visible.value = !!visible
|
|
||||||
}
|
|
||||||
|
|
||||||
const recentClick = (node: OperatorItem) => {
|
const recentClick = (node: OperatorItem) => {
|
||||||
Store.set('add-operator-value', `$recent("${node.id}")`);
|
emit('addOperatorValue', `$recent("${node.id}")`)
|
||||||
setVisible(!visible.value);
|
|
||||||
}
|
}
|
||||||
const lastClick = (node: OperatorItem) => {
|
const lastClick = (node: OperatorItem) => {
|
||||||
Store.set('add-operator-value', `$lastState("${node.id}")`);
|
emit('addOperatorValue', `$lastState("${node.id}")`)
|
||||||
setVisible(!visible.value);
|
|
||||||
}
|
}
|
||||||
const addClick = (node: OperatorItem) => {
|
const addClick = (node: OperatorItem) => {
|
||||||
Store.set('add-operator-value', node.code);
|
emit('addOperatorValue', node.code)
|
||||||
setVisible(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const productStore = useProductStore()
|
||||||
|
|
||||||
|
const getData = async (id?: string) => {
|
||||||
|
const metadata = productStore.current.metadata || '{}';
|
||||||
|
console.log('metadata', metadata)
|
||||||
|
const _properties = JSON.parse(metadata).properties || [] as PropertyMetadata[]
|
||||||
|
const properties = {
|
||||||
|
id: 'property',
|
||||||
|
name: '属性',
|
||||||
|
description: '',
|
||||||
|
code: '',
|
||||||
|
children: _properties
|
||||||
|
.filter((p: PropertyMetadata) => p.id !== id)
|
||||||
|
.map((p: PropertyMetadata) => ({
|
||||||
|
id: p.id,
|
||||||
|
name: p.name,
|
||||||
|
description: `### ${p.name}
|
||||||
|
\n 数据类型: ${p.valueType?.type}
|
||||||
|
\n 是否只读: ${p.expands?.readOnly || 'false'}
|
||||||
|
\n 可写数值范围: `,
|
||||||
|
type: 'property',
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
const response = await getOperator();
|
||||||
|
if (response.status === 200) {
|
||||||
|
data.value = [properties, ...response.result];
|
||||||
|
dataRef.value = [properties, ...response.result];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(() => props.id,
|
||||||
|
(val) => {
|
||||||
|
getData(val)
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
.border {
|
.border {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<Editor key="simple" @change="change" v-model:value="_value" :id="id" />
|
<Editor key="simple" @change="change" v-model:value="_value" :id="id" />
|
||||||
{{ ruleEditorStore.state.model }}
|
{{ _value }}
|
||||||
<Advance v-if="ruleEditorStore.state.model === 'advance'" :model="ruleEditorStore.state.model"
|
<Advance v-if="ruleEditorStore.state.model === 'advance'" v-model:value="_value" :model="ruleEditorStore.state.model"
|
||||||
:virtualRule="virtualRule" :id="id" @change="change" />
|
:virtualRule="virtualRule" :id="id" @change="change" />
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts" name="FRuleEditor">
|
<script setup lang="ts" name="FRuleEditor">
|
||||||
|
|
|
@ -87,7 +87,7 @@ const handleEdit = (index: number) => {
|
||||||
}
|
}
|
||||||
const handleDelete = (index: number) => {
|
const handleDelete = (index: number) => {
|
||||||
editIndex.value = -1
|
editIndex.value = -1
|
||||||
_value.value.slice(index, 1)
|
_value.value.splice(index, 1)
|
||||||
}
|
}
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
editIndex.value = -1
|
editIndex.value = -1
|
||||||
|
|
|
@ -1,11 +1,40 @@
|
||||||
<template>
|
<template>
|
||||||
<a-form-item :name="name.concat(['script'])">
|
<a-form-item :name="name.concat(['script'])">
|
||||||
<f-rule-editor v-model:value="value.script" :id="id" ></f-rule-editor>
|
<f-rule-editor v-model:value="value.script" :id="id"></f-rule-editor>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
<template v-if="showWindow">
|
||||||
|
<a-form-item label="规则配置" :name="name.concat(['isVirtualRule'])">
|
||||||
|
<a-switch v-model:checked="value.isVirtualRule" :checked-value="true" :un-checked-value="false"
|
||||||
|
@change="changeWindow"></a-switch>
|
||||||
|
</a-form-item>
|
||||||
|
<template v-if="value.isVirtualRule">
|
||||||
|
<a-form-item label="窗口" :name="name.concat(['windowType'])" :rules="[
|
||||||
|
{ required: true, message: '请选择窗口' },
|
||||||
|
]">
|
||||||
|
<a-select v-model:value="value.windowType" :options="windowTypeEnum" size="small" allow-clear></a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item label="聚合函数" :name="name.concat(['aggType'])" :rules="[
|
||||||
|
{ required: true, message: '请选择聚合函数' },
|
||||||
|
]">
|
||||||
|
<a-select v-model:value="value.aggType" :options="aggTypeOptions" size="small" allow-clear></a-select>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item :label="spanLabel" :name="name.concat(['window', 'span'])" :rules="[
|
||||||
|
{ required: true, message: '请输入窗口长度' },
|
||||||
|
]">
|
||||||
|
<a-input-number v-model:value="value.window.span" size="small" style="width: 100%;"></a-input-number>
|
||||||
|
</a-form-item>
|
||||||
|
<a-form-item :label="everyLabel" :name="name.concat(['window', 'every'])" :rules="[
|
||||||
|
{ required: true, message: '请输入步长' },
|
||||||
|
]">
|
||||||
|
<a-input-number v-model:value="value.window.every" size="small" style="width: 100%;"></a-input-number>
|
||||||
|
</a-form-item>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts" name="VirtualRuleParam">
|
<script setup lang="ts" name="VirtualRuleParam">
|
||||||
import { PropType } from 'vue';
|
import { PropType } from 'vue';
|
||||||
import FRuleEditor from '@/components/FRuleEditor/index.vue'
|
import FRuleEditor from '@/components/FRuleEditor/index.vue'
|
||||||
|
import { getStreamingAggType } from '@/api/device/product'
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
value: {
|
value: {
|
||||||
|
@ -18,7 +47,11 @@ const props = defineProps({
|
||||||
type: Array as PropType<string[]>,
|
type: Array as PropType<string[]>,
|
||||||
default: () => ([])
|
default: () => ([])
|
||||||
},
|
},
|
||||||
id: String
|
id: String,
|
||||||
|
showWindow: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
|
@ -32,5 +65,54 @@ onMounted(() => {
|
||||||
type: 'script'
|
type: 'script'
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const aggTypeOptions = ref()
|
||||||
|
const getAggTypeList = async () => {
|
||||||
|
aggTypeOptions.value = await getStreamingAggType().then((resp) =>
|
||||||
|
resp.result.map((item: any) => ({
|
||||||
|
label: `${item.value}(${item.text})`,
|
||||||
|
value: item.value,
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
getAggTypeList()
|
||||||
|
|
||||||
|
const changeWindow = (val: boolean | string | number) => {
|
||||||
|
if (val as boolean) {
|
||||||
|
props.value.type = 'window'
|
||||||
|
if (!props.value.window) {
|
||||||
|
props.value.window = {}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete props.value.type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const windowTypeEnum = [
|
||||||
|
{ label: '时间窗口', value: 'time' },
|
||||||
|
{ label: '次数窗口', value: 'num' },
|
||||||
|
]
|
||||||
|
|
||||||
|
const spanLabel = computed(() => {
|
||||||
|
switch(props.value.windowType) {
|
||||||
|
case 'time':
|
||||||
|
return '窗口长度(秒)';
|
||||||
|
case 'num':
|
||||||
|
return '窗口长度(次)';
|
||||||
|
default:
|
||||||
|
return '窗口长度'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const everyLabel = computed(() => {
|
||||||
|
switch(props.value.windowType) {
|
||||||
|
case 'time':
|
||||||
|
return '步长(秒)';
|
||||||
|
case 'num':
|
||||||
|
return '步长(次)';
|
||||||
|
default:
|
||||||
|
return '步长'
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
<style lang="less" scoped></style>
|
<style lang="less" scoped></style>
|
|
@ -4,7 +4,7 @@
|
||||||
]">
|
]">
|
||||||
<a-select v-model:value="_value.source" :options="PropertySource" size="small" :disabled="metadataStore.model.action === 'edit'"></a-select>
|
<a-select v-model:value="_value.source" :options="PropertySource" size="small" :disabled="metadataStore.model.action === 'edit'"></a-select>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<virtual-rule-param v-if="_value.source === 'rule'" v-model:value="_value.virtualRule" :name="name.concat(['virtualRule'])" :id="id"></virtual-rule-param>
|
<virtual-rule-param v-if="_value.source === 'rule'" v-model:value="_value.virtualRule" :name="name.concat(['virtualRule'])" :id="id" :showWindow="_value.source === 'rule'"></virtual-rule-param>
|
||||||
<a-form-item label="读写类型" :name="name.concat(['type'])" :rules="[
|
<a-form-item label="读写类型" :name="name.concat(['type'])" :rules="[
|
||||||
{ required: true, message: '请选择读写类型' },
|
{ required: true, message: '请选择读写类型' },
|
||||||
]">
|
]">
|
||||||
|
|
Loading…
Reference in New Issue