Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev

This commit is contained in:
JiangQiming 2023-02-28 21:13:25 +08:00
commit 80ea19a6e2
14 changed files with 110 additions and 87 deletions

View File

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

View File

@ -47,7 +47,7 @@ const props = defineProps({
}) })
}, },
name: { name: {
type: Array as PropType<string[]>, type: Array as PropType<(string| number)[]>,
required: true required: true
} }
}) })

View File

@ -30,7 +30,7 @@ const props = defineProps({
default: () => ({}) default: () => ({})
}, },
name: { name: {
type: Array as PropType<string[]>, type: Array as PropType<(string| number)[]>,
default: () => ([]), default: () => ([]),
required: true required: true
}, },

View File

@ -13,18 +13,18 @@
</div> </div>
</template> </template>
<template #content> <template #content>
<a-form :model="_value[index]" layout="vertical"> <div class="ant-form-vertical">
<a-form-item label="Value" name="value" :rules="[ <a-form-item label="Value" :name="name.concat([index, 'value'])" :rules="[
{ required: true, message: '请输入Value' }, { required: true, message: '请输入Value' },
]"> ]">
<a-input v-model:value="_value[index].value" size="small"></a-input> <a-input v-model:value="_value[index].value" size="small"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="Text" name="text" :rules="[ <a-form-item label="Text" :name="name.concat([index, 'text'])" :rules="[
{ required: true, message: '请输入Text' }, { required: true, message: '请输入Text' },
]"> ]">
<a-input v-model:value="_value[index].text" size="small"></a-input> <a-input v-model:value="_value[index].text" size="small"></a-input>
</a-form-item> </a-form-item>
</a-form> </div>
</template> </template>
<div class="item-edit" @click="handleEdit(index)"> <div class="item-edit" @click="handleEdit(index)">
{{ item.text || '枚举项配置' }} {{ item.text || '枚举项配置' }}
@ -33,11 +33,13 @@
</a-popover> </a-popover>
</div> </div>
<div class="item-right"> <div class="item-right">
<AIcon type="DeleteOutlined" @click="handleDelete(index)"/> <AIcon type="DeleteOutlined" @click="handleDelete(index)" />
</div> </div>
</div> </div>
<a-button type="dashed" block @click="handleAdd"> <a-button type="dashed" block @click="handleAdd">
<template #icon><AIcon type="PlusOutlined" class="item-icon" /></template> <template #icon>
<AIcon type="PlusOutlined" class="item-icon" />
</template>
新增枚举型 新增枚举型
</a-button> </a-button>
</div> </div>
@ -57,20 +59,23 @@ const emit = defineEmits<Emits>()
const props = defineProps({ const props = defineProps({
value: { value: {
type: Object as PropType<EnumType[]>, type: Object as PropType<EnumType[]>,
},
name: {
type: Array as PropType<(string | number)[]>,
default: () => ([]) default: () => ([])
} }
}) })
const _value = ref<EnumType[]>([]) const _value = ref<EnumType[]>([])
watchEffect(() => { watchEffect(() => {
_value.value = props.value _value.value = props.value || ([{}])
}) })
watch(_value, watch(_value,
() => { () => {
emit('update:value', _value.value) emit('update:value', _value.value)
}, },
{ deep: true }) { deep: true, immediate: true })
const editIndex = ref<number>(-1) const editIndex = ref<number>(-1)
const handleEdit = (index: number) => { const handleEdit = (index: number) => {

View File

@ -13,27 +13,25 @@
</div> </div>
</template> </template>
<template #content> <template #content>
<div style="max-width: 400px;"> <div style="max-width: 400px;" class="ant-form-vertical">
<a-form :model="_value[index]" layout="vertical"> <a-form-item label="标识" :name="name.concat([index, 'id'])" :rules="[
<a-form-item label="标识" name="id" :rules="[ { required: true, message: '请输入标识' },
{ required: true, message: '请输入标识' }, { max: 64, message: '最多可输入64个字符' },
{ max: 64, message: '最多可输入64个字符' }, {
{ pattern: /^[a-zA-Z0-9_\-]+$/,
pattern: /^[a-zA-Z0-9_\-]+$/, message: 'ID只能由数字、字母、下划线、中划线组成',
message: 'ID只能由数字、字母、下划线、中划线组成', },
}, ]">
]"> <a-input v-model:value="_value[index].id" size="small"></a-input>
<a-input v-model:value="_value[index].id" size="small"></a-input> </a-form-item>
</a-form-item> <a-form-item label="名称" :name="name.concat([index, 'name'])" :rules="[
<a-form-item label="名称" name="name" :rules="[ { required: true, message: '请输入名称' },
{ required: true, message: '请输入名称' }, { max: 64, message: '最多可输入64个字符' },
{ max: 64, message: '最多可输入64个字符' }, ]">
]"> <a-input v-model:value="_value[index].name" size="small"></a-input>
<a-input v-model:value="_value[index].name" size="small"></a-input> </a-form-item>
</a-form-item> <value-type-form v-model:value="_value[index].valueType" :name="name.concat([index, 'valueType'])" isSub
<value-type-form v-model:value="_value[index].valueType" :name="['valueType']" isSub key="json_sub"></value-type-form>
key="json_sub"></value-type-form>
</a-form>
</div> </div>
</template> </template>
<div class="item-edit" @click="handleEdit(index)"> <div class="item-edit" @click="handleEdit(index)">
@ -47,7 +45,9 @@
</div> </div>
</div> </div>
<a-button type="dashed" block @click="handleAdd"> <a-button type="dashed" block @click="handleAdd">
<template #icon><AIcon type="PlusOutlined" class="item-icon" /></template> <template #icon>
<AIcon type="PlusOutlined" class="item-icon" />
</template>
添加参数 添加参数
</a-button> </a-button>
</div> </div>
@ -65,6 +65,10 @@ const emit = defineEmits<Emits>()
const props = defineProps({ const props = defineProps({
value: { value: {
type: Object as PropType<JsonType[]>, type: Object as PropType<JsonType[]>,
},
name: {
type: Array as PropType<(string | number)[]>,
default: () => ([])
} }
}) })

