fix: 物模型组件修改

This commit is contained in:
wangshuaiswim 2023-03-08 17:59:51 +08:00
parent 56122ac90c
commit 23aff419a3
15 changed files with 338 additions and 241 deletions

View File

@ -2,36 +2,36 @@
<div class="indicator-box">
<template v-if="['int', 'long', 'double', 'float'].includes(type)">
<template v-if="value.range">
<a-input-number v-model:value="value.value[0]" :max="value.value[1]" size="small"
style="width: 100%;"></a-input-number>
<j-input-number v-model:value="value.value[0]" :max="value.value[1]" size="small"
style="width: 100%;"></j-input-number>
~
<a-input-number v-model:value="value.value[1]" :min="value.value[0]" size="small"
style="width: 100%;"></a-input-number>
<j-input-number v-model:value="value.value[1]" :min="value.value[0]" size="small"
style="width: 100%;"></j-input-number>
</template>
<a-input-number v-else v-model:value="value.value" size="small" style="width: 100%;"></a-input-number>
<j-input-number v-else v-model:value="value.value" size="small" style="width: 100%;"></j-input-number>
</template>
<template v-else-if="type === 'date'">
<a-range-picker v-if="value.range" show-time v-model:value="value.value" size="small" />
<a-date-picker v-else show-time v-model:value="value.value" size="small" />
<j-range-picker v-if="value.range" show-time v-model:value="value.value" size="small" />
<j-date-picker v-else show-time v-model:value="value.value" size="small" />
</template>
<template v-else-if="type === 'boolean'">
<a-select v-model:value="value.value[0]" :options="list" size="small" placeholder="请选择"></a-select>
<j-select v-model:value="value.value[0]" :options="list" size="small" placeholder="请选择"></j-select>
</template>
<template v-else-if="type === 'string'">
<a-input v-model:value="value.value" size="small" placeholder="请输入"></a-input>
<j-input v-model:value="value.value" size="small" placeholder="请输入"></j-input>
</template>
<template v-else>
<template v-if="value.range">
<a-input v-model:value="value.value[0]" :max="value.value[1]" size="small" placeholder="请输入"></a-input>
<j-input v-model:value="value.value[0]" :max="value.value[1]" size="small" placeholder="请输入"></j-input>
~
<a-input v-model:value="value.value[1]" :min="value.value[0]" size="small" placeholder="请输入"></a-input>
<j-input v-model:value="value.value[1]" :min="value.value[0]" size="small" placeholder="请输入"></j-input>
</template>
<a-input-number v-else v-model:value="value.value" size="small" placeholder="请输入"></a-input-number>
<j-input-number v-else v-model:value="value.value" size="small" placeholder="请输入"></j-input-number>
</template>
<div v-if="type !== 'boolean' && type !== 'string'">
<a-checkbox style="min-width: 60px; margin-left: 5px;" v-model:checked="value.range" @change="changeChecked">
<j-checkbox style="min-width: 60px; margin-left: 5px;" v-model:checked="value.range" @change="changeChecked">
范围
</a-checkbox>
</j-checkbox>
</div>
</div>
</template>

View File

@ -1,5 +1,5 @@
<template>
<a-popover :visible="visible" placement="left">
<j-popover :visible="visible" placement="left">
<template #title>
<div style="display: flex; justify-content: space-between; align-items: center;">
<div style="width: 150px;">配置元素</div>
@ -10,19 +10,19 @@
<div style="max-width: 400px;">
<div class="ant-form-vertical">
<value-type-form v-model:value="_value" :name="name" isSub key="sub"></value-type-form>
<a-form-item label="说明" :name="name.concat(['description'])" :rules="[
<j-form-item label="说明" :name="name.concat(['description'])" :rules="[
{ max: 200, message: '最多可输入200个字符' },
]">
<a-textarea v-model:value="_value.description" size="small"></a-textarea>
</a-form-item>
<j-textarea v-model:value="_value.description" size="small"></j-textarea>
</j-form-item>
</div>
</div>
</template>
<a-button type="dashed" block @click="visible = true">
<j-button type="dashed" block @click="visible = true">
配置元素
<AIcon type="EditOutlined" class="item-icon" />
</a-button>
</a-popover>
</j-button>
</j-popover>
</template>
<script setup lang="ts" name="ArrayParam">
import ValueTypeForm from '@/views/device/components/Metadata/Base/Edit/ValueTypeForm.vue';
@ -33,7 +33,7 @@ type ValueType = Record<any, any>;
const props = defineProps({
value: {
type: Object as PropType<ValueType>,
default: () => ({ extends: {} })
default: () => ({ expands: {} })
},
name: {
type: Array as PropType<(string | number)[]>,

View File

@ -1,35 +1,35 @@
<template>
<div class="boolean-param">
<a-row :gutter="4">
<a-col :span="12">
<a-form-item label=" " :name="name.concat(['trueText'])" :rules="[
<j-row :gutter="4">
<j-col :span="12">
<j-form-item label=" " :name="name.concat(['trueText'])" :rules="[
{ required: true, message: '请输入trueText' },
]">
<a-input v-model:value="value.trueText" placeholder="trueText" size="small" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="-" :name="name.concat(['trueValue'])" :rules="[
<j-input v-model:value="value.trueText" placeholder="trueText" size="small" />
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item label="-" :name="name.concat(['trueValue'])" :rules="[
{ required: true, message: '请输入trueValue' },
]">
<a-input v-model:value="value.trueValue" placeholder="trueValue" size="small"/>
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label=" " :name="name.concat(['falseText'])" :rules="[
<j-input v-model:value="value.trueValue" placeholder="trueValue" size="small"/>
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item label=" " :name="name.concat(['falseText'])" :rules="[
{ required: true, message: '请输入falseText' },
]">
<a-input v-model:value="value.falseText" placeholder="falseText" size="small" />
</a-form-item>
</a-col>
<a-col :span="12">
<a-form-item label="-" :name="name.concat(['falseValue'])" :rules="[
<j-input v-model:value="value.falseText" placeholder="falseText" size="small" />
</j-form-item>
</j-col>
<j-col :span="12">
<j-form-item label="-" :name="name.concat(['falseValue'])" :rules="[
{ required: true, message: '请输入falseValue' },
]">
<a-input v-model:value="value.falseValue" placeholder="falseValue" size="small" />
</a-form-item>
</a-col>
</a-row>
<j-input v-model:value="value.falseValue" placeholder="falseValue" size="small" />
</j-form-item>
</j-col>
</j-row>
</div>
</template>
<script setup lang="ts" name="BooleanParam">

