Merge branch 'dev' of github.com:jetlinks/jetlinks-ui-vue into dev
This commit is contained in:
commit
0589ea17ed
|
@ -3,7 +3,7 @@
|
|||
<template #title>
|
||||
<div style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="width: 150px;">配置元素</div>
|
||||
<AIcon type="CloseOutlined" @click="visible = false" />
|
||||
<div @click="visible = false"><AIcon type="CloseOutlined" /></div>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
|
@ -55,7 +55,7 @@ const _value = computed({
|
|||
const visible = ref(false)
|
||||
|
||||
onMounted(() => {
|
||||
emit('update:value', { extends: {}, ...props.value })
|
||||
emit('update:value', { expands: {}, ...props.value })
|
||||
})
|
||||
</script>
|
||||
<style lang="less" scoped>
|
||||
|
|
|
@ -9,18 +9,20 @@
|
|||
<template #title>
|
||||
<div class="edit-title" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="width: 150px;">枚举项配置</div>
|
||||
<AIcon type="CloseOutlined" @click="handleClose" />
|
||||
<div @click="handleClose"><AIcon type="CloseOutlined" /></div>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
<div class="ant-form-vertical">
|
||||
<j-form-item label="Value" :name="name.concat([index, 'value'])" :rules="[
|
||||
{ required: true, message: '请输入Value' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]">
|
||||
<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' },
|
||||
{ max: 64, message: '最多可输入64个字符' },
|
||||
]">
|
||||
<j-input v-model:value="_value[index].text" size="small"></j-input>
|
||||
</j-form-item>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<template #title>
|
||||
<div class="edit-title" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="width: 150px;">配置参数</div>
|
||||
<AIcon type="CloseOutlined" @click="handleClose" />
|
||||
<div @click="handleClose"><AIcon type="CloseOutlined" /></div>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
|
@ -40,8 +40,8 @@
|
|||
</div>
|
||||
</j-popover>
|
||||
</div>
|
||||
<div class="item-right">
|
||||
<AIcon type="DeleteOutlined" @click="handleDelete(index)" />
|
||||
<div class="item-right" @click="handleDelete(index)">
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</div>
|
||||
</div>
|
||||
<j-button type="dashed" block @click="handleAdd">
|
||||
|
@ -96,6 +96,7 @@ const handleDelete = (index: number) => {
|
|||
_value.value.splice(index, 1)
|
||||
}
|
||||
const handleClose = () => {
|
||||
console.log(editIndex.value)
|
||||
editIndex.value = -1
|
||||
}
|
||||
const handleAdd = () => {
|
||||
|
|
|
@ -31,11 +31,11 @@
|
|||
</j-radio-group>
|
||||
</j-form-item>
|
||||
<j-form-item label="输入参数" name="inputs" :rules="[
|
||||
{ required: true, message: '请输入输入参数' },
|
||||
{ required: true, validator: (_rule: Rule, val: Record<any, any>[]) => validateJson(_rule, val, '输入参数') },
|
||||
]">
|
||||
<JsonParam v-model:value="value.inputs" :name="['inputs']"></JsonParam>
|
||||
</j-form-item>
|
||||
<value-type-form :name="['output']" v-model:value="value.output" key="function" title="输出参数"></value-type-form>
|
||||
<value-type-form :name="['output']" v-model:value="value.output" key="function" title="输出参数" :required="false"></value-type-form>
|
||||
</template>
|
||||
<template v-if="modelType === 'events'">
|
||||
<j-form-item label="级别" :name="['expands', 'level']" :rules="[
|
||||
|
@ -43,12 +43,12 @@
|
|||
]">
|
||||
<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>
|
||||
<value-type-form :name="['valueType']" v-model:value="value.valueType" key="function" title="输出参数" only-object></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>
|
||||
<j-form-item label="读写类型" :name="['expands', 'type']" :rules="[
|
||||
{ required: true, message: '请选择读写类型' },
|
||||
<j-form-item label="标签类型" :name="['expands', 'type']" :rules="[
|
||||
{ required: true, message: '请选择标签类型' },
|
||||
]">
|
||||
<j-select v-model:value="value.expands.type" :options="ExpandsTypeList" mode="multiple" size="small"></j-select>
|
||||
</j-form-item>
|
||||
|
@ -68,6 +68,8 @@ import { getMetadataConfig } from '@/api/device/product'
|
|||
import JsonParam from '@/components/Metadata/JsonParam/index.vue'
|
||||
import { EventLevel, ExpandsTypeList } from '@/views/device/data';
|
||||
import { useMetadataStore } from '@/store/metadata';
|
||||
import { validateJson } from './validator';
|
||||
import { Rule } from 'ant-design-vue/es/form';
|
||||
|
||||
const props = defineProps({
|
||||
type: {
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
{ required: true, message: '请选择来源' },
|
||||
]">
|
||||
<j-select v-model:value="_value.source" :options="PropertySource" size="small"
|
||||
:disabled="metadataStore.model.action === 'edit'"></j-select>
|
||||
:disabled="metadataStore.model.action === 'edit'" @change="changeSource"></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>
|
||||
<j-form-item label="读写类型" :name="name.concat(['type'])" :rules="[
|
||||
{ required: true, message: '请选择读写类型' },
|
||||
]">
|
||||
<j-select v-model:value="_value.type" :options="ExpandsTypeList" mode="multiple" size="small"></j-select>
|
||||
<j-select v-model:value="_value.type" :options="ExpandsTypeList" mode="multiple" size="small" :disabled="['manual', 'rule'].includes(_value.source)"></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">
|
||||
|
@ -100,5 +100,15 @@ const validateMetrics = (value: Record<any, any>[]) => {
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const changeSource = (val: string) => {
|
||||
if (val === 'manual') {
|
||||
_value.value.type = ['write']
|
||||
} else if (val === 'rule') {
|
||||
_value.value.type = ['report']
|
||||
} else {
|
||||
_value.value.type = []
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style lang="less" scoped></style>
|
|
@ -1,23 +1,23 @@
|
|||
<template>
|
||||
<j-form-item :label="title" :name="name.concat(['type'])" :rules="[
|
||||
metadataStore.model.type !== 'functions' ? { required: true, message: `请选择${title}` } : {},
|
||||
required ? { required: true, message: `请选择${title}` } : {},
|
||||
]">
|
||||
<j-select v-model:value="_value.type"
|
||||
:options="metadataStore.model.type === 'events' ? eventDataTypeList : _dataTypeList" size="small"
|
||||
:options="onlyObject ? 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>
|
||||
</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"
|
||||
<j-input-number v-model:value="_value.scale" size="small" :min="0" :max="2147483647" :precision="0"
|
||||
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>
|
||||
</j-form-item>
|
||||
<j-form-item label="枚举项" :name="name.concat(['elements'])" v-if="['enum'].includes(_value.type)" :rules="[
|
||||
{ required: true, validator: validateEnum, message: '请配置枚举项' }
|
||||
{ required: true, validator: validateEnum }
|
||||
]">
|
||||
<EnumParam v-model:value="_value.elements" :name="name.concat(['elements'])"></EnumParam>
|
||||
</j-form-item>
|
||||
|
@ -39,7 +39,7 @@
|
|||
<ArrayParam v-model:value="_value.elementType" :name="name.concat(['elementType'])"></ArrayParam>
|
||||
</j-form-item>
|
||||
<j-form-item label="JSON对象" :name="name.concat(['properties'])" v-if="['object'].includes(_value.type)" :rules="[
|
||||
{ validator: validateJson }
|
||||
{ validator: (_rule: Rule, val: Record<any, any>[]) => validateJson(_rule, val, 'JSON对象') }
|
||||
]">
|
||||
<JsonParam v-model:value="_value.properties" :name="name.concat(['properties'])"></JsonParam>
|
||||
</j-form-item>
|
||||
|
@ -62,8 +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 { validateEnum, validateArray, validateJson } from './validator'
|
||||
import { Rule } from 'ant-design-vue/es/form';
|
||||
import { Form } from 'ant-design-vue/es';
|
||||
|
||||
type ValueType = Record<any, any>;
|
||||
const props = defineProps({
|
||||
|
@ -81,8 +81,16 @@ const props = defineProps({
|
|||
required: true
|
||||
},
|
||||
title: {
|
||||
String,
|
||||
type: String,
|
||||
default: '数据类型'
|
||||
},
|
||||
required: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
onlyObject: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -108,7 +116,7 @@ watch(_value,
|
|||
{ deep: true, immediate: true })
|
||||
|
||||
onMounted(() => {
|
||||
if (metadataStore.model.type === 'events') {
|
||||
if (props.onlyObject) {
|
||||
_value.value = {
|
||||
type: 'object',
|
||||
expands: {}
|
||||
|
@ -141,63 +149,12 @@ const eventDataTypeList = [
|
|||
]
|
||||
|
||||
const changeType = (val: SelectValue) => {
|
||||
if (['float', 'double'].includes(_value.value.type) && _value.value.scale === undefined) {
|
||||
_value.value.scale = 2
|
||||
}
|
||||
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}` } : {},
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import { Rule } from "ant-design-vue/es/form";
|
||||
|
||||
export 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();
|
||||
}
|
||||
|
||||
export const validateArray = async (_rule: Rule, val: Record<any, any>) => {
|
||||
if (!val) return Promise.reject(new Error(`请输入元素配置`));
|
||||
await validateValueType(_rule, val)
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export const validateJson = async (_rule: Rule, val: Record<any, any>[], title = '配置参数') => {
|
||||
if (!val || val.length === 0) {
|
||||
return Promise.reject(new Error(`请输入${title}`));
|
||||
}
|
||||
for (let item of val) {
|
||||
if (!item) return Promise.reject(new Error(`请输入${title}`));
|
||||
await validateIdName(_rule, item)
|
||||
await validateValueType(_rule, item.valueType)
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
export const validateIdName = async (_rule: Rule, val: Record<any, any>) => {
|
||||
if (!val.id) {
|
||||
return Promise.reject(new Error('请输入标识'))
|
||||
}
|
||||
if (!val.name) {
|
||||
return Promise.reject(new Error('请输入名称'))
|
||||
}
|
||||
}
|
||||
|
||||
export const validateValueType = async (_rule: Rule, val: Record<any, any>, title = '数据类型') => {
|
||||
console.log(val)
|
||||
if (!val) return Promise.reject(new Error('请输入元素配置'));
|
||||
if (!val?.type) {
|
||||
return Promise.reject(new Error(`请选择${title}`))
|
||||
}
|
||||
if (['enum'].includes(val.type)) {
|
||||
await validateEnum(_rule, val.elements)
|
||||
}
|
||||
if (['array'].includes(val.type)) {
|
||||
await validateArray(_rule, val.elementType)
|
||||
}
|
||||
if (['object'].includes(val.type)) {
|
||||
await validateJson(_rule, val.properties)
|
||||
}
|
||||
if (['file'].includes(val.type) && !val.fileType) {
|
||||
return Promise.reject(new Error('请选择文件类型'))
|
||||
}
|
||||
return Promise.resolve();
|
||||
}
|
|
@ -38,22 +38,20 @@
|
|||
</template>
|
||||
<template v-if="column.dataIndex === 'action'">
|
||||
<j-space>
|
||||
<PermissionButton :uhas-permission="`${permission}:update`" type="link" key="edit" style="padding: 0"
|
||||
<PermissionButton :has-permission="`${permission}:update`" type="link" key="edit" style="padding: 0"
|
||||
:udisabled="operateLimits('updata', type)" @click="handleEditClick(record)" :tooltip="{
|
||||
title: operateLimits('updata', type) ? '当前的存储方式不支持编辑' : '编辑',
|
||||
}">
|
||||
<AIcon type="EditOutlined" />
|
||||
</PermissionButton>
|
||||
<PermissionButton :uhas-permission="`${permission}:delete`" type="link" key="delete" style="padding: 0"
|
||||
<PermissionButton :has-permission="`${permission}:delete`" type="link" key="delete" style="padding: 0"
|
||||
:pop-confirm="{
|
||||
title: '确认删除?', onConfirm: async () => {
|
||||
await removeItem(record);
|
||||
},
|
||||
}"
|
||||
:tooltip="{
|
||||
}" :tooltip="{
|
||||
title: '删除',
|
||||
}"
|
||||
>
|
||||
}">
|
||||
<AIcon type="DeleteOutlined" />
|
||||
</PermissionButton>
|
||||
</j-space>
|
||||
|
@ -69,13 +67,9 @@ import { useProductStore } from '@/store/product'
|
|||
import { useMetadataStore } from '@/store/metadata'
|
||||
import PermissionButton from '@/components/PermissionButton/index.vue'
|
||||
import { TablePaginationConfig, message } from 'ant-design-vue/es'
|
||||
import { SystemConst } from '@/utils/consts'
|
||||
import { Store } from 'jetlinks-store'
|
||||
import { asyncUpdateMetadata, removeMetadata } from '../metadata'
|
||||
import { detail } from '@/api/device/instance'
|
||||
import Edit from './Edit/index.vue'
|
||||
// import { detail } from '@/api/device/instance'
|
||||
// import { detail as productDetail } from '@/api/device/product'
|
||||
interface Props {
|
||||
type: MetadataType;
|
||||
target: 'product' | 'device';
|
||||
|
@ -134,10 +128,6 @@ const handleSearch = (searchValue: string) => {
|
|||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
})
|
||||
|
||||
const refreshMetadata = () => {
|
||||
loading.value = true
|
||||
// const res = target === 'product'
|
||||
|
@ -188,11 +178,18 @@ const handleEditClick = (record: MetadataItem) => {
|
|||
}
|
||||
|
||||
const resetMetadata = async () => {
|
||||
// const { id } = route.params
|
||||
// const resp = await detail(id as string);
|
||||
// if (resp.status === 200) {
|
||||
// instanceStore.setCurrent(resp?.result || []);
|
||||
// }
|
||||
const { id } = route.params
|
||||
const resp = await detail(id as string);
|
||||
if (resp.status === 200) {
|
||||
instanceStore.setCurrent(resp?.result || []);
|
||||
if (target === 'device') {
|
||||
instanceStore.refresh(id as string)
|
||||
} else {
|
||||
productStore.refresh(id as string)
|
||||
}
|
||||
metadataStore.set('importMetadata', true)
|
||||
};
|
||||
|
||||
const removeItem = async (record: MetadataItem) => {
|
||||
|
@ -203,7 +200,7 @@ const removeItem = async (record: MetadataItem) => {
|
|||
const result = await asyncUpdateMetadata(target, _currentData);
|
||||
if (result.status === 200) {
|
||||
message.success('操作成功!');
|
||||
Store.set(SystemConst.REFRESH_METADATA_TABLE, true);
|
||||
// Store.set(SystemConst.REFRESH_METADATA_TABLE, true);
|
||||
metadataStore.model.edit = false;
|
||||
metadataStore.model.item = {};
|
||||
resetMetadata();
|
||||
|
|
Loading…
Reference in New Issue