View File

@ -15,8 +15,8 @@
</template> </template>
<template #content> <template #content>
<div> <div>
<a-form :model="_value[index]" layout="vertical"> <div class="ant-form-vertical">
<a-form-item label="标识" name="id" :rules="[ <a-form-item label="标识" :name="name.concat([index, 'id'])" :rules="[
{ required: true, message: '请输入标识' }, { required: true, message: '请输入标识' },
{ max: 64, message: '最多可输入64个字符' }, { max: 64, message: '最多可输入64个字符' },
{ {
@ -26,19 +26,19 @@
]"> ]">
<a-input v-model:value="_value[index].id" size="small"></a-input> <a-input v-model:value="_value[index].id" size="small"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="名称" name="name" :rules="[ <a-form-item label="名称" :name="name.concat([index, 'name'])" :rules="[
{ required: true, message: '请输入名称' }, { required: true, message: '请输入名称' },
{ max: 64, message: '最多可输入64个字符' }, { max: 64, message: '最多可输入64个字符' },
]"> ]">
<a-input v-model:value="_value[index].name" size="small"></a-input> <a-input v-model:value="_value[index].name" size="small"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="指标值" name="value" :rules="[ <a-form-item label="指标值" :name="name.concat([index, 'value'])" :rules="[
{ required: true, message: '请输入指标值' }, { required: true, message: '请输入指标值' },
{ validator: () => validateIndicator(_value[index]), message: '请输入指标值' } { validator: () => validateIndicator(_value[index]), message: '请输入指标值' }
]"> ]">
<JIndicators v-model:value="_value[index]" :type="type" size="small" :enum="enum"/> <JIndicators v-model:value="_value[index]" :type="type" size="small" :enum="enum" />
</a-form-item> </a-form-item>
</a-form> </div>
</div> </div>
</template> </template>
<div class="item-edit" @click="handleEdit(index)"> <div class="item-edit" @click="handleEdit(index)">
@ -52,7 +52,9 @@
</div> </div>
</div> </div>
<a-button type="dashed" block @click="handleAdd"> <a-button type="dashed" block @click="handleAdd">
<template #icon><AIcon type="PlusOutlined" class="item-icon" /></template> <template #icon>
<AIcon type="PlusOutlined" class="item-icon" />
</template>
添加指标 添加指标
</a-button> </a-button>
</div> </div>
@ -77,6 +79,10 @@ const props = defineProps({
enum: { enum: {
type: Object, type: Object,
default: () => ({}) default: () => ({})
},
name: {
type: Array as PropType<(string | number)[]>,
default: () => ([])
} }
}) })