View File

@ -1,5 +1,5 @@
<template>
<a-popover placement="left" trigger="click">
<j-popover placement="left" trigger="click">
<template #title>
<div class="edit-title" style="display: flex; justify-content: space-between; align-items: center;">
<div style="width: 150px;">{{ config.name }}</div>
@ -7,18 +7,18 @@
</template>
<template #content>
<div style="max-width: 400px;" class="ant-form-vertical">
<a-form-item v-for="item in config.properties" :name="name.concat([item.property])" :label="item.name">
<a-select v-model:value="value[item.property]" :options="item.type?.elements?.map((e: { 'text': string, 'value': string }) => ({
<j-form-item v-for="item in config.properties" :name="name.concat([item.property])" :label="item.name">
<j-select v-model:value="value[item.property]" :options="item.type?.elements?.map((e: { 'text': string, 'value': string }) => ({
label: e.text,
value: e.value,
}))" size="small"></a-select>
</a-form-item>
}))" size="small"></j-select>
</j-form-item>
</div>
</template>
<a-button type="dashed" block>
<j-button type="dashed" block>
存储配置<AIcon type="EditOutlined" class="item-icon"/>
</a-button>
</a-popover>
</j-button>
</j-popover>
</template>
<script setup lang="ts" name="ConfigParam">
import { PropType } from 'vue';

View File

@ -5,7 +5,7 @@
<AIcon type="MenuOutlined" class="item-drag item-icon" />
</div>
<div class="item-middle item-editable">
<a-popover :visible="editIndex === index" placement="top">
<j-popover :visible="editIndex === index" placement="top">
<template #title>
<div class="edit-title" style="display: flex; justify-content: space-between; align-items: center;">
<div style="width: 150px;">枚举项配置</div>
@ -14,34 +14,34 @@
</template>
<template #content>
<div class="ant-form-vertical">
<a-form-item label="Value" :name="name.concat([index, 'value'])" :rules="[
<j-form-item label="Value" :name="name.concat([index, 'value'])" :rules="[
{ required: true, message: '请输入Value' },
]">
<a-input v-model:value="_value[index].value" size="small"></a-input>
</a-form-item>
<a-form-item label="Text" :name="name.concat([index, 'text'])" :rules="[
<j-input v-model:value="_value[index].value" size="small"></j-input>
</j-form-item>
<j-form-item label="Text" :name="name.concat([index, 'text'])" :rules="[
{ required: true, message: '请输入Text' },
]">
<a-input v-model:value="_value[index].text" size="small"></a-input>
</a-form-item>
<j-input v-model:value="_value[index].text" size="small"></j-input>
</j-form-item>
</div>
</template>
<div class="item-edit" @click="handleEdit(index)">
{{ item.text || '枚举项配置' }}
<AIcon type="EditOutlined" class="item-icon" />
</div>
</a-popover>
</j-popover>
</div>
<div class="item-right">
<AIcon type="DeleteOutlined" @click="handleDelete(index)" />
</div>
</div>
<a-button type="dashed" block @click="handleAdd">
<j-button type="dashed" block @click="handleAdd">
<template #icon>
<AIcon type="PlusOutlined" class="item-icon" />
</template>
新增枚举型
</a-button>
</j-button>
</div>
</template>
<script setup lang="ts" name="BooleanParam">

View File

