feat: 新增IEC104协议;修复自定义采集频率不生效;修复MODBUS_TCP新建通道主机IP和端口未保存到后端的bug等

* feat: 新增IEC104协议

* fix: 修复自定义采集频率不生效

* fix: bug#21712、21711

* fix: 修复MODBUS_TCP新建通道主机IP和端口未保存到后端的bug

* fix: 修复产品“物模型映射”目标属性下拉框无选项的bug

* fix: bug#21958

* fix: bug#21338

* fix: bug#21262

* fix: bug#22074

* fix: 场景联动条件修改
This commit is contained in:
XieYongHong 2024-02-02 09:56:28 +08:00 committed by GitHub
parent aaa0e78343
commit fd37264925
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 144 additions and 105 deletions

View File

@ -32,7 +32,7 @@ const handleTermsArr = (queryTerms: any, data: any[], parentKey?: string) => {
handleTermsArr(queryTerms, item, `${key}`) handleTermsArr(queryTerms, item, `${key}`)
} else if (isObject(item)) { } else if (isObject(item)) {
handleTermsObject(queryTerms, item, `${key}`) handleTermsObject(queryTerms, item, `${key}`)
} else { } else{
queryTerms[key] = item queryTerms[key] = item
} }
}) })
@ -40,8 +40,10 @@ const handleTermsArr = (queryTerms: any, data: any[], parentKey?: string) => {
const handleTermsObject = (queryTerms: any, data: any, parentKey?: string) => { const handleTermsObject = (queryTerms: any, data: any, parentKey?: string) => {
Object.keys(data).forEach(k => { Object.keys(data).forEach(k => {
const key = `${parentKey}.${k}` const key = `${parentKey}.${k}`
console.log(key, data[k], isObject(data[k]), isArray(data[k])) console.log(key, data[k], isObject(data[k]), isArray(data[k]),k)
if (isArray(data[k])) { if( k === 'value' && isArray(data[k])){
queryTerms[key] = data[k].join(',')
}else if (isArray(data[k])) {
handleTermsArr(queryTerms, data[k], `${key}`) handleTermsArr(queryTerms, data[k], `${key}`)
} else if (isObject(data[k])) { } else if (isObject(data[k])) {
handleTermsObject(queryTerms, data[k], `${key}`) handleTermsObject(queryTerms, data[k], `${key}`)

View File

@ -249,7 +249,7 @@ const handleOk = async () => {
params.configuration={ params.configuration={
connect : false connect : false
} }
} else { } else if (params?.provider === 'iec104') {
params.configuration = {} params.configuration = {}
} }

View File

@ -50,7 +50,7 @@
:key="item.property" :key="item.property"
> >
<template #label> <template #label>
<Ellipsis style="margin-right: 5px;"> <Ellipsis style="margin-right: 5px">
{{ item.name }} {{ item.name }}
<j-tooltip <j-tooltip
v-if="item.description" v-if="item.description"
@ -69,11 +69,13 @@
> >
<span v-else-if="item.type.type === 'enum'"> <span v-else-if="item.type.type === 'enum'">
<Ellipsis>{{ <Ellipsis>{{
item.type.elements?.find((i)=> item.type.elements?.find(
i.value === instanceStore.current?.configuration?.[ (i) =>
item.property i.value ===
] instanceStore.current?.configuration?.[
)?.text || '' item.property
],
)?.text || ''
}}</Ellipsis> }}</Ellipsis>
<j-tooltip <j-tooltip
v-if="isExit(item.property)" v-if="isExit(item.property)"
@ -85,9 +87,24 @@
><AIcon type="QuestionCircleOutlined" ><AIcon type="QuestionCircleOutlined"
/></j-tooltip> /></j-tooltip>
</span> </span>
<span v-else-if="item.type.type === 'boolean'">
<Ellipsis>{{
[
{
label: item?.type?.falseText,
value: item?.type?.falseValue,
},
{
label: item?.type?.trueText,
value: item?.type?.trueValue,
}
].find((i) => i.value ===
instanceStore.current?.configuration?.[item.property] )?.label || ''
}}</Ellipsis>
</span>
<span v-else> <span v-else>
<Ellipsis>{{ <Ellipsis>{{
instanceStore.current?.configuration?.[item.property] || instanceStore.current?.configuration?.[item.property] ||
'' ''
}}</Ellipsis> }}</Ellipsis>
<j-tooltip <j-tooltip
@ -172,4 +189,4 @@ const saveBtn = () => {
instanceStore.refresh(instanceStore.current.id); instanceStore.refresh(instanceStore.current.id);
} }
}; };
</script> </script>

View File

@ -140,7 +140,7 @@ import { useProductStore } from '@/store/product';
import { detail as queryPluginAccessDetail } from '@/api/link/accessConfig'; import { detail as queryPluginAccessDetail } from '@/api/link/accessConfig';
import { getPluginData, getProductByPluginId } from '@/api/link/plugin'; import { getPluginData, getProductByPluginId } from '@/api/link/plugin';
import { getImage, onlyMessage } from '@/utils/comm'; import { getImage, onlyMessage } from '@/utils/comm';
import { getMetadataMapById, metadataMapById } from '@/api/device/instance'; import { getMetadataMapById, metadataMapById, getProtocolMetadata } from '@/api/device/instance';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
const productStore = useProductStore(); const productStore = useProductStore();
@ -242,7 +242,7 @@ const onSearch = () => {
const getDefaultMetadata = async () => { const getDefaultMetadata = async () => {
const metadata = JSON.parse(productDetail.value?.metadata || '{}'); const metadata = JSON.parse(productDetail.value?.metadata || '{}');
const properties = metadata.properties; const properties = metadata.properties;
const pluginMetadata = await getPluginMetadata(); const pluginMetadata = await getMetadata();
const pluginProperties = pluginMetadata?.properties || []; const pluginProperties = pluginMetadata?.properties || [];
const metadataMap: any = await getMetadataMapData(); const metadataMap: any = await getMetadataMapData();
pluginOptions.value = pluginProperties.map((item) => ({ pluginOptions.value = pluginProperties.map((item) => ({
@ -309,6 +309,19 @@ const getPluginMetadata = (): Promise<{ properties: any[] }> => {
); );
}); });
}; };
const getMetadata = (): Promise<{ properties: any[] }> => {
return new Promise((resolve) => {
const transport = productDetail.value?.transportProtocol;
getProtocolMetadata(productDetail.value?.messageProtocol || '', transport).then(
(res: any) => {
if (res.success) {
resolve(JSON.parse(res?.result || '{}'));
}
resolve({ properties: [] });
},
);
});
};
const onMapData = async (arr: any[], flag?: boolean) => { const onMapData = async (arr: any[], flag?: boolean) => {
const res = await metadataMapById('product', productDetail.value?.id, arr); const res = await metadataMapById('product', productDetail.value?.id, arr);

View File

@ -39,7 +39,8 @@ export const testType = (data:any,index:number,isArray?:boolean,isObject?:boolea
} }
} }
if(data.type === 'object' && !isArray && !isObject){ if(data.type === 'object' && !isArray && !isObject){
if(data?.valueType?.properties?.length > 0){ console.log(data,'data123')
if(data?.properties?.length > 0){
return testObject(data.properties,index) return testObject(data.properties,index)
}else{ }else{
onlyMessage(`方法定义inputs第${index+1}个数组ValueType中缺失properties属性`,'error') onlyMessage(`方法定义inputs第${index+1}个数组ValueType中缺失properties属性`,'error')

View File

@ -27,7 +27,9 @@
<j-radio-button value="hour"> <j-radio-button value="hour">
最近1小时 最近1小时
</j-radio-button> </j-radio-button>
<j-radio-button value="day"> 最近24小时 </j-radio-button> <j-radio-button value="day">
最近24小时
</j-radio-button>
<j-radio-button value="week"> 近一周 </j-radio-button> <j-radio-button value="week"> 近一周 </j-radio-button>
</j-radio-group> </j-radio-group>
<j-range-picker <j-range-picker
@ -48,20 +50,18 @@
v-if="isEmpty" v-if="isEmpty"
style="height: 250px; margin-top: 100px" style="height: 250px; margin-top: 100px"
/> />
<template v-else> <template v-else>
<div style="height: 300px"> <div style="height: 300px">
<Echarts <Echarts :options="echartsOptions" />
:options="echartsOptions" </div>
/>
</div>
<ServerList <ServerList
v-if="serverOptions.length > 1" v-if="serverOptions.length > 1"
v-model:value="serverActive" v-model:value="serverActive"
:options="serverOptions" :options="serverOptions"
color="#979AFF" color="#979AFF"
/> />
</template> </template>
</div> </div>
</div> </div>
</j-spin> </j-spin>
@ -70,23 +70,24 @@
<script lang="ts" setup name="Network"> <script lang="ts" setup name="Network">
import { dashboard } from '@/api/link/dashboard'; import { dashboard } from '@/api/link/dashboard';
import { import {
getTimeByType, getTimeByType,
typeDataLine, typeDataLine,
areaStyle, areaStyle,
colorNetwork, colorNetwork,
networkParams, arrayReverse, networkParams,
arrayReverse,
} from './tool.ts'; } from './tool.ts';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { DataType } from '../typings.d'; import { DataType } from '../typings.d';
import ServerList from './ServerList.vue' import ServerList from './ServerList.vue';
import Echarts from './echarts.vue' import Echarts from './echarts.vue';
const props = defineProps({ const props = defineProps({
serviceId: { serviceId: {
type: String, type: String,
default: undefined default: undefined,
} },
}) });
const chartRef = ref<Record<string, any>>({}); const chartRef = ref<Record<string, any>>({});
const loading = ref(false); const loading = ref(false);
@ -98,20 +99,20 @@ const data = ref<DataType>({
}, },
}); });
const isEmpty = ref(false); const isEmpty = ref(false);
const serverActive = ref<string[]>([]) const serverActive = ref<string[]>([]);
const serverOptions = ref<string[]>([]) const serverOptions = ref<string[]>([]);
const serverData = reactive({ const serverData = reactive({
xAxis: [], xAxis: [],
data: [] data: [],
}) });
const pickerTimeChange = (value: any) => { const pickerTimeChange = (value: any) => {
data.value.time.type = undefined; data.value.time.type = undefined;
getNetworkEcharts(data.value); getNetworkEcharts(data.value);
}; };
const changeType = (value:any) =>{ const changeType = (value: any) => {
getNetworkEcharts(data.value); getNetworkEcharts(data.value);
} };
const getNetworkEcharts = async (val: any) => { const getNetworkEcharts = async (val: any) => {
loading.value = true; loading.value = true;
const resp: any = await dashboard(networkParams(val)); const resp: any = await dashboard(networkParams(val));
@ -119,10 +120,10 @@ const getNetworkEcharts = async (val: any) => {
const _networkOptions = {}; const _networkOptions = {};
const _networkXAxis = new Set(); const _networkXAxis = new Set();
if (resp.result.length) { if (resp.result.length) {
isEmpty.value = false; isEmpty.value = false;
const filterArray = resp.result const filterArray = resp.result;
// const filterArray = resp.result.filter((item : any) => item.data?.clusterNodeId === props.serviceId) // const filterArray = resp.result.filter((item : any) => item.data?.clusterNodeId === props.serviceId)
filterArray.forEach((item: any) => { filterArray.forEach((item: any) => {
const value = item.data.value; const value = item.data.value;
const _data: Array<any> = []; const _data: Array<any> = [];
const nodeID = item.data.clusterNodeId; const nodeID = item.data.clusterNodeId;
@ -149,9 +150,9 @@ const getNetworkEcharts = async (val: any) => {
const formatterData = (value: any) => { const formatterData = (value: any) => {
let _data = ''; let _data = '';
const kb = 1024 const kb = 1024;
const mb = kb**2 const mb = kb ** 2;
const gb = kb**3 const gb = kb ** 3;
if (value >= kb && value < mb) { if (value >= kb && value < mb) {
_data = `${Number((value / kb).toFixed(2))}KB`; _data = `${Number((value / kb).toFixed(2))}KB`;
@ -166,10 +167,24 @@ const formatterData = (value: any) => {
}; };
const networkValueRender = (obj: any) => { const networkValueRender = (obj: any) => {
const { value } = obj; // const { value } = obj;
return `${obj?.axisValueLabel}<br />${obj?.marker}${ let data: any = '';
obj?.seriesName obj.forEach((item: any, index: number) => {
} &nbsp; ${formatterData(value)}`; const { value } = item;
if (index === 0) {
data += `${item?.axisValueLabel}<br />${item?.marker}${
item?.seriesName
} &nbsp; ${formatterData(value)}<br />`;
}else{
data += `${item?.marker}${
item?.seriesName
} &nbsp; ${formatterData(value)}<br />`;
}
});
return data;
// return `${obj?.axisValueLabel}<br />${obj?.marker}${
// obj?.seriesName
// } &nbsp; ${formatterData(value)}`;
}; };
const setOptions = (data: any, key: string) => ({ const setOptions = (data: any, key: string) => ({
@ -181,43 +196,43 @@ const setOptions = (data: any, key: string) => ({
}); });
const handleNetworkOptions = (optionsData: any, xAxis: any) => { const handleNetworkOptions = (optionsData: any, xAxis: any) => {
const dataKeys = Object.keys(optionsData); const dataKeys = Object.keys(optionsData);
serverActive.value = dataKeys serverActive.value = dataKeys;
serverOptions.value = dataKeys serverOptions.value = dataKeys;
serverData.xAxis = xAxis serverData.xAxis = xAxis;
serverData.data = optionsData serverData.data = optionsData;
}; };
const echartsOptions = computed(() => { const echartsOptions = computed(() => {
const series = serverActive.value.length const series = serverActive.value.length
? serverActive.value.map((key) => setOptions(serverData.data, key)) ? serverActive.value.map((key) => setOptions(serverData.data, key))
: typeDataLine : typeDataLine;
return { return {
xAxis: { xAxis: {
type: 'category', type: 'category',
boundaryGap: false, boundaryGap: false,
data: serverData.xAxis, data: serverData.xAxis,
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
axisLabel: { axisLabel: {
formatter: (_value: any) => formatterData(_value), formatter: (_value: any) => formatterData(_value),
}, },
}, },
grid: { grid: {
left: '70px', left: '70px',
right: data.value.time.type === 'week' ? 50 :10, right: data.value.time.type === 'week' ? 50 : 10,
bottom: '24px', bottom: '24px',
top: 24 top: 24,
}, },
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
formatter: (_value: any) => networkValueRender(_value[0]), formatter: (_value: any) => networkValueRender(_value),
}, },
color: colorNetwork, color: colorNetwork,
series: series series: series,
}; };
}) });
watch( watch(
() => data.value.time.type, () => data.value.time.type,
@ -231,7 +246,6 @@ watch(
}, },
{ immediate: true, deep: true }, { immediate: true, deep: true },
); );
</script> </script>
<style lang="less" scoped> <style lang="less" scoped>

View File

@ -36,7 +36,6 @@
v-model:value='paramsValue.termType' v-model:value='paramsValue.termType'
@select='termsTypeSelect' @select='termsTypeSelect'
/> />
<div v-if="!['notnull','isnull'].includes(paramsValue.termType)">
<DoubleParamsDropdown <DoubleParamsDropdown
v-if='showDouble' v-if='showDouble'
icon='icon-canshu' icon='icon-canshu'
@ -60,7 +59,6 @@
v-model:source='paramsValue.value.source' v-model:source='paramsValue.value.source'
@select='valueSelect' @select='valueSelect'
/> />
</div>
<j-popconfirm title='确认删除?' @confirm='onDelete' :overlayStyle='{minWidth: "180px"}'> <j-popconfirm title='确认删除?' @confirm='onDelete' :overlayStyle='{minWidth: "180px"}'>
<div v-show='showDelete' class='button-delete'> <AIcon type='CloseOutlined' /></div> <div v-show='showDelete' class='button-delete'> <AIcon type='CloseOutlined' /></div>
</j-popconfirm> </j-popconfirm>
@ -84,12 +82,12 @@ import { ContextKey, arrayParamsKey, timeTypeKeys } from './util'
import { useSceneStore } from 'store/scene' import { useSceneStore } from 'store/scene'
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import { Form } from 'jetlinks-ui-components' import { Form } from 'jetlinks-ui-components'
import {indexOf, isArray, isObject, isString, pick} from 'lodash-es' import {indexOf, isArray, isObject, isString, pick , cloneDeep } from 'lodash-es'
import {cloneDeep} from "lodash";
const sceneStore = useSceneStore() const sceneStore = useSceneStore()
const { data: formModel } = storeToRefs(sceneStore) const { data: formModel } = storeToRefs(sceneStore)
const formItemContext = Form.useInjectFormItemContext(); const formItemContext = Form.useInjectFormItemContext();
type Emit = { type Emit = {
(e: 'update:value', data: TermsType): void (e: 'update:value', data: TermsType): void
} }
@ -330,21 +328,15 @@ const termsTypeSelect = (e: { key: string, name: string }) => {
newValue.value = undefined newValue.value = undefined
} }
} }
if(
['isnull','notull'].includes(e.key)
){
newValue.value.value = 1
}
paramsValue.value = newValue paramsValue.value = newValue
emit('update:value', { ...paramsValue }) emit('update:value', { ...paramsValue })
formItemContext.onFieldChange() formItemContext.onFieldChange()
formModel.value.options!.when[props.branchName].terms[props.whenName].terms[props.termsName][1] = e.name formModel.value.options!.when[props.branchName].terms[props.whenName].terms[props.termsName][1] = e.name
} }
const valueSelect = (v: any, label: string, labelObj: Record<number, any>, option: any) => { const valueSelect = (v: any, label: string, labelObj: Record<number, any>, option: any) => {
console.log(labelObj,option,paramsValue.value,'____123')
if (paramsValue.value?.source === 'metric') { if (paramsValue.value?.source === 'metric') {
paramsValue.value.metric = option?.id paramsValue.value.metric = option?.id
} }