View File

@ -44,7 +44,7 @@ const props = defineProps({
}) })
}, },
name: { name: {
type: Array as PropType<string[]>, type: Array as PropType<(string| number)[]>,
default: () => ([]) default: () => ([])
}, },
id: String, id: String,

View File

@ -7,7 +7,7 @@
message: 'ID只能由数字、字母、下划线、中划线组成', message: 'ID只能由数字、字母、下划线、中划线组成',
}, },
]"> ]">
<a-input v-model:value="value.id" size="small" @change="asyncOtherConfig"></a-input> <a-input v-model:value="value.id" size="small" @change="asyncOtherConfig" :disabled="metadataStore.model.action === 'edit'"></a-input>
</a-form-item> </a-form-item>
<a-form-item label="名称" name="name" :rules="[ <a-form-item label="名称" name="name" :rules="[
{ required: true, message: '请输入名称' }, { required: true, message: '请输入名称' },
@ -18,7 +18,6 @@
<template v-if="modelType === 'properties'"> <template v-if="modelType === 'properties'">
<value-type-form :name="['valueType']" v-model:value="value.valueType" key="property" title="数据类型" <value-type-form :name="['valueType']" v-model:value="value.valueType" key="property" title="数据类型"
@change-type="changeValueType"></value-type-form> @change-type="changeValueType"></value-type-form>
<expands-form :name="['expands']" v-model:value="value.expands" :type="type" :id="value.id" :config="config" <expands-form :name="['expands']" v-model:value="value.expands" :type="type" :id="value.id" :config="config"
:valueType="value.valueType"></expands-form> :valueType="value.valueType"></expands-form>
</template> </template>
@ -46,20 +45,29 @@
</a-form-item> </a-form-item>
<value-type-form :name="['valueType']" v-model:value="value.valueType" key="function" title="输出参数"></value-type-form> <value-type-form :name="['valueType']" v-model:value="value.valueType" key="function" title="输出参数"></value-type-form>
</template> </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="[
{ required: true, message: '请选择读写类型' },
]">
<a-select v-model:value="value.expands.type" :options="ExpandsTypeList" mode="multiple" size="small"></a-select>
</a-form-item>
</template>
<a-form-item label="说明" name="description" :rules="[ <a-form-item label="说明" name="description" :rules="[
{ max: 200, message: '最多可输入200个字符' }, { max: 200, message: '最多可输入200个字符' },
]"> ]">
<a-textarea v-model:value="value.description" size="small"></a-textarea> <a-textarea v-model:value="value.description" size="small"></a-textarea>
</a-form-item> </a-form-item>
</template> </template>
<script setup lang="ts" name="PropertyForm"> <script setup lang="ts" name="BaseForm">
import { PropType } from 'vue'; import { PropType } from 'vue';
import ExpandsForm from './ExpandsForm.vue'; import ExpandsForm from './ExpandsForm.vue';
import ValueTypeForm from './ValueTypeForm.vue' import ValueTypeForm from './ValueTypeForm.vue'
import { useProductStore } from '@/store/product'; import { useProductStore } from '@/store/product';
import { getMetadataConfig } from '@/api/device/product' import { getMetadataConfig } from '@/api/device/product'
import JsonParam from '@/components/Metadata/JsonParam/index.vue' import JsonParam from '@/components/Metadata/JsonParam/index.vue'
import { EventLevel } from '@/views/device/data'; import { EventLevel, ExpandsTypeList } from '@/views/device/data';
import { useMetadataStore } from '@/store/metadata';
const props = defineProps({ const props = defineProps({
type: { type: {
@ -76,7 +84,10 @@ const props = defineProps({
default: '' default: ''
} }
}) })
if (props.modelType === 'events') {
const metadataStore = useMetadataStore()
if (props.modelType === 'events' || props.modelType === 'tags') {
if (!props.value.expands) { if (!props.value.expands) {
props.value.expands = {} props.value.expands = {}
} }

View File

@ -1,2 +0,0 @@
<template></template>
<script setup lang="ts" name="CommonForm"></script>

View File

@ -10,7 +10,7 @@
<a-form-item label="读写类型" :name="name.concat(['type'])" :rules="[ <a-form-item label="读写类型" :name="name.concat(['type'])" :rules="[
{ required: true, message: '请选择读写类型' }, { required: true, message: '请选择读写类型' },
]"> ]">
<a-select v-model:value="_value.type" :options="options" mode="multiple" size="small"></a-select> <a-select v-model:value="_value.type" :options="ExpandsTypeList" mode="multiple" size="small"></a-select>
</a-form-item> </a-form-item>
<a-form-item label="其他配置" v-if="config.length > 0"> <a-form-item label="其他配置" v-if="config.length > 0">
<a-form-item v-for="(item, index) in config" :key="index"> <a-form-item v-for="(item, index) in config" :key="index">
@ -19,12 +19,12 @@
</a-form-item> </a-form-item>
<a-form-item v-if="type === 'product' && ['int', 'float', 'double', 'long', 'date', 'string', 'boolean'].includes(valueType.type)" <a-form-item v-if="type === 'product' && ['int', 'float', 'double', 'long', 'date', 'string', 'boolean'].includes(valueType.type)"
label="指标配置" :name="name.concat(['metrics'])"> label="指标配置" :name="name.concat(['metrics'])">
<metrics-param v-model:value="_value.metrics" :type="valueType.type" :enum="valueType"></metrics-param> <metrics-param v-model:value="_value.metrics" :type="valueType.type" :enum="valueType" :name="name.concat(['metrics'])"></metrics-param>
</a-form-item> </a-form-item>
</template> </template>
<script setup lang="ts" name="ExpandsForm"> <script setup lang="ts" name="ExpandsForm">
import { useMetadataStore } from '@/store/metadata'; import { useMetadataStore } from '@/store/metadata';
import { PropertySource } from '@/views/device/data'; import { ExpandsTypeList, PropertySource } from '@/views/device/data';
import { PropType } from 'vue'; import { PropType } from 'vue';
import VirtualRuleParam from '@/components/Metadata/VirtualRuleParam/index.vue'; import VirtualRuleParam from '@/components/Metadata/VirtualRuleParam/index.vue';
import ConfigParam from '@/components/Metadata/ConfigParam/index.vue' import ConfigParam from '@/components/Metadata/ConfigParam/index.vue'
@ -78,21 +78,6 @@ watch(_value,
}, },
{ deep: true, immediate: true }) { deep: true, immediate: true })
const options = [
{
label: '读',
value: 'read',
},
{
label: '写',
value: 'write',
},
{
label: '上报',
value: 'report',
},
]
const metadataStore = useMetadataStore() const metadataStore = useMetadataStore()
onMounted(() => { onMounted(() => {

View File

@ -1,6 +1,6 @@
<template> <template>
<a-form-item :label="title" :name="name.concat(['type'])" :rules="[ <a-form-item :label="title" :name="name.concat(['type'])" :rules="[
metadataStore.model.type !== 'functions' ? { required: true, message: '请选择数据类型' } : {}, 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-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>
@ -17,7 +17,7 @@
<a-form-item label="枚举项" :name="name.concat(['elements'])" v-if="['enum'].includes(_value.type)" :rules="[ <a-form-item label="枚举项" :name="name.concat(['elements'])" v-if="['enum'].includes(_value.type)" :rules="[
{ required: true, message: '请配置枚举项' } { required: true, message: '请配置枚举项' }
]"> ]">
<EnumParam v-model:value="_value.elements"></EnumParam> <EnumParam v-model:value="_value.elements" :name="name.concat(['elements'])"></EnumParam>
</a-form-item> </a-form-item>
<a-form-item :name="name.concat(['expands', 'maxLength'])" v-if="['string', 'password'].includes(_value.type)"> <a-form-item :name="name.concat(['expands', 'maxLength'])" v-if="['string', 'password'].includes(_value.type)">
<template #label> <template #label>
@ -34,8 +34,8 @@
<a-form-item label="元素配置" :name="name.concat(['elementType'])" v-if="['array'].includes(_value.type)"> <a-form-item label="元素配置" :name="name.concat(['elementType'])" v-if="['array'].includes(_value.type)">
<ArrayParam v-model:value="_value.elementType" :name="name.concat(['elementType'])"></ArrayParam> <ArrayParam v-model:value="_value.elementType" :name="name.concat(['elementType'])"></ArrayParam>
</a-form-item> </a-form-item>
<a-form-item label="JSON对象" :name="name.concat(['properties'])" v-if="['object'].includes(_value.type)"> <a-form-item label="JSON对象" :name="name.concat(['properties'])" v-if="['object'].includes(_value.type)" :rules="[]">
<JsonParam v-model:value="_value.jsonConfig" :name="name.concat(['properties'])"></JsonParam> <JsonParam v-model:value="_value.properties" :name="name.concat(['properties'])"></JsonParam>
</a-form-item> </a-form-item>
<a-form-item label="文件类型" :name="name.concat(['fileType'])" v-if="['file'].includes(_value.type)" initialValue="url" <a-form-item label="文件类型" :name="name.concat(['fileType'])" v-if="['file'].includes(_value.type)" initialValue="url"
:rules="[ :rules="[
@ -68,7 +68,7 @@ const props = defineProps({
default: false default: false
}, },
name: { name: {
type: Array as PropType<string[]>, type: Array as PropType<(string | number)[]>,
default: () => ([]), default: () => ([]),
required: true required: true
}, },

View File

@ -5,7 +5,7 @@
<a-button :loading="save.loading" type="primary" @click="save.saveMetadata">保存</a-button> <a-button :loading="save.loading" type="primary" @click="save.saveMetadata">保存</a-button>
</template> </template>
<a-form ref="formRef" :model="form.model" layout="vertical"> <a-form ref="formRef" :model="form.model" layout="vertical">
<PropertyForm :model-type="metadataStore.model.type" :type="type" ref="propertyForm" v-model:value="form.model"></PropertyForm> <BaseForm :model-type="metadataStore.model.type" :type="type" v-model:value="form.model"></BaseForm>
</a-form> </a-form>
</a-drawer> </a-drawer>
</template> </template>
@ -20,7 +20,7 @@ import { updateMetadata, asyncUpdateMetadata } from '../../metadata'
import { Store } from 'jetlinks-store'; import { Store } from 'jetlinks-store';
import { detail } from '@/api/device/instance'; import { detail } from '@/api/device/instance';
import { DeviceInstance } from '@/views/device/Instance/typings'; import { DeviceInstance } from '@/views/device/Instance/typings';
import PropertyForm from './PropertyForm.vue'; import BaseForm from './BaseForm.vue';
import { PropType } from 'vue'; import { PropType } from 'vue';
const props = defineProps({ const props = defineProps({
@ -56,8 +56,6 @@ const close = () => {
const title = computed(() => metadataStore.model.action === 'add' ? '新增' : '修改') const title = computed(() => metadataStore.model.action === 'add' ? '新增' : '修改')
const propertyForm = ref()
const form = reactive({ const form = reactive({
model: {} as any, model: {} as any,
}) })
@ -128,6 +126,7 @@ const save = reactive({
} }
save.loading = false save.loading = false
}) })
save.loading = false
}, },
resetMetadata: async () => { resetMetadata: async () => {
const { id } = route.params const { id } = route.params

View File

@ -122,7 +122,7 @@ watch(
) )
watch( watch(
[props.visible, props.type], () => [props.visible, props.type],
() => { () => {
if (props.visible) { if (props.visible) {
loading.value = true loading.value = true
@ -136,7 +136,7 @@ watch(
} else { } else {
productDetail(id as string).then((resp) => { productDetail(id as string).then((resp) => {
loading.value = false loading.value = false
// productStore.setCurrent(resp.result) productStore.setCurrent(resp.result)
value.value = resp.result.metadata value.value = resp.result.metadata
}); });
} }

View File

@ -133,3 +133,18 @@ export const DateTypeList = [
// value: 'yyyy-MM-dd HH:mm:ss zzz', // value: 'yyyy-MM-dd HH:mm:ss zzz',
// }, // },
]; ];
export const ExpandsTypeList = [
{
label: '读',
value: 'read',
},
{
label: '写',
value: 'write',
},
{
label: '上报',
value: 'report',
},
]