@ -5,7 +5,7 @@
<AIcon type="MenuOutlined" class="item-drag item-icon" />
</div>
<div class="item-middle item-editable">
<a-popover :visible="editIndex === index" placement="left">
<j-popover :visible="editIndex === index" placement="left">
<template #title>
<div class="edit-title" style="display: flex; justify-content: space-between; align-items: center;">
<div style="width: 150px;">配置参数</div>
@ -14,7 +14,7 @@
</template>
<template #content>
<div style="max-width: 400px;" class="ant-form-vertical">
<a-form-item label="标识" :name="name.concat([index, 'id'])" :rules="[
<j-form-item label="标识" :name="name.concat([index, 'id'])" :rules="[
{ required: true, message: '请输入标识' },
{ max: 64, message: '最多可输入64个字符' },
{
@ -22,14 +22,14 @@
message: 'ID只能由数字、字母、下划线、中划线组成',
},
]">
<a-input v-model:value="_value[index].id" size="small"></a-input>
</a-form-item>
<a-form-item label="名称" :name="name.concat([index, 'name'])" :rules="[
<j-input v-model:value="_value[index].id" size="small"></j-input>
</j-form-item>
<j-form-item label="名称" :name="name.concat([index, 'name'])" :rules="[
{ required: true, message: '请输入名称' },
{ max: 64, message: '最多可输入64个字符' },
]">
<a-input v-model:value="_value[index].name" size="small"></a-input>
</a-form-item>
<j-input v-model:value="_value[index].name" size="small"></j-input>
</j-form-item>
<value-type-form v-model:value="_value[index].valueType" :name="name.concat([index, 'valueType'])" isSub
key="json_sub"></value-type-form>
</div>
@ -38,18 +38,18 @@
{{ item.name || '配置参数' }}
<AIcon type="EditOutlined" class="item-icon" />
</div>
</a-popover>
</j-popover>
</div>
<div class="item-right">
<AIcon type="DeleteOutlined" @click="handleDelete(index)" />
</div>
</div>
<a-button type="dashed" block @click="handleAdd">
<j-button type="dashed" block @click="handleAdd">
<template #icon>
<AIcon type="PlusOutlined" class="item-icon" />
</template>
添加参数
</a-button>
</j-button>
</div>
</template>
<script setup lang="ts" name="JsonParam">

View File

@ -6,7 +6,7 @@
{{ `#${index + 1}.` }}
</div>
<div class="item-middle item-editable">
<a-popover :visible="editIndex === index" placement="top" @visible-change="change" trigger="click">
<j-popover :visible="editIndex === index" placement="top" @visible-change="change" trigger="click">
<template #title>
<div class="edit-title" style="display: flex; justify-content: space-between; align-items: center;">
<div style="width: 150px;">配置参数</div>
@ -16,7 +16,7 @@
<template #content>
<div>
<div class="ant-form-vertical">
<a-form-item label="标识" :name="name.concat([index, 'id'])" :rules="[
<j-form-item label="标识" :name="name.concat([index, 'id'])" :rules="[
{ required: true, message: '请输入标识' },
{ max: 64, message: '最多可输入64个字符' },
{
@ -24,20 +24,19 @@
message: 'ID只能由数字、字母、下划线、中划线组成',
},
]">
<a-input v-model:value="_value[index].id" size="small"></a-input>
</a-form-item>
<a-form-item label="名称" :name="name.concat([index, 'name'])" :rules="[
<j-input v-model:value="_value[index].id" size="small"></j-input>
</j-form-item>
<j-form-item label="名称" :name="name.concat([index, 'name'])" :rules="[
{ required: true, message: '请输入名称' },
{ max: 64, message: '最多可输入64个字符' },
]">
<a-input v-model:value="_value[index].name" size="small"></a-input>
</a-form-item>
<a-form-item label="指标值" :name="name.concat([index, 'value'])" :rules="[
{ required: true, message: '请输入指标值' },
{ validator: () => validateIndicator(_value[index]), message: '请输入指标值' }
<j-input v-model:value="_value[index].name" size="small"></j-input>
</j-form-item>
<j-form-item label="指标值" :name="name.concat([index, 'value'])" :rules="[
{ required: true, validator: () => validateIndicator(_value[index]), message: '请输入指标值' }
]">
<JIndicators v-model:value="_value[index]" :type="type" size="small" :enum="enum" />
</a-form-item>
</j-form-item>
</div>
</div>
</template>
@ -45,18 +44,18 @@
{{ item.name || '配置参数' }}
<AIcon type="EditOutlined" class="item-icon" />
</div>
</a-popover>
</j-popover>
</div>
<div class="item-right">
<AIcon type="DeleteOutlined" @click="handleDelete(index)" />
</div>
</div>
<a-button type="dashed" block @click="handleAdd">
<j-button type="dashed" block @click="handleAdd">
<template #icon>
<AIcon type="PlusOutlined" class="item-icon" />
</template>
添加指标
</a-button>
</j-button>
</div>
</template>
<script setup lang="ts" name="MetricsParam">

View File

@ -1,33 +1,33 @@
<template>
<a-form-item :name="name.concat(['script'])">
<j-form-item :name="name.concat(['script'])">
<f-rule-editor v-model:value="value.script" :id="id"></f-rule-editor>
</a-form-item>
</j-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>
<j-form-item label="规则配置" :name="name.concat(['isVirtualRule'])">
<j-switch v-model:checked="value.isVirtualRule" :checked-value="true" :un-checked-value="false"
@change="changeWindow"></j-switch>
</j-form-item>
<template v-if="value.isVirtualRule">
<a-form-item label="窗口" :name="name.concat(['windowType'])" :rules="[
<j-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="[
<j-select v-model:value="value.windowType" :options="windowTypeEnum" size="small" allow-clear></j-select>
</j-form-item>
<j-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="[
<j-select v-model:value="value.aggType" :options="aggTypeOptions" size="small" allow-clear></j-select>
</j-form-item>
<j-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="[
<j-input-number v-model:value="value.window.span" size="small" style="width: 100%;"></j-input-number>
</j-form-item>
<j-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>
<j-input-number v-model:value="value.window.every" size="small" style="width: 100%;"></j-input-number>
</j-form-item>
</template>
</template>
</template>

View File

@ -1,5 +1,5 @@
<template>
<a-form-item label="标识" name="id" :rules="[
<j-form-item label="标识" name="id" :rules="[
{ required: true, message: '请输入标识' },
{ max: 64, message: '最多可输入64个字符' },
{
@ -7,14 +7,14 @@
message: 'ID只能由数字、字母、下划线、中划线组成',
},
]">
<a-input v-model:value="value.id" size="small" @change="asyncOtherConfig" :disabled="metadataStore.model.action === 'edit'"></a-input>
</a-form-item>
<a-form-item label="名称" name="name" :rules="[
<j-input v-model:value="value.id" size="small" @change="asyncOtherConfig" :disabled="metadataStore.model.action === 'edit'"></j-input>
</j-form-item>
<j-form-item label="名称" name="name" :rules="[
{ required: true, message: '请输入名称' },
{ max: 64, message: '最多可输入64个字符' },
]">
<a-input v-model:value="value.name" size="small"></a-input>
</a-form-item>
<j-input v-model:value="value.name" size="small"></j-input>
</j-form-item>
<template v-if="modelType === 'properties'">
<value-type-form :name="['valueType']" v-model:value="value.valueType" key="property" title="数据类型"
@change-type="changeValueType"></value-type-form>
@ -22,42 +22,42 @@
:valueType="value.valueType"></expands-form>
</template>
<template v-if="modelType === 'functions'">
<a-form-item label="是否异步" name="async" :rules="[
<j-form-item label="是否异步" name="async" :rules="[
{ required: true, message: '请选择是否异步' },
]">
<a-radio-group v-model:value="value.async">
<a-radio :value="true"></a-radio>
<a-radio :value="false"></a-radio>
</a-radio-group>
</a-form-item>
<a-form-item label="输入参数" name="inputs" :rules="[
<j-radio-group v-model:value="value.async">
<j-radio :value="true"></j-radio>
<j-radio :value="false"></j-radio>
</j-radio-group>
</j-form-item>
<j-form-item label="输入参数" name="inputs" :rules="[
{ required: true, message: '请输入输入参数' },
]">
<JsonParam v-model:value="value.inputs" :name="['inputs']"></JsonParam>
</a-form-item>
</j-form-item>
<value-type-form :name="['output']" v-model:value="value.output" key="function" title="输出参数"></value-type-form>
</template>
<template v-if="modelType === 'events'">
<a-form-item label="级别" :name="['expands', 'level']" :rules="[
<j-form-item label="级别" :name="['expands', 'level']" :rules="[
{ required: true, message: '请选择级别' },
]">
<a-select v-model:value="value.expands.level" :options="EventLevel" size="small"></a-select>
</a-form-item>
<j-select v-model:value="value.expands.level" :options="EventLevel" size="small"></j-select>
</j-form-item>
<value-type-form :name="['valueType']" v-model:value="value.valueType" key="function" title="输出参数"></value-type-form>
</template>
<template v-if="modelType === 'tags'">
<value-type-form :name="['valueType']" v-model:value="value.valueType" key="property" title="数据类型"></value-type-form>
<a-form-item label="读写类型" :name="['expands', 'type']" :rules="[
<j-form-item label="读写类型" :name="['expands', 'type']" :rules="[
{ required: true, message: '请选择读写类型' },
]">
<a-select v-model:value="value.expands.type" :options="ExpandsTypeList" mode="multiple" size="small"></a-select>
</a-form-item>
<j-select v-model:value="value.expands.type" :options="ExpandsTypeList" mode="multiple" size="small"></j-select>
</j-form-item>
</template>
<a-form-item label="说明" name="description" :rules="[
<j-form-item label="说明" name="description" :rules="[
{ max: 200, message: '最多可输入200个字符' },
]">
<a-textarea v-model:value="value.description" size="small"></a-textarea>
</a-form-item>
<j-textarea v-model:value="value.description" size="small"></j-textarea>
</j-form-item>
</template>
<script setup lang="ts" name="BaseForm">
import { PropType } from 'vue';

View File

@ -1,26 +1,30 @@
<template>
<a-form-item label="来源" :name="name.concat(['source'])" v-if="type === 'product'" :rules="[
<j-form-item label="来源" :name="name.concat(['source'])" v-if="type === 'product'" :rules="[
{ required: true, message: '请选择来源' },
]">
<a-select v-model:value="_value.source" :options="PropertySource" size="small"
:disabled="metadataStore.model.action === 'edit'"></a-select>
</a-form-item>
<j-select v-model:value="_value.source" :options="PropertySource" size="small"
:disabled="metadataStore.model.action === 'edit'"></j-select>
</j-form-item>
<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="[
<j-form-item label="读写类型" :name="name.concat(['type'])" :rules="[
{ required: true, message: '请选择读写类型' },
]">
<a-select v-model:value="_value.type" :options="ExpandsTypeList" mode="multiple" size="small"></a-select>
</a-form-item>
<a-form-item label="其他配置" v-if="config.length > 0">
<a-form-item v-for="(item, index) in config" :key="index">
<j-select v-model:value="_value.type" :options="ExpandsTypeList" mode="multiple" size="small"></j-select>
</j-form-item>
<j-form-item label="其他配置" v-if="config.length > 0">
<j-form-item v-for="(item, index) in config" :key="index">
<config-param v-model:value="_value" :config="item" :name="name"></config-param>
</a-form-item>
</a-form-item>
<a-form-item v-if="type === 'product' && ['int', 'float', 'double', 'long', 'date', 'string', 'boolean'].includes(valueType.type)"
label="指标配置" :name="name.concat(['metrics'])">
<metrics-param v-model:value="_value.metrics" :type="valueType.type" :enum="valueType" :name="name.concat(['metrics'])"></metrics-param>
</a-form-item>
</j-form-item>
</j-form-item>
<j-form-item
v-if="type === 'product' && ['int', 'float', 'double', 'long', 'date', 'string', 'boolean'].includes(valueType.type)"
label="指标配置" :name="name.concat(['metrics'])" :rules="[
{ validator: () => validateMetrics(_value.metrics), message: '请输入指标配置' }
]">
<metrics-param v-model:value="_value.metrics" :type="valueType.type" :enum="valueType"
:name="name.concat(['metrics'])"></metrics-param>
</j-form-item>
</template>
<script setup lang="ts" name="ExpandsForm">
import { useMetadataStore } from '@/store/metadata';
@ -86,5 +90,15 @@ onMounted(() => {
}
})
const validateMetrics = (value: Record<any, any>[]) => {
const flag = value.every((item) => {
return item.id && item.name && item.value;
});
if (!flag) {
return Promise.reject(new Error('请输入指标配置'));
}
return Promise.resolve();
}
</script>
<style lang="less" scoped></style>

View File

@ -1,48 +1,54 @@
<template>
<a-form-item :label="title" :name="name.concat(['type'])" :rules="[
<j-form-item :label="title" :name="name.concat(['type'])" :rules="[
metadataStore.model.type !== 'functions' ? { required: true, message: `请选择${title}` } : {},
]">
<a-select v-model:value="_value.type" :options="metadataStore.model.type === 'events' ? eventDataTypeList : _dataTypeList" size="small" @change="changeType"></a-select>
</a-form-item>
<a-form-item label="单位" :name="name.concat(['unit'])" v-if="['int', 'float', 'long', 'double'].includes(_value.type)">
<j-select v-model:value="_value.type"
:options="metadataStore.model.type === 'events' ? eventDataTypeList : _dataTypeList" size="small"
@change="changeType"></j-select>
</j-form-item>
<j-form-item label="单位" :name="name.concat(['unit'])" v-if="['int', 'float', 'long', 'double'].includes(_value.type)">
<InputSelect v-model:value="_value.unit" :options="unit.unitOptions" size="small"></InputSelect>
</a-form-item>
<a-form-item label="精度" :name="name.concat(['scale'])" v-if="['float', 'double'].includes(_value.type)">
<a-input-number v-model:value="_value.scale" size="small" :min="0" :max="2147483647" :precision="0" :default-value="2"
style="width: 100%"></a-input-number>
</a-form-item>
<a-form-item label="布尔值" name="booleanConfig" v-if="['boolean'].includes(_value.type)">
</j-form-item>
<j-form-item label="精度" :name="name.concat(['scale'])" v-if="['float', 'double'].includes(_value.type)">
<j-input-number v-model:value="_value.scale" size="small" :min="0" :max="2147483647" :precision="0" :default-value="2"
style="width: 100%"></j-input-number>
</j-form-item>
<j-form-item label="布尔值" name="booleanConfig" v-if="['boolean'].includes(_value.type)">
<BooleanParam :name="name" v-model:value="_value"></BooleanParam>
</a-form-item>
<a-form-item label="枚举项" :name="name.concat(['elements'])" v-if="['enum'].includes(_value.type)" :rules="[
{ required: true, message: '请配置枚举项' }
</j-form-item>
<j-form-item label="枚举项" :name="name.concat(['elements'])" v-if="['enum'].includes(_value.type)" :rules="[
{ required: true, validator: validateEnum, message: '请配置枚举项' }
]">
<EnumParam v-model:value="_value.elements" :name="name.concat(['elements'])"></EnumParam>
</a-form-item>
<a-form-item :name="name.concat(['expands', 'maxLength'])" v-if="['string', 'password'].includes(_value.type)">
</j-form-item>
<j-form-item :name="name.concat(['expands', 'maxLength'])" v-if="['string', 'password'].includes(_value.type)">
<template #label>
<a-space>
<j-space>
最大长度
<a-tooltip title="字节">
<j-tooltip title="字节">
<question-circle-outlined style="color: rgb(136, 136, 136); font-size: 12px;" />
</a-tooltip>
</a-space>
</j-tooltip>
</j-space>
</template>
<a-input-number v-model:value="_value.expands.maxLength" size="small" :max="2147483647" :min="1" :precision="0"
style="width: 100%;"></a-input-number>
</a-form-item>
<a-form-item label="元素配置" :name="name.concat(['elementType'])" v-if="['array'].includes(_value.type)">
<j-input-number v-model:value="_value.expands.maxLength" size="small" :max="2147483647" :min="1" :precision="0"
style="width: 100%;"></j-input-number>
</j-form-item>
<j-form-item label="元素配置" :name="name.concat(['elementType'])" v-if="['array'].includes(_value.type)" :rules="[
{ validator: validateArray }
]">
<ArrayParam v-model:value="_value.elementType" :name="name.concat(['elementType'])"></ArrayParam>
</a-form-item>
<a-form-item label="JSON对象" :name="name.concat(['properties'])" v-if="['object'].includes(_value.type)" :rules="[]">
</j-form-item>
<j-form-item label="JSON对象" :name="name.concat(['properties'])" v-if="['object'].includes(_value.type)" :rules="[
{ validator: validateJson }
]">
<JsonParam v-model:value="_value.properties" :name="name.concat(['properties'])"></JsonParam>
</a-form-item>
<a-form-item label="文件类型" :name="name.concat(['fileType'])" v-if="['file'].includes(_value.type)" initialValue="url"
</j-form-item>
<j-form-item label="文件类型" :name="name.concat(['fileType'])" v-if="['file'].includes(_value.type)" initialValue="url"
:rules="[
{ required: true, message: '请选择文件类型' },
]">
<a-select v-model:value="_value.fileType" :options="FileTypeList" size="small"></a-select>
</a-form-item>
<j-select v-model:value="_value.fileType" :options="FileTypeList" size="small"></j-select>
</j-form-item>
</template>
<script lang="ts" setup mame="BaseForm">
import { DataTypeList, FileTypeList } from '@/views/device/data';
@ -56,6 +62,8 @@ import EnumParam from '@/components/Metadata/EnumParam/index.vue'
import ArrayParam from '@/components/Metadata/ArrayParam/index.vue'
import JsonParam from '@/components/Metadata/JsonParam/index.vue'
import { useMetadataStore } from '@/store/metadata';
import { Rule } from 'ant-design-vue/es/form';
import { Form } from 'ant-design-vue/es';
type ValueType = Record<any, any>;
const props = defineProps({
@ -84,15 +92,8 @@ interface Emits {
}
const emit = defineEmits<Emits>()
// emit('update:value', { extends: {}, ...props.value })
const metadataStore = useMetadataStore()
// const _value = computed({
// get: () => props.value,
// set: val => {
// emit('update:value', val)
// }
// })
const _value = ref<ValueType>({})
watchEffect(() => {
_value.value = props.value || {
@ -142,6 +143,79 @@ const eventDataTypeList = [
const changeType = (val: SelectValue) => {
emit('changeType', val as string)
}
const validateEnum = async (_rule: Rule, val: Record<any, any>[]) => {
if (val.length === 0) return Promise.reject(new Error('请配置枚举项'));
const flag = val.every((item) => {
return item.value && item.text;
});
if (!flag) {
return Promise.reject(new Error('请配置枚举项'));
}
return Promise.resolve();
}
const validateArray = async (_rule: Rule, val: Record<any, any>) => {
if (!val) return Promise.reject(new Error('请输入元素配置'));
await validateValueType(_rule, val)
return Promise.resolve();
}
const validateJson = async (_rule: Rule, val: Record<any, any>[]) => {
if (!val || val.length === 0) {
return Promise.reject(new Error('请输入配置参数'));
}
for (let item of val) {
if (!item) return Promise.reject(new Error('请输入配置参数'));
await validateValueType(_rule, item)
}
return Promise.resolve();
}
const validateValueType = async (_rule: Rule, val: Record<any, any>) => {
if (!val) return Promise.reject(new Error('请输入元素配置'));
if (!val.id) {
return Promise.reject(new Error('请输入标识'))
}
if (!val.name) {
return Promise.reject(new Error('请输入名称'))
}
if (metadataStore.model.type !== 'functions' && !val.valueType?.type) {
return Promise.reject(new Error(`请选择${props.title}`))
}
if (['enum'].includes(val.valueType.type)) {
await validateEnum(_rule, val.valueType.elements)
}
if (['array'].includes(val.valueType.type)) {
await validateArray(_rule, val.valueType.elementType)
}
if (['object'].includes(val.valueType.type)) {
await validateJson(_rule, val.valueType.properties)
}
if (['file'].includes(val.valueType.type) && !val.valueType.fileType) {
return Promise.reject(new Error('请选择文件类型'))
}
return Promise.resolve();
}
// const rules = ref({
// type: [
// metadataStore.model.type !== 'functions' ? { required: true, message: `${props.title}` } : {},
// ],
// elements: [
// { required: true, validator: validateEnum, message: '' }
// ],
// elementType: [
// { validator: validateArray, message: '' }
// ],
// properties: [
// { validator: validateJson, message: '' }
// ],
// fileType: [
// { required: true, message: '' },
// ]
// })
</script>
<style lang="less" scoped>
:deep(.ant-form-item-label) {

View File

@ -1,13 +1,13 @@
<template>
<a-drawer :mask-closable="false" width="25vw" visible :title="`${title}-${typeMapping[metadataStore.model.type]}`"
<j-drawer :mask-closable="false" width="25vw" visible :title="`${title}-${typeMapping[metadataStore.model.type]}`"
@close="close" destroy-on-close :z-index="1000" placement="right">
<template #extra>
<a-button :loading="save.loading" type="primary" @click="save.saveMetadata">保存</a-button>
<j-button :loading="save.loading" type="primary" @click="save.saveMetadata">保存</j-button>
</template>
<a-form ref="formRef" :model="form.model" layout="vertical">
<j-form ref="formRef" :model="form.model" layout="vertical">
<BaseForm :model-type="metadataStore.model.type" :type="type" v-model:value="form.model"></BaseForm>
</a-form>
</a-drawer>
</j-form>
</j-drawer>
</template>
<script lang="ts" setup name="Edit">
import { useInstanceStore } from '@/store/instance';
@ -22,6 +22,7 @@ import { DeviceInstance } from '@/views/device/Instance/typings';
import BaseForm from './BaseForm.vue';
import { PropType } from 'vue';
import { _deploy } from '@/api/device/product';
import { cloneDeep } from 'lodash';
const props = defineProps({
type: {
@ -60,7 +61,7 @@ const form = reactive({
model: {} as any,
})
if (metadataStore.model.action === 'edit') {
form.model = metadataStore.model.item
form.model = cloneDeep(metadataStore.model.item)
}
const formRef = ref<FormInstance>()
@ -75,7 +76,9 @@ const save = reactive({
const type = metadataStore.model.type
const _detail: ProductItem | DeviceInstance = props.type === 'device' ? instanceStore.detail : productStore.current
const _metadata = JSON.parse(_detail?.metadata || '{}')
const list = _metadata[type] as any[]
console.log(_metadata)
console.log(type)
const list = (_metadata[type] as any[]) || []
if (formValue.id) {
if (metadataStore.model.action === 'add' && list.some(item => item.id === formValue.id)) {
message.error('标识已存在')

View File

@ -1,7 +1,7 @@
<template>
<j-pro-table :loading="loading" :data-source="data" size="small" :columns="columns" row-key="id" model="TABLE">
<template #headerTitle>
<a-input-search v-model:value="searchValue" placeholder="请输入名称" @search="handleSearch"></a-input-search>
<j-input-search v-model:value="searchValue" placeholder="请输入名称" @search="handleSearch"></j-input-search>
</template>
<template #rightExtraRender>
<PermissionButton type="primary" :uhas-permission="`${permission}:update`" key="add" @click="handleAddClick"
@ -135,6 +135,13 @@ const refreshMetadata = () => {
watch([route.params.id, type], refreshMetadata, { immediate: true })
const metadataStore = useMetadataStore()
watch(() => metadataStore.model.importMetadata,
(val: boolean) => {
if (!!val) {
refreshMetadata()
metadataStore.set('importMetadata', false)
}
})
const handleAddClick = () => {
metadataStore.set('edit', true)
metadataStore.set('item', undefined)
@ -189,6 +196,4 @@ const removeItem = async (record: MetadataItem) => {
}
};
</script>
<style scoped lang="less">
</style>
<style scoped lang="less"></style>

View File

@ -1,13 +1,13 @@
<template>
<a-drawer :mask-closable="false" title="查看物模型" width="700" v-model:visible="_visible" destroy-on-close @close="close">
<j-drawer :mask-closable="false" title="查看物模型" width="700" v-model:visible="_visible" destroy-on-close @close="close">
<template #extra>
<a-space>
<a-button type="primary" @click="handleExport">
<j-space>
<j-button type="primary" @click="handleExport">
导出
</a-button>
</a-space>
</j-button>
</j-space>
</template>
<a-spin :spinning="loading">
<j-spin :spinning="loading">
<div class="cat-content">
<p class="cat-tip">
物模型是对设备在云端的功能描述包括设备的属性服务和事件物联网平台通过定义一种物的描述语言来描述物模型称之为
@ -15,15 +15,15 @@
组装上报设备的数据您可以导出完整物模型用于云端应用开发
</p>
</div>
<a-tabs @change="handleConvertMetadata" destroy-inactive-tab-pane>
<a-tab-pane v-for="item in codecs" :key="item.id" :tab="item.name">
<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">
<MonacoEditor v-model="value" theme="vs" style="height: 100%"></MonacoEditor>
</div>
</a-tab-pane>
</a-tabs>
</a-spin>
</a-drawer>
</j-tab-pane>
</j-tabs>
</j-spin>
</j-drawer>
</template>
<script setup lang="ts" name="Cat">
import { message } from 'ant-design-vue/es';

View File

@ -1,5 +1,5 @@
<template>
<a-modal :mask-closable="false" title="导入物模型" destroy-on-close v-model:visible="_visible" @cancel="close"
<j-modal :mask-closable="false" title="导入物模型" destroy-on-close v-model:visible="_visible" @cancel="close"
@ok="handleImport" :confirm-loading="loading">
<div class="import-content">
<p class="import-tip">
@ -7,46 +7,46 @@
导入的物模型会覆盖原来的属性功能事件标签请谨慎操作
</p>
</div>
<a-form layout="vertical" v-model="formModel">
<a-form-item v-if="type === 'product'" label="导入方式" v-bind="validateInfos.type">
<a-select v-model:value="formModel.type">
<a-select-option value="copy">拷贝产品</a-select-option>
<a-select-option value="import">导入物模型</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="选择产品" v-bind="validateInfos.copy" v-if="formModel.type === 'copy'">
<a-select :options="productList" v-model:value="formModel.copy" option-filter-prop="label"></a-select>
</a-form-item>
<a-form-item label="物模型类型" v-bind="validateInfos.metadata"
<j-form layout="vertical" v-model="formModel">
<j-form-item v-if="type === 'product'" label="导入方式" v-bind="validateInfos.type">
<j-select v-model:value="formModel.type">
<j-select-option value="copy">拷贝产品</j-select-option>
<j-select-option value="import">导入物模型</j-select-option>
</j-select>
</j-form-item>
<j-form-item label="选择产品" v-bind="validateInfos.copy" v-if="formModel.type === 'copy'">
<j-select :options="productList" v-model:value="formModel.copy" option-filter-prop="label"></j-select>
</j-form-item>
<j-form-item label="物模型类型" v-bind="validateInfos.metadata"
v-if="type === 'device' || formModel.type === 'import'">
<a-select v-model:value="formModel.metadata">
<a-select-option value="jetlinks">Jetlinks物模型</a-select-option>
<a-select-option value="alink">阿里云物模型TSL</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="导入类型" v-bind="validateInfos.metadataType"
<j-select v-model:value="formModel.metadata">
<j-select-option value="jetlinks">Jetlinks物模型</j-select-option>
<j-select-option value="alink">阿里云物模型TSL</j-select-option>
</j-select>
</j-form-item>
<j-form-item label="导入类型" v-bind="validateInfos.metadataType"
v-if="type === 'device' || formModel.type === 'import'">
<a-select v-model:value="formModel.metadataType">
<a-select-option value="file">文件上传</a-select-option>
<a-select-option value="script">脚本</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="文件上传" v-bind="validateInfos.upload" v-if="formModel.metadataType === 'file'">
<a-input v-model:value="formModel.upload">
<j-select v-model:value="formModel.metadataType">
<j-select-option value="file">文件上传</j-select-option>
<j-select-option value="script">脚本</j-select-option>
</j-select>
</j-form-item>
<j-form-item label="文件上传" v-bind="validateInfos.upload" v-if="formModel.metadataType === 'file'">
<j-input v-model:value="formModel.upload">
<template #addonAfter>
<a-upload v-model:file-list="fileList" :before-upload="beforeUpload" accept=".json"
<j-upload v-model:file-list="fileList" :before-upload="beforeUpload" accept=".json"
:show-upload-list="false" :action="FILE_UPLOAD" @change="fileChange"
:headers="{ 'X-Access-Token': getToken()}">
<AIcon type="UploadOutlined" class="upload-button" />
</a-upload>
</j-upload>
</template>
</a-input>
</a-form-item>
<a-form-item label="物模型" v-bind="validateInfos.import" v-if="formModel.metadataType === 'script'">
</j-input>
</j-form-item>
<j-form-item label="物模型" v-bind="validateInfos.import" v-if="formModel.metadataType === 'script'">
<MonacoEditor v-model="formModel.import" theme="vs" style="height: 300px"></MonacoEditor>
</a-form-item>
</a-form>
</a-modal>
</j-form-item>
</j-form>
</j-modal>
</template>
<script setup lang="ts" name="Import">
import { useForm } from 'ant-design-vue/es/form';
@ -54,13 +54,14 @@ import { saveMetadata } from '@/api/device/instance'
import { queryNoPagingPost, convertMetadata, modify } from '@/api/device/product'
import type { DefaultOptionType } from 'ant-design-vue/es/select';
import type { UploadProps, UploadFile, UploadChangeParam } from 'ant-design-vue/es';
import type { DeviceMetadata, ProductItem } from '@/views/device/Product/typings'
import { message } from 'ant-design-vue/es';
import type { DeviceMetadata } from '@/views/device/Product/typings'
import { message } from 'jetlinks-ui-components';
import { useInstanceStore } from '@/store/instance'
import { useProductStore } from '@/store/product';
import { FILE_UPLOAD } from '@/api/comm';
import { getToken } from '@/utils/comm';
import MonacoEditor from '@/components/MonacoEditor/index.vue'
import { useMetadataStore } from '@/store/metadata';
const route = useRoute()
const instanceStore = useInstanceStore()
@ -87,7 +88,6 @@ const _visible = computed({
})
const close = () => {
console.log(1)
emits('update:visible', false);
}
@ -196,7 +196,7 @@ const operateLimits = (mdata: DeviceMetadata) => {
});
return obj;
};
const metadataStore = useMetadataStore()
const handleImport = async () => {
validate().then(async (data) => {
loading.value = true
@ -224,6 +224,7 @@ const handleImport = async () => {
} else {
productStore.refresh(id as string)
}
metadataStore.set('importMetadata', true)
// Store.set(SystemConst.GET_METADATA, true)
// Store.set(SystemConst.REFRESH_METADATA_TABLE, true)
close()
@ -263,13 +264,14 @@ const handleImport = async () => {
message.success('导入成功')
}
}
// Store.set(SystemConst.GET_METADATA, true)
// Store.set(SystemConst.REFRESH_METADATA_TABLE, true)
if (props?.type === 'device') {
instanceStore.refresh(id as string)
} else {
productStore.refresh(id as string)
}
metadataStore.set('importMetadata', true)
// Store.set(SystemConst.GET_METADATA, true)
// Store.set(SystemConst.REFRESH_METADATA_TABLE, true)
close();
} catch (e) {
loading.value = false